/*******************************************************************************
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenAirInterface is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see <http://www.gnu.org/licenses/>.
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@eurecom.fr
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
*******************************************************************************/
/***************************************************************************
rlc_am_reset.c -
-------------------
AUTHOR : Lionel GAUTHIER
COMPANY : EURECOM
EMAIL : Lionel.Gauthier@eurecom.fr
***************************************************************************/
/* From 3GPP TS 25.322 V5.0.0 (2002-03)
The RLC reset procedure is used to reset two RLC peer entities, which are operating in acknowledged mode.
During the reset procedure the hyper frame numbers (HFN) in UTRAN and UE are synchronised. Two HFNs
used for ciphering needs to be synchronised, DL HFN in downlink and UL HFN in uplink.
In the reset procedure, the highest UL HFN and DL HFN used by the RLC
entity in the transmitting sides, i.e. the HFNs associated with AMD PDUs of "Sequence Number"=VT(S)-1 if at least
one AMD PDU had been transmitted or of "Sequence Number"=0 if no AMD PDU had been transmitted, are
exchanged between UE and UTRAN.
The RESET PDUs and the RESET ACK PDUs have higher priority than AMD PDUs.
*/
#define RLC_AM_C
#include "rtos_header.h"
#include "platform_types.h"
//-----------------------------------------------------------------------------
#include "rlc.h"
#include "rlc_am_entity.h"
#include "rlc_am_structs.h"
#include "rlc_am_constants.h"
#include "rlc_am_control_primitives_proto_extern.h"
#include "rlc_am_fsm_proto_extern.h"
#include "list.h"
#include "mem_block.h"
#include "umts_timer_proto_extern.h"
#include "LAYER2/MAC/extern.h"
#define DEBUG_RESET
//-----------------------------------------------------------------------------
void send_reset_ack_pdu (uint8_t rsnP, struct rlc_am_entity* rlcP);
void send_reset_pdu (struct rlc_am_entity* rlcP);
void reset_rlc_am (struct rlc_am_entity* rlcP);
void process_reset_ack (mem_block_t* pduP, struct rlc_am_reset_header* controlP, struct rlc_am_entity* rlcP);
void process_reset (mem_block_t* pduP, struct rlc_am_reset_header* controlP, struct rlc_am_entity* rlcP);
//-----------------------------------------------------------------------------
void
rlc_am_reset_time_out (struct rlc_am_entity* rlcP, mem_block_t* not_usedP)
{
//-----------------------------------------------------------------------------
/* from 3GPP TS 25.322 V5.0.0 (2002-03)
If Timer_RST expires before the reset procedure is terminated, the Sender shall:
- if VT(RST)<MaxRST-1:
- set the RESET PDU as previously transmitted (even if additional SDUs were discarded in the mean-time);
- transmit RESET PDU;
- increment VT(RST) by one;
- restart Timer_RST.
Unrecoverable error (VT(RST) MaxRST)
The Sender shall:
- if VT(RST) becomes larger than or equal to MaxRST:
- indicate unrecoverable error to upper layer.
*/
rlcP->timer_rst = NULL;
#ifdef DEBUG_RESET
msg ("\n******************************************************************\n");
msg ("[RLC_AM][RB %d] RESET TIME OUT VT(RST) = %d frame %d\n", rlcP->rb_id, rlcP->vt_rst, Mac_rlc_xface->frame);
msg ("\n******************************************************************\n");
#endif
if (rlcP->protocol_state & RLC_RESET_PENDING_STATE) {
if (rlcP->vt_rst < rlcP->max_rst - 1) {
send_reset_pdu (rlcP);
rlcP->vt_rst += 1;
} else {
//rrc_indication_unrecoverable_error_from_rlc_am(rlcP);
// notification not raised to RRC, continue. (TO DO)
msg ("\n******************************************************************\n");
msg ("[RLC_AM][RB %d] RESET TIME OUT VT(RST) >= max_rst frame %d REPORT TO RRC\n", rlcP->rb_id, Mac_rlc_xface->frame);
msg ("\n******************************************************************\n");
send_reset_pdu (rlcP);
rlcP->vt_rst += 1;
rlc_data_conf (0, rlcP->rb_id, 0,RLC_TX_CONFIRM_FAILURE, rlcP->data_plane); // mui, rb_ib, status
#ifdef NODE_MT
#warning rrc_ue_CPHY_Out_Synch_rx should be called
//rrc_ue_CPHY_Out_Synch_rx (1); // Temporary hack to disconnect mobile upon RLC AM timeout
#endif /* NODE_MT */
}
}
}
//-----------------------------------------------------------------------------
void
send_reset_pdu (struct rlc_am_entity* rlcP)
{
//-----------------------------------------------------------------------------
mem_block_t* pdu;
struct rlc_am_reset_header* header;
/* From TS 25.322 V5.0.0 (2002-03)
RESET PDU contents to set
The Sender shall:
- set the HFNI field to the currently highest used HFN (DL HFN when the RESET PDU is sent by UTRAN or UL
HFN when the RESET PDU is sent by the UE);
- set the RSN field to the sequence number of the RESET PDU. The sequence number of the first RESET PDU
after the AM entity is established or re-established shall be "0". This sequence number is incremented every time
a new RESET PDU is transmitted, but not when a RESET PDU is retransmitted.
*/
if (!(rlcP->timer_rst)) {
if (rlcP->vt_rst == 0) { // first transmission of reset PDU
rlcP->reset_sequence_number ^= 1;
}
rlcP->vt_rst += 1;
pdu = get_free_mem_block (rlcP->pdu_size + sizeof (struct rlc_am_tx_control_pdu_allocation) + GUARD_CRC_LIH_SIZE);
if ((pdu)) {
((struct rlc_am_tx_control_pdu_management*) (pdu->data))->rlc_tb_type = RLC_AM_RESET_PDU_TYPE;
header = (struct rlc_am_reset_header*) (&pdu->data[sizeof (struct rlc_am_tx_control_pdu_allocation)]);
header->byte1 = RLC_PDU_TYPE_RESET | (rlcP->reset_sequence_number << 3);
#ifdef DEBUG_RESET
msg ("\n******************************************************************\n");
msg ("[RLC_AM][RB %d] TX RESET RSN %d VT(RST) %d frame %d\n", rlcP->rb_id, rlcP->reset_sequence_number, rlcP->vt_rst, Mac_rlc_xface->frame);
msg ("\n******************************************************************\n");
#endif
// HFNI NOT IMPLEMENTED NOW needed only for cyphering
/*header->hfni[0] = 0;
header->hfni[1] = 0;
header->hfni[2] = 0;
*/
list_add_head (pdu, &rlcP->control);
rlc_am_fsm_notify_event (rlcP, RLC_AM_TRANSMIT_RESET_EVENT); // not yet submitted to lower layers
} else {
msg ("[RLC_AM][RB %d] ERROR SEND RESET OUT OF MEMORY ERROR\n", rlcP->rb_id);
}
}
}
//-----------------------------------------------------------------------------
void
send_reset_ack_pdu (uint8_t rsnP, struct rlc_am_entity* rlcP)
{
//-----------------------------------------------------------------------------
mem_block_t* pdu;
struct rlc_am_reset_header* header;
/* From 3GPP TS 25.322 V5.0.0 (2002-03)
RESET ACK PDU contents to set
The Receiver shall:
- set the hyper frame number indicator field (HFNI) to the currently highest used HFN (DL HFN when the RESET
ACK PDU is sent by UTRAN or UL HFN when the RESET ACK PDU is sent by the UE);
- set the RSN field to the same value as in the corresponding received RESET PDU.
*/
if ((pdu = get_free_mem_block (rlcP->pdu_size + sizeof (struct rlc_am_tx_control_pdu_allocation) + GUARD_CRC_LIH_SIZE))) {
#ifdef DEBUG_RESET
msg ("\n******************************************************************\n");
msg ("[RLC_AM][RB %d] TX RESET ACK RSN %d frame %d\n", rlcP->rb_id, rsnP, Mac_rlc_xface->frame);
msg ("\n******************************************************************\n");
#endif
((struct rlc_am_tx_control_pdu_management*) (pdu->data))->rlc_tb_type = RLC_AM_RESET_ACK_PDU_TYPE;
header = (struct rlc_am_reset_header*) (&pdu->data[sizeof (struct rlc_am_tx_control_pdu_allocation)]);
header->byte1 = RLC_PDU_TYPE_RESET_ACK | (rsnP << 3);
list_add_head (pdu, &rlcP->control);
}
#ifdef DEBUG_RESET
else {
msg ("[RLC_AM][RB %d] SEND RESET ACK OUT OF MEMORY ERROR\n", rlcP->rb_id);
}
#endif
}
//-----------------------------------------------------------------------------
void
process_reset_ack (mem_block_t* pduP, struct rlc_am_reset_header* controlP, struct rlc_am_entity* rlcP)
{
//-----------------------------------------------------------------------------
/* from 3GPP TS 25.322 V5.0.0 (2002-03)
Upon reception of a RESET ACK PDU, the Sender shall:
- if the Sender has already transmitted a RESET PDU which has not been yet acknowledged by a RESET ACK
PDU:
- if the received RSN value is the same as the one in the corresponding RESET PDU:
- set the HFN value (DL HFN when the RESET ACK PDU is received in UE or UL HFN when the RESET
ACK PDU is received in UTRAN) to the HFNI field of the received RESET ACK PDU;
- reset the state variables described in subclause 9.4 to their initial values;
- stop all the timers described in subclause 9.5;
- reset configurable parameters to their configured values;
- discard all RLC PDUs in the receiving side of the AM RLC entity;
- discard all RLC SDUs that were transmitted before the reset in the transmitting side of the AM RLC
entity;
- increase with one the UL HFN and DL HFN, and the updated HFN values shall be used for the first
transmitted and received AMD PDUs after the reset procedure;
- otherwise (if the received RSN value is not the same as the one in the corresponding RESET PDU):
- discard the RESET ACK PDU;
- otherwise (if the Sender has not transmitted a RESET PDU which has not been yet acknowledged by a RESET
ACK PDU):
- discard the RESET ACK PDU.
NOTE: If the TFC selection exchange has been initiated by sending the RLC Entity Info parameter to MAC, the
RLC entity may delay the RLC SDUs discard in the transmitting side until the end of the next TTI.
*/
if (rlc_am_fsm_notify_event (rlcP, RLC_AM_RECEIVE_RESET_ACK_EVENT)) {
if (((controlP->byte1 & RLC_AM_RESET_SEQUENCE_NUMBER_MASK) >> 3) == rlcP->reset_sequence_number) {
#ifdef DEBUG_RESET
msg ("\n******************************************************************\n");
msg ("[RLC_AM][RB %d] RX RESET ACK RSN %d frame %d\n", rlcP->rb_id, ((controlP->byte1 & RLC_AM_RESET_SEQUENCE_NUMBER_MASK) >> 3), Mac_rlc_xface->frame);
msg ("\n******************************************************************\n");
#endif
rlc_am_reset_state_variables (rlcP);
reset_rlc_am (rlcP);
umts_stop_all_timers (&rlcP->rlc_am_timer_list);
rlcP->timer_rst = NULL;
}
#ifdef DEBUG_RESET
else {
msg ("\n******************************************************************\n");
msg ("[RLC_AM][RB %d] RX RESET ACK WRONG RSN %d != %d frame %d\n", rlcP->rb_id, (controlP->byte1 & RLC_AM_RESET_SEQUENCE_NUMBER_MASK) >> 3,
rlcP->reset_sequence_number, Mac_rlc_xface->frame);
msg ("\n******************************************************************\n");
}
#endif
}
#ifdef DEBUG_RESET
else {
msg ("\n******************************************************************\n");
msg ("[RLC_AM][RB %d] RX RESET ACK NOT EXPECTED frame %d\n", rlcP->rb_id, Mac_rlc_xface->frame);
msg ("\n******************************************************************\n");
}
#endif
msg("RLC AM RESET EXIT\n");
}
//-----------------------------------------------------------------------------
void
process_reset (mem_block_t* pduP, struct rlc_am_reset_header* controlP, struct rlc_am_entity* rlcP)
{
//-----------------------------------------------------------------------------
uint8_t rsn;
uint8_t saved_vt_rst;
/* From 25.322 V5.0.0 (2002-03)
Reception of the RESET PDU by the Receiver
Upon reception of a RESET PDU the Receiver shall:
- if the RSN value in the RESET PDU is the same as the RSN value in the last received RESET PDU:
- only submit a RESET ACK PDU to the lower layer with the contents set exactly as in the last transmitted
RESET ACK PDU (i.e., in this case the RLC entity is not reset).
- if the RESET PDU is the first RESET PDU received since the entity was (re-)established or the RSN value is
different from the RSN value in the last received RESET PDU:
- submit a RESET ACK PDU to the lower layer with the content set as specified in subclause 11.4.3.1;
- reset the state variables described in subclause 9.4 except VT(RST) to their initial values;
- stop all the timers described in subclause 9.5 except Timer_RST;
- reset configurable parameters to their configured values;
- discard all RLC PDUs in the receiving side of the AM RLC entity;
- discard all RLC SDUs that were transmitted before the reset in the transmitting side of the AM RLC entity;
- set the HFN (DL HFN when the RESET PDU is received in UE or UL HFN when the RESET PDU is
received in UTRAN) equal to the HFNI field in the received RESET PDU;
- increase with one the UL HFN and DL HFN, and the updated HFN values shall be used for the first
transmitted and received AMD PDUs after the reset procedure.
NOTE: If the TFC selection exchange has been initiated by sending the RLC Entity Info parameter to MAC, the
RLC entity may delay the RLC SDUs discard in the transmitting side of the AM RLC entity until the end
of the next TTI.
Reception of the RESET PDU by the Sender
Upon reception of a RESET PDU, the Sender shall:
- submit a RESET ACK PDU to the lower layer with the content set as specified in subclause 11.4.3.1;
- reset the state variables described in subclause 9.4 except VT(RST) to their initial values;
- stop all the timers described in subclause 9.5 except Timer_RST;
- reset configurable parameters to their configured values;
- discard all RLC PDUs in the receiving side of the AM RLC entity;
- discard all RLC SDUs that were transmitted before the reset in the transmitting side of the AM RLC entity;
- set the HFN (DL HFN when the RESET PDU is received in UE or UL HFN when the RESET PDU is received
in UTRAN) equal to the HFNI field in the received RESET PDU;
- increase with one the UL HFN and DL HFN, and the updated HFN values shall be used for the first transmitted
and received AMD PDUs after the reset procedure.
NOTE: If the TFC selection exchange has been initiated by sending the RLC Entity Info parameter to MAC, the
RLC entity may delay the RLC SDUs discard in the transmitting side until the end of the next TTI.
*/
rsn = (controlP->byte1 & RLC_AM_RESET_SEQUENCE_NUMBER_MASK) >> 3;
if ((rlcP->protocol_state & RLC_RESET_PENDING_STATE)) {
#ifdef DEBUG_RESET
msg ("\n******************************************************************\n");
msg ("[RLC_AM][RB %d] RX RESET RSN %d frame %d\n", rlcP->rb_id, rsn, Mac_rlc_xface->frame);
msg ("\n******************************************************************\n");
#endif
rlc_am_fsm_notify_event (rlcP, RLC_AM_RECEIVE_RESET_EVENT);
// sender
saved_vt_rst = rlcP->vt_rst;
reset_rlc_am (rlcP);
rlcP->vt_rst = saved_vt_rst;
rlcP->last_received_rsn = rsn;
send_reset_ack_pdu (rsn, rlcP);
// NOT IN SPECS, BUT IF SENDER RECEIVE A RESET, IT DISCARDS ALL CONTROL PDU IN ITS BUFFER
// SO IF THE RESET PDU WAS STILL IN THE RLC BUFFERS...IT IS DROPPED AND THE RESET TIMER CAN NOT
// BE STARTED (BY SUCCESSFULL TX ACK OF MAC LAYER), SO REARM THE TIMER AND SCHEDULE A NEW RESET
// PDU FOR TRANSMISSION
if (!(rlcP->timer_rst)) {
umts_stop_all_timers (&rlcP->rlc_am_timer_list);
rlc_am_reset_time_out (rlcP, NULL);
} else {
umts_stop_all_timers_except (&rlcP->rlc_am_timer_list, rlc_am_reset_time_out);
}
} else {
// receiver
#ifdef DEBUG_RESET
msg ("\n******************************************************************\n");
msg ("[RLC_AM][RB %d] RX RESET RSN %d frame %d\n", rlcP->rb_id, rsn, Mac_rlc_xface->frame);
msg ("\n******************************************************************\n");
#endif
if (rlcP->last_received_rsn == rsn) { //last_received_rsn initialized to -1 when RLC start
#ifdef DEBUG_RESET
msg ("\n******************************************************************\n");
msg ("[RLC_AM][RB %d] RX RESET RSN %d SAME RSN RECEIVED LAST RESET, SEND RESET ACK frame %d \n", rlcP->rb_id, rsn, Mac_rlc_xface->frame);
msg ("\n******************************************************************\n");
#endif
send_reset_ack_pdu (rsn, rlcP); // rsn start to zero
return;
}
rlc_am_fsm_notify_event (rlcP, RLC_AM_RECEIVE_RESET_EVENT);
saved_vt_rst = rlcP->vt_rst;
reset_rlc_am (rlcP);
rlcP->vt_rst = saved_vt_rst;
rlcP->last_received_rsn = rsn;
send_reset_ack_pdu (rsn, rlcP);
umts_stop_all_timers (&rlcP->rlc_am_timer_list);
rlcP->timer_rst = NULL;
}
}
//-----------------------------------------------------------------------------
void
reset_rlc_am (struct rlc_am_entity* rlcP)
{
//-----------------------------------------------------------------------------
int index;
for (index = 0; index < rlcP->size_input_sdus_buffer; index++) {
if (rlcP->input_sdus[index]) {
if (!(rlcP->data_plane)) {
#ifdef DEBUG_RLC_AM_SEND_CONFIRM
msg ("[RLC_AM][RB %d][CONFIRM] SDU MUI %d LOST IN RESET\n", rlcP->rb_id, ((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[index]->data))->mui);
#endif
rlc_data_conf (0, rlcP->rb_id, ((struct rlc_am_tx_sdu_management*) (rlcP->input_sdus[index]->data))->mui, RLC_TX_CONFIRM_FAILURE, rlcP->data_plane);
}
free_mem_block (rlcP->input_sdus[index]);
rlcP->input_sdus[index] = NULL;
}
}
rlc_am_reset_state_variables (rlcP);
rlc_am_discard_all_pdus (rlcP);
#ifdef DEBUG_RESET
msg ("[RLC_AM][RB %d] RESETED\n", rlcP->rb_id);
//display_mem_load();
//msg("sdu_conf_segmented : %p\n" , rlcP->sdu_conf_segmented.head);
//msg("sdu_discard_segmented : %p\n", rlcP->sdu_discard_segmented.head);
//msg("sdu_discarded : %p\n" , rlcP->sdu_discarded.head);
//msg("discard_procedures : %p\n" , rlcP->discard_procedures.head);
//check_mem_area(mem);
#endif
}