Initial commit
[o-du/l2.git] / src / 5gnrrlc / kw_umm_dl.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_dl.c
35
36 **********************************************************************/
37 static const char* RLOG_MODULE_NAME="RLC";
38 static int RLOG_MODULE_ID=2048;
39 static int RLOG_FILE_ID=239;
40 /** 
41  * @file kw_umm_dl.c
42  * @brief RLC Unacknowledged Mode downlink module
43 */
44
45 /* header (.h) include files */
46 #include "envopt.h"             /* environment options */
47 #include "envdep.h"             /* environment dependent */
48 #include "envind.h"             /* environment independent */
49
50 #include "gen.h"                /* general */
51 #include "ssi.h"                /* system services interface */
52 #include "cm5.h"                /* Timer Functions */
53 #include "cm_lte.h"             /* common umts header file */
54 #include "cm_hash.h"            /* common hash module  file */
55 #include "cm_llist.h"           /* common list header file */
56 #include "ckw.h"                /* RRC layer */
57 #include "lkw.h"                /* RRC layer */
58 #include "kwu.h"                /* RLC service user */
59 #include "lkw.h"                /* LM Interface */
60 #include "rgu.h"                /* MAC layer */
61 #include "kw_env.h"             /* RLC environment options */
62
63 #include "kw.h"                 /* RLC layer */
64 #include "kw_err.h"
65 #include "kw_udx.h"
66 #include "kw_dl.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_udx.x"
85 #include "kw_dl.x"
86
87 #define KW_MODULE (KW_DBGMASK_UM | KW_DBGMASK_DL)
88
89 /* variables for logging :declared in BRDCM cl */
90 #ifndef TENB_ACC
91 extern U32 dldrops_kwu_um;
92 extern U32 dlpkt_um;
93 extern U32 buffer_occ;
94 extern U32 dlrate_kwu;
95 #endif
96
97 PRIVATE Void kwUmmEstHdrSz ARGS ((KwUmDl *umUl));
98
99 PRIVATE Void kwUmmCreatePdu ARGS ((KwCb *gCb,
100                                   KwDlRbCb *rbCb, 
101                                   Buffer *pdu,
102                                   U8 fi,
103                                   KwPduInfo *datReqPduInfo));
104
105 /** @addtogroup ummode */
106 /*@{*/
107
108 /**
109  * @brief  Handler to queue a SDU in the SDU queue, update BO and report 
110  *         it to the lower layer.
111  *       
112  * @details
113  *    This function is used to queue the received SDU in the 
114  *    SDU queue maintained in the radio bearer control block.
115  *    After queuing the SDU, BO is updated and is reported
116  *    to the lower layer. 
117  *
118  * @param[in] gCb      RLC Instance control block
119  * @param[in] rbCb     RB control block 
120  * @param[in] datReq   Ptr to the datReq sent from PDCP
121  * @param[in] mBuf     Sdu data
122  *
123  * @return  Void
124 */  
125 #ifdef ANSI
126 PUBLIC Void kwUmmQSdu       
127 (
128 KwCb            *gCb,
129 KwDlRbCb        *rbCb, 
130 KwuDatReqInfo   *datReq,  
131 Buffer          *mBuf 
132 )
133 #else
134 PUBLIC Void kwUmmQSdu(gCb,rbCb,datReq,mBuf)
135 KwCb            *gCb;
136 KwDlRbCb        *rbCb;
137 KwuDatReqInfo   *datReq; 
138 Buffer          *mBuf;
139 #endif
140 {
141    MsgLen   len;    /* SDU buffer length */
142    KwSdu    *sdu;   /* SDU */
143
144    TRC2(kwUmmQSdu)
145
146    KW_UPD_L2_DL_TOT_SDU_STS(gCb,rbCb);
147
148    KW_ALLOC_WC(gCb, sdu, (Size)sizeof(KwSdu));
149 #if (ERRCLASS & ERRCLS_ADD_RES)
150    if ( sdu == NULLP )
151    {
152       RLOG_ARG2(L_FATAL,DBG_RBID,rbCb->rlcId.rbId,
153                "Memory allocation failed UEID:%d CELLID:%d",
154                rbCb->rlcId.ueId,
155                rbCb->rlcId.cellId);
156       SPutMsg(mBuf);
157       RETVOID;
158    }
159 #endif /* ERRCLASS & ERRCLS_ADD_RES */
160
161 /* Discard new changes starts */
162    kwUtlGetCurrTime(&sdu->arrTime);
163 /* Discard new changes ends */
164    SFndLenMsg(mBuf,&len);
165
166    sdu->mBuf = mBuf;
167    sdu->sduSz = len;
168    sdu->actSz = len;
169    sdu->mode.um.sduId = datReq->sduId;
170    sdu->mode.um.isSegmented = FALSE;
171 #ifndef RGL_SPECIFIC_CHANGES
172 #ifndef TENB_ACC
173 #ifndef LTE_PAL_ENB
174    {
175          dlrate_kwu += len;
176    }
177 #endif   
178 #endif
179 #endif
180    rbCb->m.umDl.bo += len;
181    
182    cmLListAdd2Tail(&(rbCb->m.umDl.sduQ), &sdu->lstEnt);
183    sdu->lstEnt.node = (PTR)sdu;
184    
185    kwUmmEstHdrSz(&rbCb->m.umDl);
186
187    if(!kwDlUtlIsReestInProgress(rbCb))
188    {
189       kwUtlSndDStaRsp(gCb,rbCb,rbCb->m.umDl.bo,rbCb->m.umDl.estHdrSz,FALSE,0);
190    }
191    
192    /* kw005.201 added support for L2 Measurement */
193 #ifdef LTE_L2_MEAS_RLC
194    /* Update numActUe if it is not active */
195    if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_ACT_UE) &&
196       (rbCb->ueCb->numActRb[rbCb->qci]++ == 0))
197    {
198      kwCb.kwL2Cb.numActUe[rbCb->qci]++;
199    }
200 #endif
201
202    RETVOID;    
203 }
204
205
206 /**
207  * @brief   Handler to form PDU(s) and update the BO. 
208  *       
209  * @details
210  *     -# This function forms pdu(s) from the SDU(s) in the
211  *        SDU queue and returns them.
212  *     -# This function also updates the BO along with the 
213  *        along with the estimated Header size.
214  *
215  * @param[in]  rbCb     RB control block 
216  * @param[out] pduInfo  Pdu Info to be filled and the PDU size to be 
217  *                      formed and the updated BO
218  * @param[in]  pduSz    The size for which PDUs have to constructed
219  *
220  * @return  S16
221  *    -# ROK       In case of success
222  *    -# RFAILED   If allocation of Sdu fails
223 */  
224 #ifdef ANSI
225 PUBLIC Void kwUmmProcessSdus
226 (
227 KwCb       *gCb,
228 KwDlRbCb   *rbCb,   
229 KwDatReq   *datReq   
230 )
231 #else
232 PUBLIC Void kwUmmProcessSdus(gCb, rbCb, datReq)
233 KwCb       *gCb;
234 KwDlRbCb   *rbCb; 
235 KwDatReq   *datReq;
236 #endif
237 {
238    CmLList     *firstNode;   /* First Node in SDU queue */
239    U8          fi=0;           /* Framing Info */
240    Buffer      *pdu;         /* Buffer for holding the formed PDU */
241    KwPduInfo   *pduInfo;     /* PDU Info pointer */
242    S16         pduSz;        /* PDU Size to be constructed */
243    
244    /* kw005.201 added support for L2 Measurement */
245 #ifdef LTE_L2_MEAS
246    KwContSduLst         contSduLst;  /*Contained sduLst */
247    S32                  dataVol    = rbCb->m.umDl.bo;
248    U32*                 totMacGrant= &(datReq->totMacGrant);
249    KwL2MeasDlIpTh       *dlIpThPut = &rbCb->l2MeasIpThruput.dlIpTh;
250    U8                   *sduIdx    = &dlIpThPut->lastSduIdx;
251    Bool                 newIdx = FALSE;
252    S32                  oldBo;
253    KwlchInfo            lchInfo = {0};
254    U32                  segSduCnt = 0;
255 #endif
256    Ticks                curTime  = 0;
257    S16                  timeDiff = 0;
258    KwSdu                *sdu;
259
260
261    TRC2(kwUmmProcessSdus)
262
263
264    pdu = NULLP;
265
266    pduInfo = &(datReq->pduInfo);
267    pduSz = datReq->pduSz;
268    
269 #ifdef LTE_L2_MEAS   
270    contSduLst.numSdus = 0;
271    contSduLst.lcId = rbCb->lch.lChId;
272    oldBo = rbCb->m.umDl.bo; 
273    lchInfo.lcId = rbCb->lch.lChId;
274    lchInfo.numSdus = 0;
275 #endif
276
277    /* Discard new changes starts */
278    kwUtlGetCurrTime(&curTime);
279
280    /* ccpu00143043 */
281    while ((pduSz > 0) && (rbCb->m.umDl.sduQ.count > 0) &&
282            (rbCb->m.umDl.numLi < KW_MAX_DL_LI) && (pduInfo->numPdu < KW_MAX_PDU))
283    {
284       CM_LLIST_FIRST_NODE(&rbCb->m.umDl.sduQ,firstNode);
285       sdu = (KwSdu *)(firstNode->node);
286
287       if ((sdu->mode.um.isSegmented == FALSE) && (rbCb->discTmrInt > 0) && 
288             (rbCb->rlcId.rbType == CM_LTE_DRB))
289       {
290          timeDiff = KW_TIME_DIFF(curTime,sdu->arrTime); 
291
292          if (timeDiff >= rbCb->discTmrInt)
293          {
294 #ifdef LTE_L2_MEAS 
295             KW_UPD_L2_DL_DISC_SDU_STS(gCb, rbCb);
296 #endif
297             rbCb->m.umDl.bo -= sdu->sduSz;
298             KW_RMV_SDU(gCb,&rbCb->m.umDl.sduQ,sdu);
299             continue;
300          }
301       }
302       /* When forming a new PDU, pdu == NULLP
303            -# Eliminate MAC header size for each pdu 
304            -# Initialize the li array to 0 
305            -# Substract the fixed header length based on SN length
306       */
307 #ifdef LTE_L2_MEAS
308       newIdx = FALSE;
309 #endif
310       if (!pdu)
311       {
312          KW_RMV_MAC_HDR_SZ(pduSz);
313
314          /* account for the RLC header size */
315          pduSz -= rbCb->m.umDl.snLen;
316
317          /* kw005.201 fixing pduSz <= 0 problem, ccpu00119417 */
318          if(pduSz <= 0)
319          {
320             break;
321          }         
322          
323          rbCb->m.umDl.numLi = 0;
324          if (sdu->mode.um.isSegmented == TRUE)
325          {
326             fi = 2;
327          }
328          else
329          {
330             fi = 0;
331          }
332       }
333
334       kwUtlCalcLiForSdu(gCb,rbCb->m.umDl.numLi,sdu->sduSz,&pduSz);
335      
336       /* Exact fit scenario :
337          If the SDU size matches with the PDU size
338            -# Allocate memory equal to PDU size;
339            -# update BO
340            -# Remove SDu from queue
341            -# Append to already existing PDU portion if present .
342            -# Add Header and create complete PDU and place it in
343               pduInfo and return
344       */ 
345       if (sdu->sduSz == pduSz)
346       {
347          if (!pdu)
348          {
349             pdu = sdu->mBuf;
350             sdu->mBuf = NULLP;
351          }
352          else
353          {
354             SCatMsg(pdu, sdu->mBuf, M1M2);    
355          }
356          
357          rbCb->m.umDl.bo -= pduSz;
358          pduSz = 0;
359
360 #ifdef LTE_L2_MEAS
361         if(KW_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb))
362         {
363            if(sdu->mode.um.isSegmented)
364            {
365               *sduIdx    = dlIpThPut->lastSduIdx;
366            }
367            else
368            {
369               KW_GETSDUIDX(*sduIdx);
370               newIdx = TRUE;
371            }
372            kwUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
373            kwUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz, 
374                  sdu->mode.um.sduId, newIdx);
375            /* ccpu00143043 */
376            if ( lchInfo.numSdus < KW_L2MEAS_SDUIDX)
377            {
378               lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime; 
379               lchInfo.sduInfo[lchInfo.numSdus].isRetxPdu = FALSE;
380               lchInfo.numSdus++;
381            }
382         }
383 #endif
384 /* kw005.201 added support for L2 Measurement */
385 #ifdef LTE_L2_MEAS_RLC
386          kwUtlUpdSduSnMap(rbCb, sdu, datReq, TRUE);
387          if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_DL_DELAY) ||
388                  (rbCb->rbL2Cb.measOn & LKW_L2MEAS_UU_LOSS))
389           {
390              /* ccpu00143043 */
391              if ( lchInfo.numSdus < KW_L2MEAS_SDUIDX)
392              {
393                 lchInfo.arvlTime[lchInfo.numSdus] = sdu->arrTime; 
394                 lchInfo.numSdus++;
395              }
396           }
397 #endif /*  LTE_L2_MEAS */
398          KW_RMV_SDU(gCb,&(rbCb->m.umDl.sduQ),sdu); /* kw003.201 */
399          kwUtlIncrementKwuStsSduTx(gCb->u.dlCb->kwuDlSap + rbCb->kwuSapId);
400
401          kwUmmCreatePdu(gCb,rbCb,pdu,fi,pduInfo);
402          pdu = NULLP;
403          
404       }
405       /* Concatenation scenario :
406          If SDU size is less than the requested PDU size
407            -# Allocate memory and copy SDU into it.
408            -# Update BO
409            -# Remove SDU from the Queue.
410            -# Append to already existing PDU portion if present .
411            -# If the SDU size is greater than 2047 or the number of i
412                  LIs reaches max, place it as a separate PDU in pduInfo and 
413                  set pdu to NULL
414               else 
415                  place the msglen in li array and continue with the next SDU.
416            -# If the number of PDUs is more than KW_MAX_PDU, return from 
417               the function even if pduSize > 0.
418       */
419       else if (sdu->sduSz < pduSz)
420       {
421          if (!pdu)
422          {
423             pdu = sdu->mBuf;
424             sdu->mBuf = NULLP;
425          }
426          else
427          {
428             SCatMsg(pdu, sdu->mBuf ,M1M2);
429          }
430          rbCb->m.umDl.bo -= sdu->sduSz;
431
432          pduSz -= sdu->sduSz;
433 /* kw005.201 added support for L2 Measurement */
434 #ifdef LTE_L2_MEAS_RLC
435           kwUtlUpdSduSnMap(rbCb, sdu, datReq, TRUE);
436 #endif /*  LTE_L2_MEAS */
437          if (sdu->sduSz < 2048 && rbCb->m.umDl.numLi < KW_MAX_DL_LI)
438          {
439             rbCb->m.umDl.li[(rbCb->m.umDl.numLi)++] = sdu->sduSz;
440          }
441          else 
442          {
443             kwUmmCreatePdu(gCb, rbCb, pdu, fi, pduInfo);
444             pdu = NULLP;
445
446             if ( pduInfo->numPdu == KW_MAX_PDU)
447             {
448                 /* Could not transmit what MAC asked for because the number 
449                  * of PDUs to be transmitted has reached maximum. */
450                RLOG_ARG2(L_DEBUG,DBG_RBID,rbCb->rlcId.rbId, 
451                         "Maximum Pdu limit has been reached UEID:%d CELLID:%d",
452                         rbCb->rlcId.ueId,
453                         rbCb->rlcId.cellId);
454                break;
455             }
456          }
457 #ifdef LTE_L2_MEAS
458         if(KW_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) )
459         {
460            if(sdu->mode.um.isSegmented)
461            {
462               *sduIdx    = dlIpThPut->lastSduIdx;
463            }
464            else
465            {
466               KW_GETSDUIDX(*sduIdx);
467               newIdx = TRUE;
468            }
469            kwUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
470            kwUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz, 
471                  sdu->mode.um.sduId, newIdx);
472            /* ccpu00143043 */
473            if ( lchInfo.numSdus < KW_L2MEAS_SDUIDX)
474            {
475               lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime; 
476               lchInfo.sduInfo[lchInfo.numSdus].isRetxPdu = FALSE;
477               lchInfo.numSdus++;
478            }
479         }
480 #endif
481          KW_RMV_SDU(gCb,&(rbCb->m.umDl.sduQ),sdu);
482          /* kw005.201 ccpu00117318, updating the statistics */
483          kwUtlIncrementKwuStsSduTx(gCb->u.dlCb->kwuDlSap + rbCb->kwuSapId);         
484       }
485       /* Segmentation scenario :
486          If size of SDU is greater than PDU size 
487            -# Allocate memory and Segment the Sdu.
488            -# Update BO
489            -# Append to already existing PDU if any.
490            -# Set the second bit of the framing info.
491            -# Create the complete PDU and place in pduInfo.
492       */ 
493       else 
494       {
495          Buffer *remSdu;
496        
497          SSegMsg(sdu->mBuf,pduSz,&remSdu);
498         
499 #ifdef LTE_L2_MEAS
500         if(KW_MEAS_IS_DL_IP_MEAS_ON_FOR_RB(gCb, rbCb))
501         {
502            if(sdu->mode.um.isSegmented)
503            {
504               *sduIdx    = dlIpThPut->lastSduIdx;
505            }
506            else
507            {
508               KW_GETSDUIDX(*sduIdx);
509               newIdx = TRUE;
510            }
511            kwUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
512            kwUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz, 
513                  sdu->mode.um.sduId, newIdx);
514         }
515         if(KW_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb))
516         {
517            if(sdu->actSz == sdu->sduSz)
518            {
519               segSduCnt++;
520            }
521         }
522 #endif
523          if (!pdu)
524          {
525             pdu = sdu->mBuf;
526          }
527          else 
528          {
529             SCatMsg(pdu, sdu->mBuf, M1M2);
530             KW_FREE_BUF_WC(sdu->mBuf);
531          }
532
533          sdu->sduSz -= pduSz;
534          rbCb->m.umDl.bo -= pduSz;
535          sdu->mode.um.isSegmented = TRUE;
536          sdu->mBuf = remSdu;
537          pduSz = 0;
538          
539          fi |= 1;
540 /* kw005.201 added support for L2 Measurement */
541 #ifdef LTE_L2_MEAS_RLC
542          kwUtlUpdSduSnMap(rbCb, sdu, datReq, FALSE);
543 #endif /*  LTE_L2_MEAS */
544
545          kwUmmCreatePdu(gCb,rbCb,pdu,fi,pduInfo);
546          pdu = NULLP;
547       }
548 /* kw005.201 added support for L2 Measurement */
549    }
550 #ifdef LTE_L2_MEAS_RLC
551    if((rbCb->rbL2Cb.measOn) && 
552       (rbCb->m.umDl.sduQ.count == 0) && 
553       (dataWasPrsnt))
554    {
555       if(--(rbCb->ueCb->numActRb[rbCb->qci]) == 0)
556       {
557          kwCb.kwL2Cb.numActUe[rbCb->qci]--;
558       }
559    }
560 #endif /* LTE_L2_MEAS */
561 #ifdef LTE_L2_MEAS
562    kwUtlUpdateBurstSdus(gCb, rbCb, &contSduLst, dataVol, *totMacGrant);
563    /* Need to check into optimizing this code : TODO */
564    if(KW_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) && (lchInfo.numSdus != 0))
565    {
566       KwL2MeasTb *l2MeasTb = kwUtlGetCurMeasTb(gCb, rbCb);
567       /* ccpu00143043 */
568       /* Fix Klock warning */
569       if ((lchInfo.numSdus != 0) && (l2MeasTb != NULLP) &&
570           (l2MeasTb->numLchInfo < KW_MAX_ACTV_DRB))
571       {   
572          cmMemcpy((U8 *) &l2MeasTb->lchInfo[l2MeasTb->numLchInfo], (U8 *) &lchInfo, sizeof(KwlchInfo));
573          l2MeasTb->numLchInfo++;
574       }
575       l2MeasTb->txSegSduCnt += segSduCnt;
576    }
577    *totMacGrant -= (oldBo - rbCb->m.umDl.bo);
578 #endif 
579
580    /* If we have a situation wherein the size requested is greater than the total size of SDUs
581       and a pdu buffer which is not null, this if loop helps to send 
582       a non null PDU to the lower layer. 
583    */
584    if (pduSz > 0 && pdu)
585    {
586       if (pduInfo->numPdu != KW_MAX_PDU)
587       {
588          rbCb->m.umDl.numLi--;         
589          kwUmmCreatePdu(gCb,rbCb,pdu,fi,pduInfo);   
590          pdu = NULLP;
591       }
592       else
593       {
594          KW_FREE_BUF_WC(pdu);
595       }
596    }
597    
598    kwUmmEstHdrSz(&rbCb->m.umDl);
599    datReq->boRep.bo = rbCb->m.umDl.bo;
600    datReq->boRep.estHdrSz = rbCb->m.umDl.estHdrSz;
601    datReq->boRep.staPduPrsnt = FALSE;
602    if (rbCb->m.umDl.sduQ.count > 0)
603    {
604       datReq->boRep.oldestSduArrTime = 
605         ((KwSdu *)(rbCb->m.umDl.sduQ.first->node))->arrTime;
606    }
607    RETVOID; 
608 }
609
610 /**
611  * @brief   Handler to process the re-establishment request received from i
612  *          the upper layer. 
613  *       
614  * @details
615  *     This function does the following functions : 
616  *         Remove all the SDUs in the SDU queue.
617  *
618  * @param[in] gCb        RLC Instance control block
619  * @param[in] rlcID      Identity of the RLC entity for which 
620  *                       re-establishment is to be done
621  * @param[in] sendReEst  Whether to send re-establishment complete 
622  *                       indication to  upper layer or not
623  * @param[in] rbCb       RB control block for which re-establishment 
624  *                       is to be done
625  *
626  * @return  Void
627 */ 
628 #ifdef ANSI
629 PUBLIC Void kwDlUmmReEstablish
630 (
631 KwCb         *gCb,
632 CmLteRlcId   rlcId,
633 Bool         sendReEst,
634 KwDlRbCb     *rbCb
635 )
636 #else
637 PUBLIC Void kwDlUmmReEstablish(gCb, rlcId, rbCb)
638 KwCb         *gCb;
639 CmLteRlcId   rlcId;
640 Bool         sendReEst;
641 KwDlRbCb       *rbCb;
642 #endif
643 {
644    /* The re-establishment indication is sent from the UL only */
645    TRC2(kwDlUmmReEstablish)
646
647
648    kwUmmFreeDlRbCb(gCb, rbCb);
649
650    rbCb->m.umDl.vtUs = 0;
651
652    /* this would have been set when re-establishment was triggered
653       for SRB 1 */
654    kwDlUtlResetReestInProgress(rbCb);
655    
656    RETVOID;
657 }
658 /**
659  * @brief   Handler to create the header and complete a PDU.
660  *       
661  * @details
662  *     This function is used to create the header of a PDU and concatenate  it
663  *     with the data part of the PDU.
664  *     Also updates the statistics
665  *     Sets the passed pdu to NULLP
666  *
667  * @param[in]     gCb            RLC instance control block
668  * @param[in,out] rbCb           RB control block 
669  * @param[in]     pdu            PDU  
670  * @param[in]     fi             Framing Info field
671  * @param[out]    datReqPduInfo  Holder in which to copy the created PDU pointer
672  *
673  * @return  Void
674 */ 
675 #ifdef ANSI
676 PRIVATE Void kwUmmCreatePdu
677 (
678 KwCb        *gCb,
679 KwDlRbCb    *rbCb,           
680 Buffer      *pdu,           
681 U8          fi, 
682 KwPduInfo   *datReqPduInfo
683 )
684 #else
685 PRIVATE Void kwUmmCreatePdu(gCb, rbCb, pdu, fi, datReqPduInfo)
686 KwCb        *gCb;
687 KwDlRbCb    *rbCb;          
688 Buffer      *pdu;           
689 U8          fi;
690 KwPduInfo   *datReqPduInfo
691 #endif
692 {
693    KwSn   sn;        /*  Sequence Number */
694    U32    liCount;   /*  LI count */
695    U8     e = 0;     /* Extension Bit */
696    U32    count;     /* Loop Counter */
697    U32    hdrSz;
698
699    /* create a big array to store the header, assuming 3 bytes per 2 L1s 
700     * (2 bytes if only a single LI) and 2 bytes for the 
701     *  FI and SN
702     * size of header = ( NumLi /2 ) * 3 + (NumLi % 2) * 2 + 2;
703     * where NumLi = Number of Length Indicators to be sent
704    */
705    U8 hdr[((KW_MAX_DL_LI >> 1) * 3) + ((KW_MAX_DL_LI & 0x01) << 1) + 2];
706    U32 idx = 0; /* To index to the hdr array */
707    
708    /* Note: idx is not checked against crossing the hdr array bound as 
709     * liCount will be < KW_MAX_DL_LI and as per the size calculated above; 
710     * idx cannot cross the array
711     */
712
713    TRC2(kwUmmCreatePdu) 
714
715
716    /* stats updated before for bytes sent before adding RLC headers */
717    kwUtlIncrementGenStsBytesAndPdusSent(&gCb->genSts, pdu);
718          
719    sn = rbCb->m.umDl.vtUs;
720    liCount = rbCb->m.umDl.numLi;
721    
722    if(liCount > KW_MAX_DL_LI)
723       liCount = KW_MAX_DL_LI;
724
725    /* if there are any LI's then set the first E bit */
726    if(liCount)
727    {
728       e = 1;
729    }
730    
731    if (rbCb->m.umDl.snLen == 1) 
732    {
733       hdr[idx++] = (fi << 6) | (e << 5) | sn;
734    }
735    else /* SN length is 2 */
736    {
737       /* SN length is 10 bits */
738       hdr[idx] = (fi << 3) | (e << 2) | (sn >> 8);
739       hdr[++idx] = sn & 0xff;
740       ++idx;
741    }
742
743    hdrSz = sizeof(hdr); 
744    for (count = 0;count < liCount;count++)
745    {
746       /* In each iteration we try and encode 2 LIs */
747       /* if this is the last LI then e should be 0 */
748       if(count == liCount - 1)
749       {
750          e = 0;
751       }
752       
753       /* ccpu00135170  Fixing KLOCK warning */  
754       if((idx + 1)>= hdrSz)
755       {
756               break;
757       }
758       /* odd LI, 1st , 3rd etc */
759       hdr[idx] = (e << 7) | (rbCb->m.umDl.li[count] >> 4);
760       hdr[++idx] = (rbCb->m.umDl.li[count] & 0xf) << 4;
761       
762       count++;
763       if(count == liCount - 1)
764       {
765          e = 0;
766       }
767       else if(count >= liCount)
768       {
769          break;
770       }
771       /* ccpu00135170  Fixing KLOCK warning */  
772       if((idx + 1)>= hdrSz)
773       {
774               break;
775       }
776       /* even one, 2nd , 4th etc LI's, count starts at 0 */
777       hdr[idx] |= ((e << 3) | (rbCb->m.umDl.li[count] >> 8));
778       hdr[++idx] = rbCb->m.umDl.li[count] & 0xff;
779       ++idx;
780    }
781
782    /* if odd number of L1s increment idx */
783    if(liCount & 0x1)
784    {
785       ++idx;
786    }
787
788    /* increment VT(US) */
789    rbCb->m.umDl.vtUs = (rbCb->m.umDl.vtUs + 1) & rbCb->m.umDl.modBitMask;
790
791    /* add the header to the beginning of the pdu */
792    SAddPreMsgMultInOrder(hdr, idx, pdu);
793
794    datReqPduInfo->mBuf[datReqPduInfo->numPdu++] = pdu;
795    RETVOID;
796 }
797
798 /**
799  * @brief  Handler to estimate the header size of the RLC SDUs 
800  *         present in the SDU queue.
801  *       
802  * @details
803  *     This function is used to update the estimated header size variable in RB.
804  *     This function is called when a SDU is queued and when a PDU is formed and
805  *     sent to the lower layer.
806  *
807  * @param[in] umDl  UM mode downlink control block
808  *
809  * @return  Void
810 */ 
811 #ifdef ANSI
812 PRIVATE Void kwUmmEstHdrSz
813 (
814 KwUmDl *umDl          
815 )
816 #else
817 PRIVATE Void kwUmmEstHdrSz(umDl)
818 KwUmDl *umDl;          
819 #endif
820 {
821    /* The header size is estimated as :
822           If sdu count = 0 then 0
823           else sdu count * 2 + 1; the 1 is added for the FI and SN byte; 
824           2 for one LI and E
825     */   
826    umDl->estHdrSz = (umDl->sduQ.count)?((umDl->sduQ.count << 1) + 1) : 0;
827    
828    RETVOID;
829 }
830
831 /**
832  * @brief   Handler to discard a SDU.
833  *       
834  * @details
835  *     This function is used to discard a SDU after receiving
836  *     the Discard Request from the upper layer.The SDU is discarded if 
837  *     it is present and is not mapped to any PDU yet. 
838  *     The discards coming from the upper layer would be coming in 
839  *     sequence according to the sduId, so we should find the sduId at the 
840  *     head of the sduQ. Discards if there is a match else does nothing.
841  *
842  * @param[in] rbCb   RB control block 
843  * @param[in] sduId  SDU ID of the SDU to be discarded
844  *
845  * @return  Void
846 */
847 #ifdef ANSI
848 PUBLIC Void kwUmmDiscSdu
849 (
850 KwCb       *gCb,
851 KwDlRbCb   *rbCb,                
852 U32        sduId                
853 )
854 #else
855 PUBLIC Void kwUmmDiscSdu(gCb,rbCb,sduId)
856 KwCb       *gCb;
857 KwDlRbCb   *rbCb;                
858 U32        sduId;                
859 #endif
860 {
861    CmLList *tmpNode;  /* Temporary Node in SDU queue */
862    
863    TRC2(kwUmmDiscSdu)
864
865   
866    CM_LLIST_FIRST_NODE(&rbCb->m.umDl.sduQ,tmpNode);
867
868    if (tmpNode)
869    {
870       KwSdu *sdu = (KwSdu *)tmpNode->node;
871       
872       if (sdu->mode.um.sduId == sduId && sdu->mode.um.isSegmented == FALSE)
873       {
874 /* kw005.201 added support for L2 Measurement */
875          KW_RMV_SDU(gCb,&rbCb->m.umDl.sduQ,sdu);
876          gCb->genSts.numSduDisc++;         
877       }
878    }
879
880    RETVOID;
881 }
882
883 /*
884  *
885  * @brief
886  *    function to free/release the UnAcknowledged mode RBCB buffers
887  *
888  * @details
889  *    This primitive Frees the Unacknowldged Mode RbCb sdu queue
890  *
891  * @param [in]   gCb    - RLC instance control block
892  * @param [in]   rbCb   - RB Control Block
893  *
894  * @return Void
895  */
896 #ifdef ANSI
897 PUBLIC Void kwUmmFreeDlRbCb
898 (
899 KwCb       *gCb,
900 KwDlRbCb   *rbCb
901 )
902 #else
903 PUBLIC Void kwUmmFreeDlRbCb(gCb,rbCb)
904 KwCb       *gCb;
905 KwDlRbCb   *rbCb;
906 #endif
907 {
908    TRC2(kwUmmFreeDlRbCb)
909
910
911    /* cat the SDU queue to the to be freed list */
912    cmLListCatLList(&(gCb->u.dlCb->toBeFreed.sduLst),&(rbCb->m.umDl.sduQ));
913    kwUtlRaiseDlCleanupEvent(gCb);
914
915    RETVOID;
916 } /* kwUmmFreeDlRbCb */
917
918 /********************************************************************30**
919          End of file
920 **********************************************************************/