RLC BO, BO response and DL Data handling. [Issue-ID: ODUHIGH-181]
[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 extern U32 dldrops_kwu_um;
73 extern U32 dlpkt_um;
74 extern U32 buffer_occ;
75 extern U32 dlrate_kwu;
76 #endif
77
78 PRIVATE void rlcUmmEstHdrSz ARGS ((RlcUmDl *umUl));
79
80 PRIVATE Void rlcUmmCreatePdu ARGS ((RlcCb *gCb,
81                                   RlcDlRbCb *rbCb, 
82                                   Buffer *pdu,
83                                   U8 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("\nRLC : 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("\nRLC: 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             RLC_FREE_BUF_WC(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          cmMemcpy((U8 *) &l2MeasTb->lchInfo[l2MeasTb->numLchInfo], (U8 *) &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          RLC_FREE_BUF_WC(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 #ifdef ANSI
575 Void rlcDlUmmReEstablish
576 (
577 RlcCb         *gCb,
578 CmLteRlcId   rlcId,
579 Bool         sendReEst,
580 RlcDlRbCb     *rbCb
581 )
582 #else
583 Void rlcDlUmmReEstablish(gCb, rlcId, rbCb)
584 RlcCb         *gCb;
585 CmLteRlcId   rlcId;
586 Bool         sendReEst;
587 RlcDlRbCb       *rbCb;
588 #endif
589 {
590    /* The re-establishment indication is sent from the UL only */
591    TRC2(rlcDlUmmReEstablish)
592
593
594    rlcUmmFreeDlRbCb(gCb, rbCb);
595
596    rbCb->m.umDl.vtUs = 0;
597
598    /* this would have been set when re-establishment was triggered
599       for SRB 1 */
600    rlcDlUtlResetReestInProgress(rbCb);
601    
602    RETVOID;
603 }
604 /**
605  * @brief   Handler to create the header and complete a PDU.
606  *       
607  * @details
608  *     This function is used to create the header of a PDU and concatenate  it
609  *     with the data part of the PDU.
610  *     Also updates the statistics
611  *     Sets the passed pdu to NULLP
612  *
613  * @param[in]     gCb            RLC instance control block
614  * @param[in,out] rbCb           RB control block 
615  * @param[in]     pdu            PDU  
616  * @param[in]     fi             Framing Info field
617  * @param[out]    datReqPduInfo  Holder in which to copy the created PDU pointer
618  *
619  * @return  Void
620 */ 
621 void rlcUmmCreatePdu(RlcCb *gCb, RlcDlRbCb *rbCb, Buffer *pdu, uint8_t fi, KwPduInfo *datReqPduInfo)
622 {
623    RlcSn     sn;        /*  Sequence Number */
624    uint32_t  liCount;   /*  LI count */
625    uint8_t   e = 0;     /* Extension Bit */
626    uint32_t  count;     /* Loop Counter */
627    uint32_t  hdrSz;
628
629    /* create a big array to store the header, assuming 3 bytes per 2 L1s 
630     * (2 bytes if only a single LI) and 2 bytes for the 
631     *  FI and SN
632     * size of header = ( NumLi /2 ) * 3 + (NumLi % 2) * 2 + 2;
633     * where NumLi = Number of Length Indicators to be sent
634    */
635    uint8_t hdr[((RLC_MAX_DL_LI >> 1) * 3) + ((RLC_MAX_DL_LI & 0x01) << 1) + 2];
636    uint32_t idx = 0; /* To index to the hdr array */
637    
638    /* Note: idx is not checked against crossing the hdr array bound as 
639     * liCount will be < RLC_MAX_DL_LI and as per the size calculated above; 
640     * idx cannot cross the array
641     */
642
643    /* stats updated before for bytes sent before adding RLC headers */
644    rlcUtlIncrementGenStsBytesAndPdusSent(&gCb->genSts, pdu);
645          
646    sn = rbCb->m.umDl.vtUs;
647    liCount = rbCb->m.umDl.numLi;
648    
649    if(liCount > RLC_MAX_DL_LI)
650       liCount = RLC_MAX_DL_LI;
651
652    /* if there are any LI's then set the first E bit */
653    if(liCount)
654    {
655       e = 1;
656    }
657    
658    if (rbCb->m.umDl.snLen == 1) 
659    {
660       hdr[idx++] = (fi << 6) | (e << 5) | sn;
661    }
662    else /* SN length is 2 */
663    {
664       /* SN length is 10 bits */
665       hdr[idx] = (fi << 3) | (e << 2) | (sn >> 8);
666       hdr[++idx] = sn & 0xff;
667       ++idx;
668    }
669
670    hdrSz = sizeof(hdr); 
671    for (count = 0;count < liCount;count++)
672    {
673       /* In each iteration we try and encode 2 LIs */
674       /* if this is the last LI then e should be 0 */
675       if(count == liCount - 1)
676       {
677          e = 0;
678       }
679       
680       /* ccpu00135170  Fixing KLOCK warning */  
681       if((idx + 1)>= hdrSz)
682       {
683               break;
684       }
685       /* odd LI, 1st , 3rd etc */
686       hdr[idx] = (e << 7) | (rbCb->m.umDl.li[count] >> 4);
687       hdr[++idx] = (rbCb->m.umDl.li[count] & 0xf) << 4;
688       
689       count++;
690       if(count == liCount - 1)
691       {
692          e = 0;
693       }
694       else if(count >= liCount)
695       {
696          break;
697       }
698       /* ccpu00135170  Fixing KLOCK warning */  
699       if((idx + 1)>= hdrSz)
700       {
701               break;
702       }
703       /* even one, 2nd , 4th etc LI's, count starts at 0 */
704       hdr[idx] |= ((e << 3) | (rbCb->m.umDl.li[count] >> 8));
705       hdr[++idx] = rbCb->m.umDl.li[count] & 0xff;
706       ++idx;
707    }
708
709    /* if odd number of L1s increment idx */
710    if(liCount & 0x1)
711    {
712       ++idx;
713    }
714
715    /* increment VT(US) */
716    rbCb->m.umDl.vtUs = (rbCb->m.umDl.vtUs + 1) & rbCb->m.umDl.modBitMask;
717
718    /* add the header to the beginning of the pdu */
719    ODU_ADD_PRE_MSG_MULT_IN_ORDER(hdr, idx, pdu);
720
721    datReqPduInfo->mBuf[datReqPduInfo->numPdu++] = pdu;
722    return;
723 }
724
725 /**
726  * @brief  Handler to estimate the header size of the RLC SDUs 
727  *         present in the SDU queue.
728  *       
729  * @details
730  *     This function is used to update the estimated header size variable in RB.
731  *     This function is called when a SDU is queued and when a PDU is formed and
732  *     sent to the lower layer.
733  *
734  * @param[in] umDl  UM mode downlink control block
735  *
736  * @return  Void
737 */ 
738 void rlcUmmEstHdrSz(RlcUmDl *umDl)
739 {
740    /* The header size is estimated as :
741           If sdu count = 0 then 0
742           else sdu count * 2 + 1; the 1 is added for the FI and SN byte; 
743           2 for one LI and E
744     */   
745    umDl->estHdrSz = (umDl->sduQ.count)?((umDl->sduQ.count << 1) + 1) : 0;
746    
747    return;
748 }
749
750 /**
751  * @brief   Handler to discard a SDU.
752  *       
753  * @details
754  *     This function is used to discard a SDU after receiving
755  *     the Discard Request from the upper layer.The SDU is discarded if 
756  *     it is present and is not mapped to any PDU yet. 
757  *     The discards coming from the upper layer would be coming in 
758  *     sequence according to the sduId, so we should find the sduId at the 
759  *     head of the sduQ. Discards if there is a match else does nothing.
760  *
761  * @param[in] rbCb   RB control block 
762  * @param[in] sduId  SDU ID of the SDU to be discarded
763  *
764  * @return  Void
765 */
766 #ifdef ANSI
767 Void rlcUmmDiscSdu
768 (
769 RlcCb       *gCb,
770 RlcDlRbCb   *rbCb,                
771 U32        sduId                
772 )
773 #else
774 Void rlcUmmDiscSdu(gCb,rbCb,sduId)
775 RlcCb       *gCb;
776 RlcDlRbCb   *rbCb;                
777 U32        sduId;                
778 #endif
779 {
780    CmLList *tmpNode;  /* Temporary Node in SDU queue */
781    
782    TRC2(rlcUmmDiscSdu)
783
784   
785    CM_LLIST_FIRST_NODE(&rbCb->m.umDl.sduQ,tmpNode);
786
787    if (tmpNode)
788    {
789       RlcSdu *sdu = (RlcSdu *)tmpNode->node;
790       
791       if (sdu->mode.um.sduId == sduId && sdu->mode.um.isSegmented == FALSE)
792       {
793 /* kw005.201 added support for L2 Measurement */
794          RLC_RMV_SDU(gCb,&rbCb->m.umDl.sduQ,sdu);
795          gCb->genSts.numSduDisc++;         
796       }
797    }
798
799    RETVOID;
800 }
801
802 /*
803  *
804  * @brief
805  *    function to free/release the UnAcknowledged mode RBCB buffers
806  *
807  * @details
808  *    This primitive Frees the Unacknowldged Mode RbCb sdu queue
809  *
810  * @param [in]   gCb    - RLC instance control block
811  * @param [in]   rbCb   - RB Control Block
812  *
813  * @return Void
814  */
815 #ifdef ANSI
816 Void rlcUmmFreeDlRbCb
817 (
818 RlcCb       *gCb,
819 RlcDlRbCb   *rbCb
820 )
821 #else
822 Void rlcUmmFreeDlRbCb(gCb,rbCb)
823 RlcCb       *gCb;
824 RlcDlRbCb   *rbCb;
825 #endif
826 {
827    TRC2(rlcUmmFreeDlRbCb)
828
829
830    /* cat the SDU queue to the to be freed list */
831    cmLListCatLList(&(gCb->u.dlCb->toBeFreed.sduLst),&(rbCb->m.umDl.sduQ));
832    rlcUtlRaiseDlCleanupEvent(gCb);
833
834    RETVOID;
835 } /* rlcUmmFreeDlRbCb */
836
837 /********************************************************************30**
838          End of file
839 **********************************************************************/