srsRAN/srsue/src/stack/upper/rrctl.cc

230 lines
5.9 KiB
C++
Raw Normal View History

srsue/extnas: implement RRCTL codec and message handling RRCTL is a simple protocol (inspired by Osmocom's L1CTL) that allows an external NAS entity to control the RRC layer of srsUE. The most notable primitives are PLMN search, selection, and PDU transfer. The protocol assumes traditional master-slave communication, where one side (an external NAS entity) initiates various processes, while the other (srsUE) executes them and indicates the outcome. Each RRCTL message starts with a header that can be defined as follows: +-------------------------------+--------------------------+ | Message type | 6 bits | +-------------------------------+--------------------------+ | Message sub-type | 2 bits | +-------------------------------+--------------------------+ | Spare (RFU) | 8 bits | +-------------------------------+--------------------------+ | Payload length | 2 octets (big endian) | +-------------------------------+--------------------------+ | Payload (optional) | (see payload length) | +-------------------------------+--------------------------+ The following message types are defined at the moment: - RRCTL_RESET - reset internal state of the external NAS interface (does nothing for now, may be useful in the future); - RRCTL_PLMN_SEARCH - initiates PLMN (carrier) search on pre-configured EARFCN (Absolute Radio Freqency Number); - RRCTL_PLMN_SELECT - binds the UE to one of the previously detected carriers (see RRCTL_PLMN_SEARCH) defined by a given pair of MCC and MNC; - RRCTL_CONN_ESTABLISH - establishes connection to the serving cell (previously selected using RRCTL_PLMN_SELECT) with a given cause and NAS PDU; - RRCTL_CONN_RELEASE - releases previously established dedicated connection (currently does nothing because the RRC layer does not expose any API for that); - RRCTL_DATA - encapsulates a received (Downlink) or to be transmitted (Uplink) NAS PDU (the former also contains LCID). Each message type has at least two of the following sub-types: - RRCTL_REQ - request (usually comes from an external NAS entity), used to initiate some process (e.g. PLMN search); - RRCTL_IND - indication that something has happened without a prior request (for example, a Downlink NAS PDU was received); - RRCTL_CNF - confirmation (positive conslusion) of the requested task; - RRCTL_ERR - negative conslusion of the requested task (error). The protocol definition (enums ans structs) and codec functions are defined in a separate namespaces: 'rrctl::proto' and 'rrctl::codec' respectively. The codec functions may throw exceptions of type 'rrctl::codec::error' if something goes wrong.
2020-03-18 08:04:17 +00:00
/*
* Copyright 2020 Software Radio Systems Limited
* Author: Vadim Yanitskiy <axilirator@gmail.com>
* Sponsored by Positive Technologies
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE 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 Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdint.h>
#include <arpa/inet.h>
#include "srsue/hdr/stack/upper/rrctl.h"
namespace rrctl {
namespace proto {
std::string msg_hdr_desc(proto::msg_type type, proto::msg_disc disc, uint16_t len)
{
std::string desc;
switch (type) {
case RRCTL_RESET:
desc += "Reset";
break;
case RRCTL_PLMN_SEARCH:
desc += "PLMN Search";
break;
case RRCTL_PLMN_SELECT:
desc += "PLMN Select";
break;
case RRCTL_CONN_ESTABLISH:
desc += "Connection Establish";
break;
case RRCTL_CONN_RELEASE:
desc += "Connection Release";
break;
case RRCTL_DATA:
desc += "Data (PDU)";
break;
case RRCTL_PAGING:
desc += "Paging";
break;
case RRCTL_PARAM:
desc += "Parameter";
break;
case RRCTL_SEC_MODE:
desc += "Security Mode";
break;
case RRCTL_EXT_USIM:
desc += "(U)SIM Specific";
break;
case RRCTL_RESERVED:
desc += "RFU (Reserved for Further Use)";
break;
srsue/extnas: implement RRCTL codec and message handling RRCTL is a simple protocol (inspired by Osmocom's L1CTL) that allows an external NAS entity to control the RRC layer of srsUE. The most notable primitives are PLMN search, selection, and PDU transfer. The protocol assumes traditional master-slave communication, where one side (an external NAS entity) initiates various processes, while the other (srsUE) executes them and indicates the outcome. Each RRCTL message starts with a header that can be defined as follows: +-------------------------------+--------------------------+ | Message type | 6 bits | +-------------------------------+--------------------------+ | Message sub-type | 2 bits | +-------------------------------+--------------------------+ | Spare (RFU) | 8 bits | +-------------------------------+--------------------------+ | Payload length | 2 octets (big endian) | +-------------------------------+--------------------------+ | Payload (optional) | (see payload length) | +-------------------------------+--------------------------+ The following message types are defined at the moment: - RRCTL_RESET - reset internal state of the external NAS interface (does nothing for now, may be useful in the future); - RRCTL_PLMN_SEARCH - initiates PLMN (carrier) search on pre-configured EARFCN (Absolute Radio Freqency Number); - RRCTL_PLMN_SELECT - binds the UE to one of the previously detected carriers (see RRCTL_PLMN_SEARCH) defined by a given pair of MCC and MNC; - RRCTL_CONN_ESTABLISH - establishes connection to the serving cell (previously selected using RRCTL_PLMN_SELECT) with a given cause and NAS PDU; - RRCTL_CONN_RELEASE - releases previously established dedicated connection (currently does nothing because the RRC layer does not expose any API for that); - RRCTL_DATA - encapsulates a received (Downlink) or to be transmitted (Uplink) NAS PDU (the former also contains LCID). Each message type has at least two of the following sub-types: - RRCTL_REQ - request (usually comes from an external NAS entity), used to initiate some process (e.g. PLMN search); - RRCTL_IND - indication that something has happened without a prior request (for example, a Downlink NAS PDU was received); - RRCTL_CNF - confirmation (positive conslusion) of the requested task; - RRCTL_ERR - negative conslusion of the requested task (error). The protocol definition (enums ans structs) and codec functions are defined in a separate namespaces: 'rrctl::proto' and 'rrctl::codec' respectively. The codec functions may throw exceptions of type 'rrctl::codec::error' if something goes wrong.
2020-03-18 08:04:17 +00:00
default:
desc += "<UNKNOWN>";
}
desc += " ";
switch (disc) {
case RRCTL_REQ:
desc += "Request";
break;
case RRCTL_IND:
desc += "Indication";
break;
case RRCTL_CNF:
desc += "Confirmation";
break;
case RRCTL_ERR:
desc += "Error";
break;
}
if (len > 0) {
desc += " (length ";
desc += std::to_string(len);
desc += ")";
}
return desc;
}
}
namespace codec {
struct proto::msg_hdr* enc_hdr(srslte::byte_buffer_t& buf,
proto::msg_type type,
proto::msg_disc disc,
uint16_t len)
srsue/extnas: implement RRCTL codec and message handling RRCTL is a simple protocol (inspired by Osmocom's L1CTL) that allows an external NAS entity to control the RRC layer of srsUE. The most notable primitives are PLMN search, selection, and PDU transfer. The protocol assumes traditional master-slave communication, where one side (an external NAS entity) initiates various processes, while the other (srsUE) executes them and indicates the outcome. Each RRCTL message starts with a header that can be defined as follows: +-------------------------------+--------------------------+ | Message type | 6 bits | +-------------------------------+--------------------------+ | Message sub-type | 2 bits | +-------------------------------+--------------------------+ | Spare (RFU) | 8 bits | +-------------------------------+--------------------------+ | Payload length | 2 octets (big endian) | +-------------------------------+--------------------------+ | Payload (optional) | (see payload length) | +-------------------------------+--------------------------+ The following message types are defined at the moment: - RRCTL_RESET - reset internal state of the external NAS interface (does nothing for now, may be useful in the future); - RRCTL_PLMN_SEARCH - initiates PLMN (carrier) search on pre-configured EARFCN (Absolute Radio Freqency Number); - RRCTL_PLMN_SELECT - binds the UE to one of the previously detected carriers (see RRCTL_PLMN_SEARCH) defined by a given pair of MCC and MNC; - RRCTL_CONN_ESTABLISH - establishes connection to the serving cell (previously selected using RRCTL_PLMN_SELECT) with a given cause and NAS PDU; - RRCTL_CONN_RELEASE - releases previously established dedicated connection (currently does nothing because the RRC layer does not expose any API for that); - RRCTL_DATA - encapsulates a received (Downlink) or to be transmitted (Uplink) NAS PDU (the former also contains LCID). Each message type has at least two of the following sub-types: - RRCTL_REQ - request (usually comes from an external NAS entity), used to initiate some process (e.g. PLMN search); - RRCTL_IND - indication that something has happened without a prior request (for example, a Downlink NAS PDU was received); - RRCTL_CNF - confirmation (positive conslusion) of the requested task; - RRCTL_ERR - negative conslusion of the requested task (error). The protocol definition (enums ans structs) and codec functions are defined in a separate namespaces: 'rrctl::proto' and 'rrctl::codec' respectively. The codec functions may throw exceptions of type 'rrctl::codec::error' if something goes wrong.
2020-03-18 08:04:17 +00:00
{
struct proto::msg_hdr hdr = {
#if defined(__LITTLE_ENDIAN_BITFIELD)
.disc = (uint8_t) disc,
.type = (uint8_t) type,
#elif defined(__BIG_ENDIAN_BITFIELD)
.type = (uint8_t) type,
.disc = (uint8_t) disc,
#else
#error "Please fix <asm/byteorder.h>"
#endif
.len = ntohs(len),
};
buf.append_bytes((const uint8_t*) &hdr, sizeof(hdr));
return reinterpret_cast<struct proto::msg_hdr*> (&buf.msg[0]);
srsue/extnas: implement RRCTL codec and message handling RRCTL is a simple protocol (inspired by Osmocom's L1CTL) that allows an external NAS entity to control the RRC layer of srsUE. The most notable primitives are PLMN search, selection, and PDU transfer. The protocol assumes traditional master-slave communication, where one side (an external NAS entity) initiates various processes, while the other (srsUE) executes them and indicates the outcome. Each RRCTL message starts with a header that can be defined as follows: +-------------------------------+--------------------------+ | Message type | 6 bits | +-------------------------------+--------------------------+ | Message sub-type | 2 bits | +-------------------------------+--------------------------+ | Spare (RFU) | 8 bits | +-------------------------------+--------------------------+ | Payload length | 2 octets (big endian) | +-------------------------------+--------------------------+ | Payload (optional) | (see payload length) | +-------------------------------+--------------------------+ The following message types are defined at the moment: - RRCTL_RESET - reset internal state of the external NAS interface (does nothing for now, may be useful in the future); - RRCTL_PLMN_SEARCH - initiates PLMN (carrier) search on pre-configured EARFCN (Absolute Radio Freqency Number); - RRCTL_PLMN_SELECT - binds the UE to one of the previously detected carriers (see RRCTL_PLMN_SEARCH) defined by a given pair of MCC and MNC; - RRCTL_CONN_ESTABLISH - establishes connection to the serving cell (previously selected using RRCTL_PLMN_SELECT) with a given cause and NAS PDU; - RRCTL_CONN_RELEASE - releases previously established dedicated connection (currently does nothing because the RRC layer does not expose any API for that); - RRCTL_DATA - encapsulates a received (Downlink) or to be transmitted (Uplink) NAS PDU (the former also contains LCID). Each message type has at least two of the following sub-types: - RRCTL_REQ - request (usually comes from an external NAS entity), used to initiate some process (e.g. PLMN search); - RRCTL_IND - indication that something has happened without a prior request (for example, a Downlink NAS PDU was received); - RRCTL_CNF - confirmation (positive conslusion) of the requested task; - RRCTL_ERR - negative conslusion of the requested task (error). The protocol definition (enums ans structs) and codec functions are defined in a separate namespaces: 'rrctl::proto' and 'rrctl::codec' respectively. The codec functions may throw exceptions of type 'rrctl::codec::error' if something goes wrong.
2020-03-18 08:04:17 +00:00
}
const uint8_t* dec_hdr(const srslte::byte_buffer_t& buf,
proto::msg_type& type,
proto::msg_disc& disc,
uint16_t& len)
{
const struct proto::msg_hdr* hdr;
// Make sure at least header is present
if (buf.N_bytes < sizeof(*hdr))
throw codec::error("header is too short");
hdr = reinterpret_cast<const struct proto::msg_hdr*> (buf.msg);
type = static_cast<proto::msg_type> (hdr->type);
disc = static_cast<proto::msg_disc> (hdr->disc);
len = htons(hdr->len);
// Make sure the whole message fits
if (buf.N_bytes < sizeof(*hdr) + len)
throw codec::error("body is too short");
// Return pointer to the payload (if present)
return len ? hdr->data : NULL;
}
void enc_plmn_search_res(srslte::byte_buffer_t& buf,
const srsue::rrc_interface_nas::found_plmn_t* plmns,
size_t nof_plmns)
{
struct proto::msg_plmn_search_res msg;
uint16_t msg_len;
if (nof_plmns > 16)
throw codec::error("too many PLMNS to encode");
msg.nof_plmns = static_cast<uint8_t> (nof_plmns);
for (size_t i = 0; i < nof_plmns; i++) {
plmns[i].plmn_id.to_rrctl_bytes(msg.plmns[i].mcc, msg.plmns[i].mnc);
msg.plmns[i].tac = htons(plmns[i].tac);
}
msg_len = sizeof(proto::msg_plmn_search_res::plmn) * nof_plmns + 1;
enc_hdr(buf, proto::RRCTL_PLMN_SEARCH, proto::RRCTL_CNF, msg_len);
buf.append_bytes((uint8_t *) &msg, msg_len);
}
void dec_plmn_select_req(std::pair<uint16_t, uint16_t>& mcc_mnc,
const uint8_t* payload, size_t len)
{
const struct proto::msg_plmn_select_req* msg;
struct srslte::plmn_id_t plmn_id;
if (len < sizeof(*msg))
throw codec::error("body is too short");
msg = reinterpret_cast<const struct proto::msg_plmn_select_req*> (payload);
plmn_id.from_rrctl_bytes(msg->mcc, msg->mnc);
mcc_mnc = plmn_id.to_number();
}
void dec_conn_establish_req(srslte::establishment_cause_t& cause,
const uint8_t*& pdu, size_t& pdu_len,
const uint8_t* payload, size_t len)
{
const struct proto::msg_conn_establish_req* msg;
if (len < sizeof(*msg))
throw codec::error("body is too short");
msg = reinterpret_cast<const struct proto::msg_conn_establish_req*> (payload);
cause = static_cast<srslte::establishment_cause_t> (msg->cause);
pdu_len = len - 1;
pdu = msg->pdu;
}
void enc_data_ind(srslte::byte_buffer_t& buf,
const uint8_t *pdu, size_t pdu_len,
uint32_t lcid)
{
struct proto::msg_data msg;
msg.lcid = htonl(lcid);
enc_hdr(buf, proto::RRCTL_DATA, proto::RRCTL_IND, sizeof(msg) + pdu_len);
buf.append_bytes((const uint8_t*) &msg, sizeof(msg));
buf.append_bytes(pdu, pdu_len);
}
void enc_paging_ind(srslte::byte_buffer_t& buf,
srslte::s_tmsi_t* ue_identity)
{
struct proto::msg_paging_ind msg;
msg.ueid.m_tmsi = htonl(ue_identity->m_tmsi);
msg.ueid.mmec = ue_identity->mmec;
enc_hdr(buf, proto::RRCTL_PAGING, proto::RRCTL_IND, sizeof(msg));
buf.append_bytes((const uint8_t*) &msg, sizeof(msg));
}
} // namespace codec
} // namespace rrctl