JIRA ID = ODUHIGH-334 Implementation of DLRRC message for RRC RELEASE
[o-du/l2.git] / src / 5gnrrlc / rlc_tmr.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**
20   
21         Name:    RLC - TMR module file
22     
23         Type:    C source file
24   
25         Desc:    Source code for timer functions such as, 
26
27                  - rlcStartTmr
28                  - rlcStopTmr
29                  - rlcTmrExpiry
30                  - rlcBndTmrExpiry  
31                   
32         File:    rlc_tmr.c
33   
34 *********************************************************************21*/
35
36 /* header (.h) include files */
37 #include "common_def.h"
38 #include "lkw.h"           /* LKW defines */
39 #include "ckw.h"           /* CKW defines */
40 #include "kwu.h"           /* KWU defines */
41 #include "rgu.h"           /* RGU defines */
42 #include "rlc_env.h"        /* RLC environment options */
43 #include "rlc_err.h"        /* Error defines */
44
45 /* extern (.x) include files */
46 #include "lkw.x"           /* LKW */
47 #include "ckw.x"           /* CKW */
48 #include "kwu.x"           /* KWU */
49 #include "rgu.x"           /* RGU */
50
51 #include "du_app_rlc_inf.h"
52 #include "rlc_utils.h"            /* RLC defines */
53 #include "rlc_dl_ul_inf.h"
54 #include "rlc_dl.h"
55 #include "rlc_ul.h"
56 #include "rlc_mgr.h"
57
58 /** 
59  * @file gp_tmr.c
60  * @brief RLC Timer Module
61 */
62
63 /**
64  * @def RLC_TMR_CALCUATE_WAIT
65  *
66  *    This macro calculates and assigns wait time based on the value of the 
67  *    timer and the timer resolution. Timer value of 0 signifies that the
68  *    timer is not configured
69  *
70  * @param[out] _wait   Time for which to arm the timer changed to proper 
71  *                     value according to the resolution
72  * @param[in] _tmrVal   Value of the timer
73  * @param[in] _timerRes   Resolution of the timer
74  *
75 */
76 #define RLC_TMR_CALCUATE_WAIT(_wait, _tmrVal, _timerRes)       \
77 {                                                             \
78    (_wait) = ((_tmrVal) * SS_TICKS_SEC)/((_timerRes) * 1000); \
79    if((0 != (_tmrVal)) && (0 == (_wait)))                     \
80    {                                                          \
81       (_wait) = 1;                                            \
82    }                                                          \
83 }
84
85 /* private function declarations */
86 static Void rlcBndTmrExpiry(PTR cb);
87
88 /**
89  * @brief Handler to start timer
90  *       
91  * @param[in] gCb       Pointer to the RLC instance control block
92  * @param[in] cb        Control block depending on the type of the timer event. 
93  *                      It can be uplink/downlink rbCb or rgu sap control block
94  * @param[in] tmrEvnt   Timer event to be started
95  *
96  * @return  Void
97 */
98 void rlcStartTmr(RlcCb *gCb, PTR cb, int16_t tmrEvnt)
99 {
100 /* kw005.201 added support for L2 Measurement */
101 #ifdef LTE_L2_MEAS
102    RlcL2MeasEvtCb *measEvtCb = NULLP;
103 #endif
104
105    CmTmrArg arg;
106    arg.wait = 0;
107
108    /* kw002.201 Adjusting the wait time as per timeRes configured by layer manager */
109    switch (tmrEvnt)
110    {
111       case EVENT_RLC_UMUL_REASSEMBLE_TMR:
112       {
113          RlcUmUl* umUl = &(((RlcUlRbCb *)cb)->m.umUl);
114          /* kw005.201 Changed wait calculation ccpu00117634*/ 
115          RLC_TMR_CALCUATE_WAIT(arg.wait, umUl->reAsmblTmrInt, gCb->genCfg.timeRes);
116
117          arg.timers = &umUl->reAsmblTmr;
118          arg.max = RLC_MAX_UM_TMR;
119          break;
120       }
121       case EVENT_RLC_AMUL_REASSEMBLE_TMR:
122       {
123          RlcAmUl* amUl = &(((RlcUlRbCb *)cb)->m.amUl);
124          /* kw005.201 Changed wait calculation ccpu00117634*/ 
125          RLC_TMR_CALCUATE_WAIT(arg.wait, amUl->reAsmblTmrInt, gCb->genCfg.timeRes);         
126
127          arg.timers = &amUl->reAsmblTmr;
128          arg.max = RLC_MAX_AM_TMR;
129          break;
130       }
131       case EVENT_RLC_AMUL_STA_PROH_TMR:
132       {
133          RlcAmUl* amUl = &(((RlcUlRbCb *)cb)->m.amUl);
134          /* kw005.201 Changed wait calculation ccpu00117634*/ 
135          RLC_TMR_CALCUATE_WAIT(arg.wait,
136                               amUl->staProhTmrInt,
137                               gCb->genCfg.timeRes);                  
138
139          arg.timers = &amUl->staProhTmr;
140          arg.max = RLC_MAX_AM_TMR;
141          break;
142       } 
143       case EVENT_RLC_AMDL_POLL_RETX_TMR:
144       {
145          RlcAmDl* amDl = &(((RlcDlRbCb *)cb)->m.amDl);
146          /* kw005.201 Changed wait calculation ccpu00117634*/ 
147          RLC_TMR_CALCUATE_WAIT(arg.wait, 
148                               amDl->pollRetxTmrInt, 
149                               gCb->genCfg.timeRes);                  
150
151          arg.timers = &amDl->pollRetxTmr;
152          arg.max = RLC_MAX_AM_TMR;
153          break;
154       } 
155       case EVENT_RLC_WAIT_BNDCFM:
156       {
157          RlcRguSapCb* rguSap = (RlcRguSapCb *)cb;
158          /* kw005.201 Changed wait calculation ccpu00117634*/ 
159          RLC_TMR_CALCUATE_WAIT(arg.wait, rguSap->bndTmrInt, gCb->genCfg.timeRes);                  
160
161          arg.timers = &rguSap->bndTmr;
162          arg.max = RLC_MAX_RGUSAP_TMR;
163          break;
164       }
165 /* kw005.201 added support for L2 Measurement */
166 #ifdef LTE_L2_MEAS
167       case EVENT_RLC_L2_TMR:
168       {
169          measEvtCb = (RlcL2MeasEvtCb *)cb;
170          /* kw005.201 Changed wait calculation ccpu00117634*/ 
171          RLC_TMR_CALCUATE_WAIT(arg.wait, 
172                               measEvtCb->l2TmrCfg.val, 
173                               gCb->genCfg.timeRes);                  
174
175          arg.timers = &measEvtCb->l2Tmr;
176          arg.max = RLC_L2_MAX_TIMERS;
177          break;
178       }
179 #endif
180       case EVENT_RLC_THROUGHPUT_TMR:
181       {
182          RlcThpt *thptCb = (RlcThpt *)cb;
183          RLC_TMR_CALCUATE_WAIT(arg.wait, ODU_THROUGHPUT_PRINT_TIME_INTERVAL, gCb->genCfg.timeRes);
184          arg.timers = &thptCb->thptTmr;
185          arg.max = RLC_MAX_THPT_TMR; 
186          break;
187       }
188       case EVENT_RLC_UE_DELETE_TMR:
189       {
190          RlcUlUeCb *ulUeCb = (RlcUlUeCb*)cb;
191          RLC_TMR_CALCUATE_WAIT(arg.wait, RLC_UE_DELETE_WAIT_TIME, gCb->genCfg.timeRes);
192          arg.timers = &ulUeCb->ueDeleteInfo.ueDelTmr;
193          arg.max = RLC_MAX_UE_TMR;
194          break;
195       }
196       default:
197       {
198          DU_LOG("\nERROR  -->  RLC : rlcStartTmr: Invalid tmr Evnt [%d]", tmrEvnt);
199       }
200    } 
201
202    if(arg.wait != 0)
203    {
204       arg.tqCp   = &gCb->rlcTqCp;
205       arg.tq     = gCb->rlcTq;
206       arg.cb     = cb;
207       arg.evnt   = tmrEvnt;
208       arg.tNum   = 0;
209
210       cmPlcCbTq(&arg);
211    }
212
213    return;
214 }
215
216 /**
217  * @brief Handler to stop a timer
218  *       
219  * @param[in] gCb       Pointer to the RLC instance control block
220  * @param[in] cb        Control block depending on the type of the timer event. 
221  *                      It can be uplink/downlink rbCb or rgu sap control block
222  * @param[in] tmrType   Timer event to be started
223  *
224  * @return  Void
225 */
226 void rlcStopTmr(RlcCb *gCb, PTR cb, uint8_t tmrType)
227 {
228    CmTmrArg   arg;
229 /* kw005.201 added support for L2 Measurement */
230 #ifdef LTE_L2_MEAS
231    RlcL2MeasEvtCb *measEvtCb = NULLP;
232 #endif
233
234    arg.timers = NULLP;
235
236    switch (tmrType)
237    {
238       case EVENT_RLC_UMUL_REASSEMBLE_TMR:
239       {
240          arg.timers  = &((RlcUlRbCb *)cb)->m.umUl.reAsmblTmr;
241          arg.max = RLC_MAX_UM_TMR;
242          break;
243       }
244       case EVENT_RLC_AMUL_REASSEMBLE_TMR:
245       {
246          arg.timers = &((RlcUlRbCb *)cb)->m.amUl.reAsmblTmr;
247          arg.max = RLC_MAX_AM_TMR;
248          break;
249       }
250       case EVENT_RLC_AMUL_STA_PROH_TMR:
251       {
252          arg.timers = &((RlcUlRbCb *)cb)->m.amUl.staProhTmr;
253          arg.max = RLC_MAX_AM_TMR;
254          break;
255       } 
256       case EVENT_RLC_AMDL_POLL_RETX_TMR:
257       {
258          arg.timers = &((RlcDlRbCb *)cb)->m.amDl.pollRetxTmr;
259          arg.max = RLC_MAX_AM_TMR;
260          break;
261       } 
262       case EVENT_RLC_WAIT_BNDCFM:
263       {
264          arg.timers = &((RlcRguSapCb *)cb)->bndTmr;
265          arg.max = RLC_MAX_RGUSAP_TMR;
266          break;
267       }
268 /* kw005.201 added support for L2 Measurement */
269 #ifdef LTE_L2_MEAS
270       case EVENT_RLC_L2_TMR:
271       {
272          measEvtCb = (RlcL2MeasEvtCb *)cb;
273          arg.timers   = &measEvtCb->l2Tmr;
274          arg.max  = RLC_L2_MAX_TIMERS;
275          break;
276       }
277 #endif
278       case EVENT_RLC_THROUGHPUT_TMR:
279       {
280          arg.timers   = &((RlcThpt *)cb)->thptTmr;
281          arg.max  = RLC_MAX_THPT_TMR;
282       }
283       case EVENT_RLC_UE_DELETE_TMR:
284       {
285          arg.timers   = &((RlcUlUeCb*)cb)->ueDeleteInfo.ueDelTmr;
286          arg.max  = EVENT_RLC_UE_DELETE_TMR;
287       }
288       default:
289       {
290          DU_LOG("\nERROR  -->  RLC : rlcStopTmr: Invalid tmr Evnt[%d]", tmrType);
291       }
292    } 
293    if (tmrType != TMR0)
294    {
295       arg.tqCp   = &gCb->rlcTqCp;
296       arg.tq     = gCb->rlcTq;
297       arg.cb     = cb;
298       arg.evnt   = tmrType;
299       arg.wait   = 0;
300       arg.tNum   = 0;
301       cmRmvCbTq(&arg);
302    }
303    
304    return;
305 }
306
307 /**
308  * @brief Handler to invoke events on expiry of timer.
309  *
310  * @details
311  *    This function is used to handle expiry of timer,it invokes relevant 
312  *    functions.
313  *       
314  * @param[in] cb        Control block depending on the type of the timer event. 
315  *                      It can be uplink/downlink rbCb or rgu sap control block
316  * @param[in] tmrEvnt   Timer event to be started
317  *
318  * @return  Void
319 */
320 Void rlcTmrExpiry(PTR cb,S16 tmrEvnt)
321 {
322 /* kw005.201 added support for L2 Measurement */
323
324    switch (tmrEvnt)
325    {
326       case EVENT_RLC_UMUL_REASSEMBLE_TMR:
327       {
328          RlcUlRbCb *ulRbCb = (RlcUlRbCb *)cb;
329          rlcUmmReAsmblTmrExp(RLC_GET_RLCCB(ulRbCb->inst), ulRbCb);
330
331          break;
332       }
333       case EVENT_RLC_AMUL_REASSEMBLE_TMR:
334       {
335          RlcUlRbCb *ulRbCb = (RlcUlRbCb *)cb;
336          rlcAmmReAsmblTmrExp(RLC_GET_RLCCB(ulRbCb->inst), ulRbCb);
337          break;
338       }
339       case EVENT_RLC_AMUL_STA_PROH_TMR:
340       {
341          RlcUlRbCb *ulRbCb = (RlcUlRbCb *)cb;
342          rlcAmmStaProTmrExp(RLC_GET_RLCCB(ulRbCb->inst), ulRbCb);
343
344          break;
345       }
346       case EVENT_RLC_AMDL_POLL_RETX_TMR:
347       {
348          RlcDlRbCb *dlRbCb = (RlcDlRbCb *)cb;
349          RlcCb *gCb = RLC_GET_RLCCB(dlRbCb->inst);
350          
351          rlcAmmPollRetxTmrExp(gCb, dlRbCb);
352
353          gCb->genSts.protTimeOut++;
354          break;
355       }
356       case EVENT_RLC_WAIT_BNDCFM:
357       {
358          rlcBndTmrExpiry(cb);
359          break;
360       }
361       case EVENT_RLC_THROUGHPUT_TMR:
362       {
363          rlcThptTmrExpiry(cb);
364          break;
365       }
366       case EVENT_RLC_UE_DELETE_TMR:
367       {
368          rlcUeDeleteTmrExpiry(cb);
369          break;
370       }
371       default:
372       {
373          break;
374       }
375    }
376
377    return;
378 }
379
380 /**
381  * @brief Handler to check if the timer is running
382  *       
383  * @param[in] gCb       Pointer to the RLC instance control block
384  * @param[in] cb        Control block depending on the type of the timer event. 
385  *                      It can be uplink/downlink rbCb or rgu sap control block
386  * @param[in] tmrEvnt   Timer event to be started
387  *
388  * @return  Bool indicating whether the timer is running or not
389  *      -# ROK 
390  *      -# RFAILED 
391 */
392 bool rlcChkTmr(RlcCb *gCb, PTR cb, int16_t tmrEvnt)
393 {
394    switch (tmrEvnt)
395    {
396       case EVENT_RLC_UMUL_REASSEMBLE_TMR:
397       {
398          return (((RlcUlRbCb *)cb)->m.umUl.reAsmblTmr.tmrEvnt == 
399                   EVENT_RLC_UMUL_REASSEMBLE_TMR);
400       }
401       case EVENT_RLC_AMUL_REASSEMBLE_TMR:
402       {
403          return (((RlcUlRbCb *)cb)->m.amUl.reAsmblTmr.tmrEvnt == 
404                   EVENT_RLC_AMUL_REASSEMBLE_TMR);
405       }
406       case EVENT_RLC_AMUL_STA_PROH_TMR:
407       {
408          return (((RlcUlRbCb *)cb)->m.amUl.staProhTmr.tmrEvnt == 
409                   EVENT_RLC_AMUL_STA_PROH_TMR);
410       } 
411       case EVENT_RLC_AMDL_POLL_RETX_TMR:
412       {
413          return (((RlcDlRbCb *)cb)->m.amDl.pollRetxTmr.tmrEvnt == 
414                   EVENT_RLC_AMDL_POLL_RETX_TMR);
415       } 
416       case EVENT_RLC_WAIT_BNDCFM:
417       {
418          return (((RlcRguSapCb *)cb)->bndTmr.tmrEvnt == EVENT_RLC_WAIT_BNDCFM);
419       }
420       case EVENT_RLC_THROUGHPUT_TMR:
421       {
422          return (((RlcThpt *)cb)->thptTmr.tmrEvnt == EVENT_RLC_THROUGHPUT_TMR);
423       }
424       case EVENT_RLC_UE_DELETE_TMR:
425       {
426          return (((RlcUlUeCb *)cb)->ueDeleteInfo.ueDelTmr.tmrEvnt == EVENT_RLC_UE_DELETE_TMR);
427       }
428       default:
429       {
430          DU_LOG("\nERROR  -->  RLC : rlcChkTmr: Invalid tmr Evnt [%d]", tmrEvnt);
431       }
432    } 
433
434    return FALSE;
435 }
436
437 /**
438  * @brief Handler to do processing on expiry of the bind timer
439  *
440  * @details
441  *    This function processes the RLC bind timer expiry. If the number of
442  *    retries is less than the maximum retry counter, bind request is sent
443  *    again, else an alarm is raised to the layer manager.
444  *
445  * @param[in] cb  Pointer to the Rgu sap
446  *
447  * @return  Void
448 */
449 static Void rlcBndTmrExpiry(PTR cb)
450 {
451    RlcRguSapCb *rguSapCb;
452
453    rguSapCb = (RlcRguSapCb *) cb;
454
455    if (rguSapCb->state == RLC_SAP_BINDING)
456    {
457       if (rguSapCb->retryCnt < RLC_MAX_SAP_BND_RETRY)
458       {
459          /* start timer to wait for bind confirm */
460          rlcStartTmr(RLC_GET_RLCCB(rguSapCb->pst.srcInst),
461                     (PTR)rguSapCb,
462                     EVENT_RLC_WAIT_BNDCFM);
463
464          /* Send bind request */
465          rguSapCb->retryCnt++;
466          RlcLiRguBndReq (&rguSapCb->pst, rguSapCb->suId, rguSapCb->spId);
467       }
468       else
469       {
470          rguSapCb->retryCnt = 0;
471          rguSapCb->state = RLC_SAP_CFG;
472
473          /* Send alarm to the layer manager */
474 #ifdef LTE_L2_MEAS
475          rlcLmmSendAlarm(RLC_GET_RLCCB(rguSapCb->pst.srcInst),
476                         LCM_CATEGORY_INTERFACE,
477                         LCM_EVENT_BND_FAIL,
478                         LCM_CAUSE_TMR_EXPIRED,
479                         0,
480                         0,
481                         0);
482 #else
483          rlcLmmSendAlarm(RLC_GET_RLCCB(rguSapCb->pst.srcInst),
484                         LCM_CATEGORY_INTERFACE,
485                         LCM_EVENT_BND_FAIL,
486                         LCM_CAUSE_TMR_EXPIRED,
487                         0, /* suId */
488                         0 /* ueId */);
489 #endif
490       }
491    }
492
493    return;
494 }
495
496 /**
497  * @brief Handler to do processing on expiry of the throughput timer
498  *
499  * @details
500  *    This function processes the RLC throughput timer expiry.
501  *
502  * @param[in] cb  Pointer to the RLC throughput struct
503  *
504  * @return  Void
505  */
506 void rlcThptTmrExpiry(PTR cb)
507 {
508    uint16_t  ueIdx;
509    long double tpt;
510    RlcThpt *rlcThptCb = (RlcThpt*)cb; 
511    
512    /* If cell is not up, throughput details cannot be printed */
513    if(gCellStatus != CELL_UP)
514    {
515       /* Restart timer */
516       rlcStartTmr(RLC_GET_RLCCB(rlcThptCb->inst), (PTR)rlcThptCb, EVENT_RLC_THROUGHPUT_TMR);
517       return;
518    }
519
520    /* If cell is up, print throughout for each UE attached to the cell */
521    DU_LOG("\n===================== DL Throughput ==============================");
522    DU_LOG("\nNumber of UEs : %d", rlcThptCb->numActvUe);
523    if(rlcThptCb->numActvUe)
524    {
525       for(ueIdx = 0; ueIdx < MAX_NUM_UE; ueIdx++)
526       {
527          if(rlcThptCb->thptPerUe[ueIdx].ueId)
528          {
529             /* Spec 28.552, section 5.1.1.3 : 
530              * Throughput in kilobits/sec = (dataVol in kiloBits * 1000)/time in milligseconds
531              * 
532              * Since our dataVol is in bytes, multiplying 0.008 to covert into kilobits i.e. 
533              * Throughput[kbits/sec] = (dataVol * 0.008 * 1000)/time in ms
534              */
535              tpt = (double)(rlcThptCb->thptPerUe[ueIdx].dataVol * 8)/(double)ODU_THROUGHPUT_PRINT_TIME_INTERVAL;
536       
537              DU_LOG("\nUE Id : %d   DL Tpt : %.2Lf", rlcThptCb->thptPerUe[ueIdx].ueId, tpt);
538              rlcThptCb->thptPerUe[ueIdx].dataVol = 0;
539          }
540       }
541    }
542    DU_LOG("\n==================================================================");
543
544    /* Restart timer */
545    rlcStartTmr(RLC_GET_RLCCB(rlcThptCb->inst), (PTR)rlcThptCb, EVENT_RLC_THROUGHPUT_TMR);
546
547    return;
548 }
549
550 /**
551 *
552 * @brief filling RLC UE delete configuration
553 *
554 * @details
555 *    filling RLC UE delete configuration
556 *
557 * @params[in] RlcUlUeCb *ueCb, RlcCfgInfo *rlcUeCfg
558 *
559 * @return void
560 *
561 */
562
563 void fillRlcUeDelInfo(RlcUlUeCb *ueCb, RlcCfgInfo *rlcUeCfg)
564 {
565    uint8_t lcIdx;
566
567    rlcUeCfg->ueId    = ueCb->ueId;
568    rlcUeCfg->cellId  = ueCb->cellId;
569    rlcUeCfg->numEnt = 0;
570    for(lcIdx=0; lcIdx<RLC_MAX_LCH_PER_UE && rlcUeCfg->numEnt < 1; lcIdx++)
571    {
572       if(ueCb->lCh[lcIdx].ulRbCb != NULLP)
573       {
574          rlcUeCfg->entCfg[rlcUeCfg->numEnt].rbId    = 0;
575          rlcUeCfg->entCfg[rlcUeCfg->numEnt].rbType  = 0;
576          rlcUeCfg->entCfg[rlcUeCfg->numEnt].cfgType = CKW_CFG_DELETE_UE;
577          rlcUeCfg->numEnt++;
578       }
579    }
580 }
581
582 /**
583 * @brief Handler to do processing on expiry of the UE delete timer
584 *
585 * @details
586 *    This function processes the RLC UE delete timer expiry.
587 *
588 * @param[in] cb  Pointer to the RlcUlUeCb  
589 *
590 * @return  uint8_t
591 */
592
593 uint8_t rlcUeDeleteTmrExpiry(PTR cb)
594 {
595    RlcCb *gRlcCb = NULLP;
596    RlcCfgInfo *rlcUeCfg = NULLP;
597    RlcUlUeCb *ueCb = (RlcUlUeCb*)cb;
598
599    gRlcCb = RLC_GET_RLCCB(ueCb->ueDeleteInfo.pst.dstInst);
600    RLC_ALLOC(gRlcCb, rlcUeCfg, sizeof(RlcCfgInfo));
601    if(rlcUeCfg == NULLP)
602    {
603       DU_LOG("\nERROR  -->  RLC: rlcUeDeleteTmrExpiry(): Failed to allocate memory");
604       return RFAILED;
605    }
606    memset(rlcUeCfg, 0, sizeof(RlcCfgInfo));
607    fillRlcUeDelInfo(ueCb, rlcUeCfg);
608    if(RlcProcCfgReq(&ueCb->ueDeleteInfo.pst, rlcUeCfg) != ROK)
609    {
610       DU_LOG("\nERROR  -->  RLC: rlcUeDeleteTmrExpiry(): Failed to delete UE");
611       if(sendRlcUeDeleteRspToDu(rlcUeCfg->cellId, rlcUeCfg->ueId, INVALID_UEID) != ROK)
612       {
613          DU_LOG("ERROR  --> RLC: rlcUeDeleteTmrExpiry(): Failed to send UE delete response ");
614          return RFAILED;
615       }
616    }
617    return ROK;
618 }
619 \f  
620 /********************************************************************30**
621   
622          End of file
623 **********************************************************************/