8c35e73691a6c8618692b63ade10baefc3047eeb
[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                   --rlcUmmQSdu
29                   --rlcUmmProcessSdus
30                   --rlcUmmProcessPdus
31                   --rlcUmmReAssembleSdus
32                   --kwUmmReEstablish 
33
34      File:     kw_umm_dl.c
35
36 **********************************************************************/
37 /** 
38  * @file kw_umm_dl.c
39  * @brief RLC Unacknowledged Mode downlink 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_udx.h"
54 #include "kw_dl.h"
55
56
57 /* header/extern include files (.x) */
58
59 #include "ckw.x"                /* RRC layer */
60 #include "kwu.x"                /* RLC service user */
61 #include "lkw.x"                /* LM Interface */
62 #include "rgu.x"                /* MAC later */
63
64 #include "kw.x"                 /* RLC layer */
65 #include "kw_udx.x"
66 #include "kw_dl.x"
67
68 #define RLC_MODULE (RLC_DBGMASK_UM | RLC_DBGMASK_DL)
69
70 /* variables for logging :declared in BRDCM cl */
71 #ifndef TENB_ACC
72 uint32_t dldrops_kwu_um;
73 uint32_t dlpkt_um;
74 uint32_t buffer_occ;
75 uint32_t dlrate_kwu;
76 #endif
77
78 static void rlcUmmEstHdrSz ARGS ((RlcUmDl *umUl));
79
80 static Void rlcUmmCreatePdu ARGS ((RlcCb *gCb,
81                                   RlcDlRbCb *rbCb, 
82                                   Buffer *pdu,
83                                   uint8_t fi,
84                                   KwPduInfo *datReqPduInfo));
85
86 /** @addtogroup ummode */
87 /*@{*/
88
89 /**
90  * @brief  Handler to queue a SDU in the SDU queue, update BO and report 
91  *         it to the lower layer.
92  *       
93  * @details
94  *    This function is used to queue the received SDU in the 
95  *    SDU queue maintained in the radio bearer control block.
96  *    After queuing the SDU, BO is updated and is reported
97  *    to the lower layer. 
98  *
99  * @param[in] gCb      RLC Instance control block
100  * @param[in] rbCb     RB control block 
101  * @param[in] datReq   Ptr to the datReq sent from PDCP
102  * @param[in] mBuf     Sdu data
103  *
104  * @return  Void
105 */  
106 void rlcUmmQSdu(RlcCb *gCb, RlcDlRbCb *rbCb, KwuDatReqInfo *datReq, Buffer *mBuf)
107 {
108    MsgLen   len;    /* SDU buffer length */
109    RlcSdu    *sdu;   /* SDU */
110
111    RLC_UPD_L2_DL_TOT_SDU_STS(gCb,rbCb);
112
113    RLC_ALLOC_WC(gCb, sdu, (Size)sizeof(RlcSdu));
114 #if (ERRCLASS & ERRCLS_ADD_RES)
115    if ( sdu == NULLP )
116    {
117       DU_LOG("\nERROR  -->  RLC DL : Memory allocation failed in rlcUmmQSdu for UEID:%d CELLID:%d",\
118                rbCb->rlcId.ueId,
119                rbCb->rlcId.cellId);
120       ODU_PUT_MSG_BUF(mBuf);
121       return;
122    }
123 #endif /* ERRCLASS & ERRCLS_ADD_RES */
124
125 /* Discard new changes starts */
126    rlcUtlGetCurrTime(&sdu->arrTime);
127 /* Discard new changes ends */
128    ODU_GET_MSG_LEN(mBuf,&len);
129
130    sdu->mBuf = mBuf;
131    sdu->sduSz = len;
132    sdu->actSz = len;
133    sdu->mode.um.sduId = datReq->sduId;
134    sdu->mode.um.isSegmented = FALSE;
135 #ifndef RGL_SPECIFIC_CHANGES
136 #ifndef TENB_ACC
137 #ifndef LTE_PAL_ENB
138    {
139          dlrate_kwu += len;
140    }
141 #endif   
142 #endif
143 #endif
144    rbCb->m.umDl.bo += len;
145    
146    cmLListAdd2Tail(&(rbCb->m.umDl.sduQ), &sdu->lstEnt);
147    sdu->lstEnt.node = (PTR)sdu;
148    
149    rlcUmmEstHdrSz(&rbCb->m.umDl);
150
151    if(!rlcDlUtlIsReestInProgress(rbCb))
152    {
153       rlcUtlSendDedLcBoStatus(gCb,rbCb,rbCb->m.umDl.bo,rbCb->m.umDl.estHdrSz,FALSE,0);
154    }
155    
156    /* kw005.201 added support for L2 Measurement */
157 #ifdef LTE_L2_MEAS_RLC
158    /* Update numActUe if it is not active */
159    if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_ACT_UE) &&
160       (rbCb->ueCb->numActRb[rbCb->qci]++ == 0))
161    {
162      rlcCb.rlcL2Cb.numActUe[rbCb->qci]++;
163    }
164 #endif
165
166    return;    
167 }
168
169
170 /**
171  * @brief   Handler to form PDU(s) and update the BO. 
172  *       
173  * @details
174  *     -# This function forms pdu(s) from the SDU(s) in the
175  *        SDU queue and returns them.
176  *     -# This function also updates the BO along with the 
177  *        along with the estimated Header size.
178  *
179  * @param[in]  rbCb     RB control block 
180  * @param[out] pduInfo  Pdu Info to be filled and the PDU size to be 
181  *                      formed and the updated BO
182  * @param[in]  pduSz    The size for which PDUs have to constructed
183  *
184  * @return  S16
185  *    -# ROK       In case of success
186  *    -# RFAILED   If allocation of Sdu fails
187 */  
188 void rlcUmmProcessSdus(RlcCb *gCb, RlcDlRbCb *rbCb, RlcDatReq *datReq)
189 {
190    CmLList     *firstNode;   /* First Node in SDU queue */
191    uint8_t      fi=0;           /* Framing Info */
192    Buffer      *pdu;         /* Buffer for holding the formed PDU */
193    KwPduInfo   *pduInfo;     /* PDU Info pointer */
194    int16_t     pduSz;        /* PDU Size to be constructed */
195    
196    /* kw005.201 added support for L2 Measurement */
197 #ifdef LTE_L2_MEAS
198    RlcContSduLst         contSduLst;  /*Contained sduLst */
199    int32_t               dataVol    = rbCb->m.umDl.bo;
200    uint32_t*             totMacGrant= &(datReq->totMacGrant);
201    RlcL2MeasDlIpTh       *dlIpThPut = &rbCb->l2MeasIpThruput.dlIpTh;
202    uint8_t               *sduIdx    = &dlIpThPut->lastSduIdx;
203    bool                  newIdx = FALSE;
204    int32_t               oldBo;
205    RlclchInfo            lchInfo = {0};
206    uint32_t              segSduCnt = 0;
207 #endif
208    Ticks                curTime  = 0;
209    int16_t              timeDiff = 0;
210    RlcSdu                *sdu;
211
212    pdu = NULLP;
213
214    pduInfo = &(datReq->pduInfo);
215    pduSz = datReq->pduSz;
216    
217 #ifdef LTE_L2_MEAS   
218    contSduLst.numSdus = 0;
219    contSduLst.lcId = rbCb->lch.lChId;
220    oldBo = rbCb->m.umDl.bo; 
221    lchInfo.lcId = rbCb->lch.lChId;
222    lchInfo.numSdus = 0;
223 #endif
224
225    /* Discard new changes starts */
226    rlcUtlGetCurrTime(&curTime);
227
228    /* ccpu00143043 */
229    while ((pduSz > 0) && (rbCb->m.umDl.sduQ.count > 0) &&
230            (rbCb->m.umDl.numLi < RLC_MAX_DL_LI) && (pduInfo->numPdu < RLC_MAX_PDU))
231    {
232       CM_LLIST_FIRST_NODE(&rbCb->m.umDl.sduQ,firstNode);
233       sdu = (RlcSdu *)(firstNode->node);
234
235       if ((sdu->mode.um.isSegmented == FALSE) && (rbCb->discTmrInt > 0) && 
236             (rbCb->rlcId.rbType == CM_LTE_DRB))
237       {
238          timeDiff = RLC_TIME_DIFF(curTime,sdu->arrTime); 
239
240          if (timeDiff >= rbCb->discTmrInt)
241          {
242 #ifdef LTE_L2_MEAS 
243             RLC_UPD_L2_DL_DISC_SDU_STS(gCb, rbCb);
244 #endif
245             rbCb->m.umDl.bo -= sdu->sduSz;
246             RLC_RMV_SDU(gCb,&rbCb->m.umDl.sduQ,sdu);
247             continue;
248          }
249       }
250       /* When forming a new PDU, pdu == NULLP
251            -# Eliminate MAC header size for each pdu 
252            -# Initialize the li array to 0 
253            -# Substract the fixed header length based on SN length
254       */
255 #ifdef LTE_L2_MEAS
256       newIdx = FALSE;
257 #endif
258       if (!pdu)
259       {
260          RLC_RMV_MAC_HDR_SZ(pduSz);
261
262          /* account for the RLC header size */
263          pduSz -= rbCb->m.umDl.snLen;
264
265          /* kw005.201 fixing pduSz <= 0 problem, ccpu00119417 */
266          if(pduSz <= 0)
267          {
268             break;
269          }         
270          
271          rbCb->m.umDl.numLi = 0;
272          if (sdu->mode.um.isSegmented == TRUE)
273          {
274             fi = 2;
275          }
276          else
277          {
278             fi = 0;
279          }
280       }
281
282       rlcUtlCalcLiForSdu(gCb,rbCb->m.umDl.numLi,sdu->sduSz,&pduSz);
283      
284       /* Exact fit scenario :
285          If the SDU size matches with the PDU size
286            -# Allocate memory equal to PDU size;
287            -# update BO
288            -# Remove SDu from queue
289            -# Append to already existing PDU portion if present .
290            -# Add Header and create complete PDU and place it in
291               pduInfo and return
292       */ 
293       if (sdu->sduSz == pduSz)
294       {
295          if (!pdu)
296          {
297             pdu = sdu->mBuf;
298             sdu->mBuf = NULLP;
299          }
300          else
301          {
302             SCatMsg(pdu, sdu->mBuf, M1M2);    
303          }
304          
305          rbCb->m.umDl.bo -= pduSz;
306          pduSz = 0;
307
308 #ifdef LTE_L2_MEAS
309         if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb))
310         {
311            if(sdu->mode.um.isSegmented)
312            {
313               *sduIdx    = dlIpThPut->lastSduIdx;
314            }
315            else
316            {
317               RLC_GETSDUIDX(*sduIdx);
318               newIdx = TRUE;
319            }
320            rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
321            rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz, 
322                  sdu->mode.um.sduId, newIdx);
323            /* ccpu00143043 */
324            if ( lchInfo.numSdus < RLC_L2MEAS_SDUIDX)
325            {
326               lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime; 
327               lchInfo.sduInfo[lchInfo.numSdus].isRetxPdu = FALSE;
328               lchInfo.numSdus++;
329            }
330         }
331 #endif
332 /* kw005.201 added support for L2 Measurement */
333 #ifdef LTE_L2_MEAS_RLC
334          rlcUtlUpdSduSnMap(rbCb, sdu, datReq, TRUE);
335          if((rbCb->rbL2Cb.measOn & LKW_L2MEAS_DL_DELAY) ||
336                  (rbCb->rbL2Cb.measOn & LKW_L2MEAS_UU_LOSS))
337           {
338              /* ccpu00143043 */
339              if ( lchInfo.numSdus < RLC_L2MEAS_SDUIDX)
340              {
341                 lchInfo.arvlTime[lchInfo.numSdus] = sdu->arrTime; 
342                 lchInfo.numSdus++;
343              }
344           }
345 #endif /*  LTE_L2_MEAS */
346          RLC_RMV_SDU(gCb,&(rbCb->m.umDl.sduQ),sdu); /* kw003.201 */
347          rlcUtlIncrementKwuStsSduTx(gCb->u.dlCb->rlcKwuDlSap + rbCb->k1wuSapId);
348
349          rlcUmmCreatePdu(gCb,rbCb,pdu,fi,pduInfo);
350          pdu = NULLP;
351          
352       }
353       /* Concatenation scenario :
354          If SDU size is less than the requested PDU size
355            -# Allocate memory and copy SDU into it.
356            -# Update BO
357            -# Remove SDU from the Queue.
358            -# Append to already existing PDU portion if present .
359            -# If the SDU size is greater than 2047 or the number of i
360                  LIs reaches max, place it as a separate PDU in pduInfo and 
361                  set pdu to NULL
362               else 
363                  place the msglen in li array and continue with the next SDU.
364            -# If the number of PDUs is more than RLC_MAX_PDU, return from 
365               the function even if pduSize > 0.
366       */
367       else if (sdu->sduSz < pduSz)
368       {
369          if (!pdu)
370          {
371             pdu = sdu->mBuf;
372             sdu->mBuf = NULLP;
373          }
374          else
375          {
376             ODU_CAT_MSG(pdu, sdu->mBuf ,M1M2);
377          }
378          rbCb->m.umDl.bo -= sdu->sduSz;
379
380          pduSz -= sdu->sduSz;
381 /* kw005.201 added support for L2 Measurement */
382 #ifdef LTE_L2_MEAS_RLC
383           rlcUtlUpdSduSnMap(rbCb, sdu, datReq, TRUE);
384 #endif /*  LTE_L2_MEAS */
385          if (sdu->sduSz < 2048 && rbCb->m.umDl.numLi < RLC_MAX_DL_LI)
386          {
387             rbCb->m.umDl.li[(rbCb->m.umDl.numLi)++] = sdu->sduSz;
388          }
389          else 
390          {
391             rlcUmmCreatePdu(gCb, rbCb, pdu, fi, pduInfo);
392             pdu = NULLP;
393
394             if ( pduInfo->numPdu == RLC_MAX_PDU)
395             {
396                 /* Could not transmit what MAC asked for because the number 
397                  * of PDUs to be transmitted has reached maximum. */
398                 DU_LOG("\nERROR  -->  RLC DL: rlcUmmProcessSdus: Maximum Pdu limit has been reached\
399                   UEID:%d CELLID:%d", rbCb->rlcId.ueId, rbCb->rlcId.cellId);
400                break;
401             }
402          }
403 #ifdef LTE_L2_MEAS
404         if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) )
405         {
406            if(sdu->mode.um.isSegmented)
407            {
408               *sduIdx    = dlIpThPut->lastSduIdx;
409            }
410            else
411            {
412               RLC_GETSDUIDX(*sduIdx);
413               newIdx = TRUE;
414            }
415            rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
416            rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz, 
417                  sdu->mode.um.sduId, newIdx);
418            /* ccpu00143043 */
419            if ( lchInfo.numSdus < RLC_L2MEAS_SDUIDX)
420            {
421               lchInfo.sduInfo[lchInfo.numSdus].arvlTime = sdu->arrTime; 
422               lchInfo.sduInfo[lchInfo.numSdus].isRetxPdu = FALSE;
423               lchInfo.numSdus++;
424            }
425         }
426 #endif
427          RLC_RMV_SDU(gCb,&(rbCb->m.umDl.sduQ),sdu);
428          /* kw005.201 ccpu00117318, updating the statistics */
429          rlcUtlIncrementKwuStsSduTx(gCb->u.dlCb->rlcKwuDlSap + rbCb->k1wuSapId);         
430       }
431       /* Segmentation scenario :
432          If size of SDU is greater than PDU size 
433            -# Allocate memory and Segment the Sdu.
434            -# Update BO
435            -# Append to already existing PDU if any.
436            -# Set the second bit of the framing info.
437            -# Create the complete PDU and place in pduInfo.
438       */ 
439       else 
440       {
441          Buffer *remSdu;
442        
443          ODU_SEGMENT_MSG(sdu->mBuf,pduSz,&remSdu);
444         
445 #ifdef LTE_L2_MEAS
446         if(RLC_MEAS_IS_DL_IP_MEAS_ON_FOR_RB(gCb, rbCb))
447         {
448            if(sdu->mode.um.isSegmented)
449            {
450               *sduIdx    = dlIpThPut->lastSduIdx;
451            }
452            else
453            {
454               RLC_GETSDUIDX(*sduIdx);
455               newIdx = TRUE;
456            }
457            rlcUtlUpdateContainedSduLst(*sduIdx, &contSduLst);
458            rlcUtlUpdateOutStandingSduLst(dlIpThPut, *sduIdx, sdu->actSz, 
459                  sdu->mode.um.sduId, newIdx);
460         }
461         if(RLC_MEAS_IS_DL_UU_LOSS_MEAS_ON_FOR_RB(gCb,rbCb))
462         {
463            if(sdu->actSz == sdu->sduSz)
464            {
465               segSduCnt++;
466            }
467         }
468 #endif
469          if (!pdu)
470          {
471             pdu = sdu->mBuf;
472          }
473          else 
474          {
475             ODU_CAT_MSG(pdu, sdu->mBuf, M1M2);
476             ODU_PUT_MSG_BUF(sdu->mBuf);
477          }
478
479          sdu->sduSz -= pduSz;
480          rbCb->m.umDl.bo -= pduSz;
481          sdu->mode.um.isSegmented = TRUE;
482          sdu->mBuf = remSdu;
483          pduSz = 0;
484          
485          fi |= 1;
486 /* kw005.201 added support for L2 Measurement */
487 #ifdef LTE_L2_MEAS_RLC
488          rlcUtlUpdSduSnMap(rbCb, sdu, datReq, FALSE);
489 #endif /*  LTE_L2_MEAS */
490
491          rlcUmmCreatePdu(gCb,rbCb,pdu,fi,pduInfo);
492          pdu = NULLP;
493       }
494 /* kw005.201 added support for L2 Measurement */
495    }
496 #ifdef LTE_L2_MEAS_RLC
497    if((rbCb->rbL2Cb.measOn) && 
498       (rbCb->m.umDl.sduQ.count == 0) && 
499       (dataWasPrsnt))
500    {
501       if(--(rbCb->ueCb->numActRb[rbCb->qci]) == 0)
502       {
503          rlcCb.rlcL2Cb.numActUe[rbCb->qci]--;
504       }
505    }
506 #endif /* LTE_L2_MEAS */
507 #ifdef LTE_L2_MEAS
508    rlcUtlUpdateBurstSdus(gCb, rbCb, &contSduLst, dataVol, *totMacGrant);
509    /* Need to check into optimizing this code : TODO */
510    if(RLC_MEAS_IS_DL_ANY_MEAS_ON_FOR_RB(gCb,rbCb) && (lchInfo.numSdus != 0))
511    {
512       RlcL2MeasTb *l2MeasTb = rlcUtlGetCurMeasTb(gCb, rbCb);
513       /* ccpu00143043 */
514       /* Fix Klock warning */
515       if ((lchInfo.numSdus != 0) && (l2MeasTb != NULLP) &&
516           (l2MeasTb->numLchInfo < RLC_MAX_ACTV_DRB))
517       {   
518          memcpy( &l2MeasTb->lchInfo[l2MeasTb->numLchInfo],  &lchInfo, sizeof(RlclchInfo));
519          l2MeasTb->numLchInfo++;
520       }
521       l2MeasTb->txSegSduCnt += segSduCnt;
522    }
523    *totMacGrant -= (oldBo - rbCb->m.umDl.bo);
524 #endif 
525
526    /* If we have a situation wherein the size requested is greater than the total size of SDUs
527       and a pdu buffer which is not null, this if loop helps to send 
528       a non null PDU to the lower layer. 
529    */
530    if (pduSz > 0 && pdu)
531    {
532       if (pduInfo->numPdu != RLC_MAX_PDU)
533       {
534          rbCb->m.umDl.numLi--;         
535          rlcUmmCreatePdu(gCb,rbCb,pdu,fi,pduInfo);   
536          pdu = NULLP;
537       }
538       else
539       {
540          ODU_PUT_MSG_BUF(pdu);
541       }
542    }
543    
544    rlcUmmEstHdrSz(&rbCb->m.umDl);
545    datReq->boRep.bo = rbCb->m.umDl.bo;
546    datReq->boRep.estHdrSz = rbCb->m.umDl.estHdrSz;
547    datReq->boRep.staPduPrsnt = FALSE;
548    if (rbCb->m.umDl.sduQ.count > 0)
549    {
550       datReq->boRep.oldestSduArrTime = 
551         ((RlcSdu *)(rbCb->m.umDl.sduQ.first->node))->arrTime;
552    }
553    return; 
554 }
555
556 /**
557  * @brief   Handler to process the re-establishment request received from i
558  *          the upper layer. 
559  *       
560  * @details
561  *     This function does the following functions : 
562  *         Remove all the SDUs in the SDU queue.
563  *
564  * @param[in] gCb        RLC Instance control block
565  * @param[in] rlcID      Identity of the RLC entity for which 
566  *                       re-establishment is to be done
567  * @param[in] sendReEst  Whether to send re-establishment complete 
568  *                       indication to  upper layer or not
569  * @param[in] rbCb       RB control block for which re-establishment 
570  *                       is to be done
571  *
572  * @return  Void
573 */ 
574 Void rlcDlUmmReEstablish(RlcCb *gCb,CmLteRlcId rlcId,Bool sendReEst,RlcDlRbCb *rbCb)
575 {
576    /* The re-establishment indication is sent from the UL only */
577
578    rlcUmmFreeDlRbCb(gCb, rbCb);
579
580    rbCb->m.umDl.vtUs = 0;
581
582    /* this would have been set when re-establishment was triggered
583       for SRB 1 */
584    rlcDlUtlResetReestInProgress(rbCb);
585    
586    return;
587 }
588 /**
589  * @brief   Handler to create the header and complete a PDU.
590  *       
591  * @details
592  *     This function is used to create the header of a PDU and concatenate  it
593  *     with the data part of the PDU.
594  *     Also updates the statistics
595  *     Sets the passed pdu to NULLP
596  *
597  * @param[in]     gCb            RLC instance control block
598  * @param[in,out] rbCb           RB control block 
599  * @param[in]     pdu            PDU  
600  * @param[in]     fi             Framing Info field
601  * @param[out]    datReqPduInfo  Holder in which to copy the created PDU pointer
602  *
603  * @return  Void
604 */ 
605 static void rlcUmmCreatePdu(RlcCb *gCb, RlcDlRbCb *rbCb, Buffer *pdu, uint8_t fi, KwPduInfo *datReqPduInfo)
606 {
607    RlcSn     sn;        /*  Sequence Number */
608    uint32_t  liCount;   /*  LI count */
609    uint8_t   e = 0;     /* Extension Bit */
610    uint32_t  count;     /* Loop Counter */
611    uint32_t  hdrSz;
612
613    /* create a big array to store the header, assuming 3 bytes per 2 L1s 
614     * (2 bytes if only a single LI) and 2 bytes for the 
615     *  FI and SN
616     * size of header = ( NumLi /2 ) * 3 + (NumLi % 2) * 2 + 2;
617     * where NumLi = Number of Length Indicators to be sent
618    */
619    uint8_t hdr[((RLC_MAX_DL_LI >> 1) * 3) + ((RLC_MAX_DL_LI & 0x01) << 1) + 2];
620    uint32_t idx = 0; /* To index to the hdr array */
621    
622    /* Note: idx is not checked against crossing the hdr array bound as 
623     * liCount will be < RLC_MAX_DL_LI and as per the size calculated above; 
624     * idx cannot cross the array
625     */
626
627    /* stats updated before for bytes sent before adding RLC headers */
628    rlcUtlIncrementGenStsBytesAndPdusSent(&gCb->genSts, pdu);
629          
630    sn = rbCb->m.umDl.vtUs;
631    liCount = rbCb->m.umDl.numLi;
632    
633    if(liCount > RLC_MAX_DL_LI)
634       liCount = RLC_MAX_DL_LI;
635
636    /* if there are any LI's then set the first E bit */
637    if(liCount)
638    {
639       e = 1;
640    }
641    
642    if (rbCb->m.umDl.snLen == 1) 
643    {
644       hdr[idx++] = (fi << 6) | (e << 5) | sn;
645    }
646    else /* SN length is 2 */
647    {
648       /* SN length is 10 bits */
649       hdr[idx] = (fi << 3) | (e << 2) | (sn >> 8);
650       hdr[++idx] = sn & 0xff;
651       ++idx;
652    }
653
654    hdrSz = sizeof(hdr); 
655    for (count = 0;count < liCount;count++)
656    {
657       /* In each iteration we try and encode 2 LIs */
658       /* if this is the last LI then e should be 0 */
659       if(count == liCount - 1)
660       {
661          e = 0;
662       }
663       
664       /* ccpu00135170  Fixing KLOCK warning */  
665       if((idx + 1)>= hdrSz)
666       {
667               break;
668       }
669       /* odd LI, 1st , 3rd etc */
670       hdr[idx] = (e << 7) | (rbCb->m.umDl.li[count] >> 4);
671       hdr[++idx] = (rbCb->m.umDl.li[count] & 0xf) << 4;
672       
673       count++;
674       if(count == liCount - 1)
675       {
676          e = 0;
677       }
678       else if(count >= liCount)
679       {
680          break;
681       }
682       /* ccpu00135170  Fixing KLOCK warning */  
683       if((idx + 1)>= hdrSz)
684       {
685               break;
686       }
687       /* even one, 2nd , 4th etc LI's, count starts at 0 */
688       hdr[idx] |= ((e << 3) | (rbCb->m.umDl.li[count] >> 8));
689       hdr[++idx] = rbCb->m.umDl.li[count] & 0xff;
690       ++idx;
691    }
692
693    /* if odd number of L1s increment idx */
694    if(liCount & 0x1)
695    {
696       ++idx;
697    }
698
699    /* increment VT(US) */
700    rbCb->m.umDl.vtUs = (rbCb->m.umDl.vtUs + 1) & rbCb->m.umDl.modBitMask;
701
702    /* add the header to the beginning of the pdu */
703    ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx, pdu);
704
705    datReqPduInfo->mBuf[datReqPduInfo->numPdu++] = pdu;
706    return;
707 }
708
709 /**
710  * @brief  Handler to estimate the header size of the RLC SDUs 
711  *         present in the SDU queue.
712  *       
713  * @details
714  *     This function is used to update the estimated header size variable in RB.
715  *     This function is called when a SDU is queued and when a PDU is formed and
716  *     sent to the lower layer.
717  *
718  * @param[in] umDl  UM mode downlink control block
719  *
720  * @return  Void
721 */ 
722 static void rlcUmmEstHdrSz(RlcUmDl *umDl)
723 {
724    /* The header size is estimated as :
725           If sdu count = 0 then 0
726           else sdu count * 2 + 1; the 1 is added for the FI and SN byte; 
727           2 for one LI and E
728     */   
729    umDl->estHdrSz = (umDl->sduQ.count)?((umDl->sduQ.count << 1) + 1) : 0;
730    
731    return;
732 }
733
734 /**
735  * @brief   Handler to discard a SDU.
736  *       
737  * @details
738  *     This function is used to discard a SDU after receiving
739  *     the Discard Request from the upper layer.The SDU is discarded if 
740  *     it is present and is not mapped to any PDU yet. 
741  *     The discards coming from the upper layer would be coming in 
742  *     sequence according to the sduId, so we should find the sduId at the 
743  *     head of the sduQ. Discards if there is a match else does nothing.
744  *
745  * @param[in] rbCb   RB control block 
746  * @param[in] sduId  SDU ID of the SDU to be discarded
747  *
748  * @return  Void
749 */
750 Void rlcUmmDiscSdu(RlcCb *gCb,RlcDlRbCb *rbCb,uint32_t sduId)
751 {
752    CmLList *tmpNode;  /* Temporary Node in SDU queue */
753    CM_LLIST_FIRST_NODE(&rbCb->m.umDl.sduQ,tmpNode);
754
755    if (tmpNode)
756    {
757       RlcSdu *sdu = (RlcSdu *)tmpNode->node;
758       
759       if (sdu->mode.um.sduId == sduId && sdu->mode.um.isSegmented == FALSE)
760       {
761 /* kw005.201 added support for L2 Measurement */
762          RLC_RMV_SDU(gCb,&rbCb->m.umDl.sduQ,sdu);
763          gCb->genSts.numSduDisc++;         
764       }
765    }
766
767    return;
768 }
769
770 /*
771  *
772  * @brief
773  *    function to free/release the UnAcknowledged mode RBCB buffers
774  *
775  * @details
776  *    This primitive Frees the Unacknowldged Mode RbCb sdu queue
777  *
778  * @param [in]   gCb    - RLC instance control block
779  * @param [in]   rbCb   - RB Control Block
780  *
781  * @return Void
782  */
783 Void rlcUmmFreeDlRbCb(RlcCb *gCb,RlcDlRbCb *rbCb)
784 {
785
786    /* cat the SDU queue to the to be freed list */
787    cmLListCatLList(&(gCb->u.dlCb->toBeFreed.sduLst),&(rbCb->m.umDl.sduQ));
788    rlcUtlRaiseDlCleanupEvent(gCb);
789
790    return;
791 } /* rlcUmmFreeDlRbCb */
792
793 /********************************************************************30**
794          End of file
795 **********************************************************************/