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