pdcp_sequence_manager.c 10.3 KB
Newer Older
1 2 3 4 5
/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
6
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */

22 23
/*! \file pdcp_sequence_manager.c
* \brief PDCP Sequence Numbering Methods
24 25 26
* \author Baris Demiray and Navid Nikaein
* \email navid.nikaein@eurecom.fr
* \date 2014
27 28 29 30 31 32 33 34 35
*/

#include "pdcp_sequence_manager.h"
#include "UTIL/LOG/log_if.h"
#include "pdcp_util.h"

/*
 * Initializes sequence numbering state
 * @param pdcp_entity The PDCP entity to be initialized
Lionel Gauthier's avatar
Lionel Gauthier committed
36
 * @return boolean_t TRUE on success, FALSE otherwise
37
 */
Lionel Gauthier's avatar
Lionel Gauthier committed
38
boolean_t pdcp_init_seq_numbers(pdcp_t* pdcp_entity)
39
{
40
  if (pdcp_entity == NULL) {
41
    return FALSE;
42
  }
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60

  /* Sequence number state variables */

  // TX and RX window
  pdcp_entity->next_pdcp_tx_sn = 0;
  pdcp_entity->next_pdcp_rx_sn = 0;

  // TX and RX Hyper Frame Numbers
  pdcp_entity->tx_hfn = 0;
  pdcp_entity->rx_hfn = 0;

  // SN of the last PDCP SDU delivered to upper layers
  // Shall UE and eNB behave differently on initialization? (see 7.1.e)
  pdcp_entity->last_submitted_pdcp_rx_sn = 4095;

  return TRUE;
}

Lionel Gauthier's avatar
Lionel Gauthier committed
61
boolean_t pdcp_is_seq_num_size_valid(pdcp_t* pdcp_entity)
62
{
63
  if (pdcp_entity == NULL) {
64
    return FALSE;
65
  }
66 67 68 69 70 71 72 73 74 75 76 77 78

  // Check if the size of SN is valid (see 3GPP TS 36.323 v10.1.0 item 6.3.2)
  if (pdcp_entity->seq_num_size != 5 && pdcp_entity->seq_num_size != 7 && pdcp_entity->seq_num_size != 12) {
    LOG_W(PDCP, "Incoming SN size is invalid! (Expected: {5 | 7 | 12}, Received: %d\n", pdcp_entity->seq_num_size);
    return FALSE;
  }

  return TRUE;
}

/**
 * Check if SN number is in the range according to SN size
 */
79
boolean_t pdcp_is_seq_num_valid(uint16_t seq_num, uint8_t seq_num_size)
80
{
81
  if (seq_num >= 0 && seq_num <= pdcp_calculate_max_seq_num_for_given_size(seq_num_size)) {
82
    return TRUE;
83
  }
84 85 86 87

  return FALSE;
}

88
uint16_t pdcp_calculate_max_seq_num_for_given_size(uint8_t seq_num_size)
89
{
90
  uint16_t max_seq_num = 1;
91 92 93 94 95 96

  max_seq_num <<= seq_num_size;

  return max_seq_num - 1;
}

97
uint16_t pdcp_get_next_tx_seq_number(pdcp_t* pdcp_entity)
98
{
99
  if (pdcp_is_seq_num_size_valid(pdcp_entity) == FALSE) {
100
    return -1;
101
  }
102 103

  // Sequence number should be incremented after it is assigned for a PDU
104
  uint16_t pdcp_seq_num = pdcp_entity->next_pdcp_tx_sn;
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120

  /*
   * Update sequence numbering state and Hyper Frame Number if SN has already reached
   * its max value (see 5.1 PDCP Data Transfer Procedures)
   */
  if (pdcp_entity->next_pdcp_tx_sn == pdcp_calculate_max_seq_num_for_given_size(pdcp_entity->seq_num_size)) {
    pdcp_entity->next_pdcp_tx_sn = 0;
    pdcp_entity->tx_hfn++;
    LOG_D(PDCP,"Reseting the PDCP sequence number\n");
  } else {
    pdcp_entity->next_pdcp_tx_sn++;
  }

  return pdcp_seq_num;
}

