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