Lionel Gauthier's avatar
Lionel Gauthier committed
121
boolean_t pdcp_advance_rx_window(pdcp_t* pdcp_entity)
122
{
123
  if (pdcp_is_seq_num_size_valid(pdcp_entity) == FALSE) {
124
    return FALSE;
125
  }
126 127 128 129 130

  /*
   * Update sequence numbering state and Hyper Frame Number if SN has already reached
   * its max value (see 5.1 PDCP Data Transfer Procedures)
   */
131
  LOG_D(PDCP, "Advancing RX window...\n");
132

133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
  if (pdcp_entity->next_pdcp_rx_sn == pdcp_calculate_max_seq_num_for_given_size(pdcp_entity->seq_num_size)) {
    pdcp_entity->next_pdcp_rx_sn = 0;
    pdcp_entity->rx_hfn++;
  } else {
    pdcp_entity->next_pdcp_rx_sn++;
  }

  return TRUE;
}

/**
 * Checks if incoming PDU has a sequence number in accordance with the RX window
 * @return 1 if SN is okay, 0 otherwise
 * XXX Reordering window should also be handled here
 */
148 149 150
boolean_t pdcp_is_rx_seq_number_valid(uint16_t seq_num, pdcp_t* pdcp_entity,srb_flag_t srb_flagP)
{

151
  uint16_t  reordering_window = 0;
152

153
  LOG_D(PDCP, "Incoming RX Sequence number is %04d\n", seq_num);
154

155
  if (pdcp_is_seq_num_size_valid(pdcp_entity) == FALSE || pdcp_is_seq_num_valid(seq_num, pdcp_entity->seq_num_size) == FALSE) {
156
    return FALSE;
157
  }
158 159 160 161 162 163

  /*
   * Mark received sequence numbers to keep track of missing ones
   * (and to build PDCP Control PDU for PDCP status report)
   */
  if (pdcp_mark_current_pdu_as_received(seq_num, pdcp_entity) == TRUE) {
Cedric Roux's avatar
fix  
Cedric Roux committed
164
    LOG_D(PDCP, "Received sequence number successfuly marked\n");
165 166 167 168 169
  } else {
    LOG_W(PDCP, "Cannot mark received sequence number on the bitmap!\n");
  }

  /*
170
   * RX Procedures for SRB and DRBs as described in sec 5.1.2 of 36.323
171
   */
172

173
  if (srb_flagP) { // SRB
174

175
    if (seq_num < pdcp_entity->next_pdcp_rx_sn) {
176
      // decipher and verify the integrity of the PDU (if applicable) using COUNT based on RX_HFN + 1 and the received PDCP SN
177 178
      pdcp_entity->rx_hfn++;
      pdcp_entity->rx_hfn_offset   = 0;
179
    } else {
180 181 182 183
      // decipher and verify the integrity of the PDU (if applicable) using COUNT based using COUNT based on RX_HFN and the received PDCP SN
      pdcp_entity->rx_hfn_offset   = 0;
    }

184
    // Assume  that integrity verification is applicable and the integrity verification is passed successfully;
185
    // or assume that  integrity verification is not applicable:
186

187 188
    // same the old next_pdcp_rx_sn to revert otherwise
    pdcp_entity->next_pdcp_rx_sn_before_integrity = pdcp_entity->next_pdcp_rx_sn;
189

190
    if (seq_num != pdcp_entity->next_pdcp_rx_sn) {
191
      LOG_D(PDCP,"Re-adjusting the sequence number to %d\n", seq_num);
192
    }
193

194 195 196
    //set Next_PDCP_RX_SN to the received PDCP SN +1 ;
    pdcp_entity->next_pdcp_rx_sn = seq_num;
    pdcp_advance_rx_window(pdcp_entity);  // + 1, and check if it is larger than Maximum_PDCP_SN:
197

198 199
  } else { // DRB

200
    if (pdcp_entity->seq_num_size == PDCP_SN_7BIT) {
201
      reordering_window = REORDERING_WINDOW_SN_7BIT;
202
    } else {
203
      reordering_window = REORDERING_WINDOW_SN_12BIT;
204
    }
205 206

    switch (pdcp_entity->rlc_mode) {
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
    case RLC_MODE_AM:
      if ((seq_num - pdcp_entity->last_submitted_pdcp_rx_sn > reordering_window)  ||
          ((0 <= pdcp_entity->last_submitted_pdcp_rx_sn - seq_num) &&
           (pdcp_entity->last_submitted_pdcp_rx_sn - seq_num < reordering_window)  )) {

        if (seq_num  > pdcp_entity->next_pdcp_rx_sn) {
          /*
           * decipher the PDCP PDU as specified in the subclause 5.6, using COUNT based on RX_HFN - 1 and the received PDCP SN;
           */
          pdcp_entity->rx_hfn_offset   =  -1;
        } else  {
          /*
           *  decipher the PDCP PDU as specified in the subclause 5.6, using COUNT based on RX_HFN and the received PDCP SN;
           */
          pdcp_entity->rx_hfn_offset   = 0;
        }

        // discard this PDCP SDU;
        LOG_W(PDCP, "Out of the reordering window (Incoming SN:%d, Expected SN:%d): discard this PDCP SDU\n",
              seq_num, pdcp_entity->next_pdcp_rx_sn);
        return FALSE;
228
      } else if (pdcp_entity->next_pdcp_rx_sn - seq_num > reordering_window) {
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
        pdcp_entity->rx_hfn++;
        // use COUNT based on RX_HFN and the received PDCP SN for deciphering the PDCP PDU;
        pdcp_entity->rx_hfn_offset   = 0;
        pdcp_entity->next_pdcp_rx_sn++;
      } else if (seq_num - pdcp_entity->next_pdcp_rx_sn  >= reordering_window ) {
        //  use COUNT based on RX_HFN – 1 and the received PDCP SN for deciphering the PDCP PDU;
        pdcp_entity->rx_hfn_offset   = -1;
      } else if (seq_num  >= pdcp_entity->next_pdcp_rx_sn ) {
        // use COUNT based on RX_HFN and the received PDCP SN for deciphering the PDCP PDU;
        pdcp_entity->rx_hfn_offset = 0;
        //set Next_PDCP_RX_SN to the received PDCP SN +1 ;
        pdcp_entity->next_pdcp_rx_sn = seq_num;
        pdcp_advance_rx_window(pdcp_entity);  // + 1, anc check if it is larger than Maximum_PDCP_SN:
        LOG_D(PDCP,"Re-adjusting the sequence number to %d\n", seq_num);
      } else if (seq_num < pdcp_entity->next_pdcp_rx_sn) {
        // use COUNT based on RX_HFN and the received PDCP SN for deciphering the PDCP PDU;
        pdcp_entity->rx_hfn_offset = 0;
246
      }
247

248
      break;
249

250
    case RLC_MODE_UM :
251
      if (seq_num <  pdcp_entity->next_pdcp_rx_sn) {
252
        pdcp_entity->rx_hfn++;
253
      }
254

255 256 257 258
      // decipher the PDCP Data PDU using COUNT based on RX_HFN and the received PDCP SN as specified in the subclause 5.6;
      //set Next_PDCP_RX_SN to the received PDCP SN +1 ;
      pdcp_entity->next_pdcp_rx_sn = seq_num;
      pdcp_advance_rx_window(pdcp_entity);  // + 1, and check if it is larger than Maximum_PDCP_SN:
259

260
      break;
261 262

    case RLC_MODE_TM :
263 264 265 266 267 268
    default:
      LOG_W(PDCP,"RLC mode %d not supported\n",pdcp_entity->rlc_mode);
      return FALSE;
    }
  }

269
  /*
270 271 272 273 274
  if (seq_num == pdcp_entity->next_pdcp_rx_sn) {
    LOG_I(PDCP, "Next expected SN (%d) arrived, advancing RX window\n", seq_num);

    return pdcp_advance_rx_window(pdcp_entity);
  } else {
275
    LOG_E(PDCP, "Incoming SN is not the one we expected to receive! (Incoming:%d, Expected:%d)\n", \
276
        seq_num, pdcp_entity->next_pdcp_rx_sn);
277

278

279
    // Update first missing PDU (used in PDCP Control PDU for PDCP status report, see 6.2.6)
280 281 282 283 284
    if (pdcp_entity->first_missing_pdu != -1)
      pdcp_entity->first_missing_pdu = pdcp_entity->next_pdcp_rx_sn;

    return FALSE;
  }
285
  */
286
  return TRUE;
287 288
}

289
boolean_t pdcp_mark_current_pdu_as_received(uint16_t seq_num, pdcp_t* pdcp_entity)
290 291 292
{
  /*
   * Incoming sequence number and PDCP entity were already
293
   * validated in pdcp_is_rx_seq_number_valid() so we don't
294 295 296 297 298 299
   * check here
   */

  /*
   * Find relevant octet
   */
300
  uint16_t octet_index = seq_num / 8;
301 302 303 304
  /*
   * Set relevant bit
   */
  LOG_D(PDCP, "Marking %d. bit of %d. octet of status bitmap\n", (seq_num % 8) + 1, octet_index);
305
  util_mark_nth_bit_of_octet(&pdcp_entity->missing_pdu_bitmap[octet_index], seq_num % 8);
306
  util_print_binary_representation((uint8_t*)"Current state of relevant octet: ", pdcp_entity->missing_pdu_bitmap[octet_index]);
307 308
  return TRUE;
}