Compare commits
5 Commits
796a6df0df
...
2df561cfa2
Author | SHA1 | Date |
---|---|---|
Vadim Yanitskiy | 2df561cfa2 | |
Vadim Yanitskiy | fbb2ed3aa9 | |
Vadim Yanitskiy | 19ed00e9bb | |
Vadim Yanitskiy | b594b15e79 | |
Vadim Yanitskiy | 27344af7f0 |
|
@ -66,6 +66,31 @@ protected:
|
|||
|
||||
// PCAP
|
||||
srslte::nas_pcap* pcap = nullptr;
|
||||
|
||||
// Security context
|
||||
uint8_t k_nas_enc[32] = { };
|
||||
uint8_t k_nas_int[32] = { };
|
||||
|
||||
struct nas_sec_ctxt {
|
||||
uint8_t ksi;
|
||||
uint8_t k_asme[32];
|
||||
uint32_t tx_count;
|
||||
uint32_t rx_count;
|
||||
uint32_t k_enb_count;
|
||||
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
|
||||
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
|
||||
LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti;
|
||||
} ctxt = { };
|
||||
|
||||
void integrity_generate(uint8_t* key_128, uint32_t count, uint8_t direction,
|
||||
uint8_t* msg, uint32_t msg_len, uint8_t* mac);
|
||||
bool integrity_check(srslte::byte_buffer_t* pdu);
|
||||
|
||||
void cipher_encrypt(srslte::byte_buffer_t* pdu);
|
||||
void cipher_decrypt(srslte::byte_buffer_t* pdu);
|
||||
|
||||
void set_k_enb_count(uint32_t count);
|
||||
uint32_t get_k_enb_count();
|
||||
};
|
||||
|
||||
class nas : public nas_base
|
||||
|
@ -83,7 +108,6 @@ public:
|
|||
bool paging(srslte::s_tmsi_t* ue_identity) override;
|
||||
void set_barring(srslte::barring_t barring) override;
|
||||
void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu) override;
|
||||
uint32_t get_k_enb_count() override;
|
||||
bool is_attached() override;
|
||||
bool get_k_asme(uint8_t* k_asme_, uint32_t n) override;
|
||||
uint32_t get_ipv4_addr() override;
|
||||
|
@ -113,18 +137,6 @@ private:
|
|||
|
||||
std::vector<srslte::plmn_id_t> known_plmns;
|
||||
|
||||
// Security context
|
||||
struct nas_sec_ctxt {
|
||||
uint8_t ksi;
|
||||
uint8_t k_asme[32];
|
||||
uint32_t tx_count;
|
||||
uint32_t rx_count;
|
||||
uint32_t k_enb_count;
|
||||
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
|
||||
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
|
||||
LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti;
|
||||
};
|
||||
|
||||
typedef enum { DEFAULT_EPS_BEARER = 0, DEDICATED_EPS_BEARER } eps_bearer_type_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -139,7 +151,6 @@ private:
|
|||
|
||||
bool have_guti = false;
|
||||
bool have_ctxt = false;
|
||||
nas_sec_ctxt ctxt = {};
|
||||
bool auth_request = false;
|
||||
uint8_t current_sec_hdr = LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS;
|
||||
|
||||
|
@ -175,8 +186,6 @@ private:
|
|||
// Security
|
||||
bool eia_caps[8] = {};
|
||||
bool eea_caps[8] = {};
|
||||
uint8_t k_nas_enc[32] = {};
|
||||
uint8_t k_nas_int[32] = {};
|
||||
|
||||
// Airplane mode simulation
|
||||
typedef enum { DISABLED = 0, ENABLED } airplane_mode_state_t;
|
||||
|
@ -187,16 +196,9 @@ private:
|
|||
|
||||
bool running = false;
|
||||
|
||||
void
|
||||
integrity_generate(uint8_t* key_128, uint32_t count, uint8_t direction, uint8_t* msg, uint32_t msg_len, uint8_t* mac);
|
||||
bool integrity_check(srslte::byte_buffer_t* pdu);
|
||||
void cipher_encrypt(srslte::byte_buffer_t* pdu);
|
||||
void cipher_decrypt(srslte::byte_buffer_t* pdu);
|
||||
int apply_security_config(srslte::unique_byte_buffer_t& pdu, uint8_t sec_hdr_type);
|
||||
void reset_security_context();
|
||||
|
||||
void set_k_enb_count(uint32_t count);
|
||||
|
||||
bool check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT* caps);
|
||||
|
||||
void select_plmn();
|
||||
|
|
|
@ -58,7 +58,6 @@ public:
|
|||
bool paging(srslte::s_tmsi_t* ue_identity);
|
||||
void set_barring(srslte::barring_t barring);
|
||||
void write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu);
|
||||
uint32_t get_k_enb_count();
|
||||
bool is_attached();
|
||||
bool get_k_asme(uint8_t* k_asme_, uint32_t n);
|
||||
uint32_t get_ipv4_addr();
|
||||
|
@ -89,6 +88,11 @@ private:
|
|||
void handle_rrctl_conn_release(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len);
|
||||
void handle_rrctl_data(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len);
|
||||
void handle_rrctl_param(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len);
|
||||
void handle_rrctl_sec_mode(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len);
|
||||
|
||||
void handle_rrctl_ext_usim(const uint8_t* msg, size_t len);
|
||||
void handle_usim_gen_auth_resp_req(const struct rrctl::proto::ext_usim_msg* msg, size_t len);
|
||||
void handle_usim_gen_nas_keys_req(const struct rrctl::proto::ext_usim_msg* msg, size_t len);
|
||||
|
||||
void rrctl_send_confirm(rrctl::proto::msg_type type);
|
||||
void rrctl_send_error(rrctl::proto::msg_type type);
|
||||
|
|
|
@ -228,10 +228,10 @@ public:
|
|||
explicit error(const std::string& msg) : std::runtime_error(msg) {};
|
||||
};
|
||||
|
||||
void enc_hdr(srslte::byte_buffer_t& buf,
|
||||
proto::msg_type type,
|
||||
proto::msg_disc disc,
|
||||
uint16_t len = 0);
|
||||
struct proto::msg_hdr* enc_hdr(srslte::byte_buffer_t& buf,
|
||||
proto::msg_type type,
|
||||
proto::msg_disc disc,
|
||||
uint16_t len = 0);
|
||||
const uint8_t* dec_hdr(const srslte::byte_buffer_t& buf,
|
||||
proto::msg_type& type,
|
||||
proto::msg_disc& disc,
|
||||
|
|
|
@ -713,14 +713,14 @@ void nas::write_pdu(uint32_t lcid, unique_byte_buffer_t pdu)
|
|||
}
|
||||
}
|
||||
|
||||
void nas::set_k_enb_count(uint32_t count)
|
||||
void nas_base::set_k_enb_count(uint32_t count)
|
||||
{
|
||||
// UL count for RRC key derivation depends on UL Count of the Attach Request or Service Request.
|
||||
// On the case of an Authentication Request, the UL count used to generate K_enb must be reset to zero.
|
||||
ctxt.k_enb_count = count;
|
||||
}
|
||||
|
||||
uint32_t nas::get_k_enb_count()
|
||||
uint32_t nas_base::get_k_enb_count()
|
||||
{
|
||||
return ctxt.k_enb_count;
|
||||
}
|
||||
|
@ -768,12 +768,12 @@ void nas_base::start_pcap(srslte::nas_pcap* pcap_)
|
|||
* Security
|
||||
******************************************************************************/
|
||||
|
||||
void nas::integrity_generate(uint8_t* key_128,
|
||||
uint32_t count,
|
||||
uint8_t direction,
|
||||
uint8_t* msg,
|
||||
uint32_t msg_len,
|
||||
uint8_t* mac)
|
||||
void nas_base::integrity_generate(uint8_t* key_128,
|
||||
uint32_t count,
|
||||
uint8_t direction,
|
||||
uint8_t* msg,
|
||||
uint32_t msg_len,
|
||||
uint8_t* mac)
|
||||
{
|
||||
switch (ctxt.integ_algo) {
|
||||
case INTEGRITY_ALGORITHM_ID_EIA0:
|
||||
|
@ -812,7 +812,7 @@ void nas::integrity_generate(uint8_t* key_128,
|
|||
|
||||
// This function depends to a valid k_nas_int.
|
||||
// This key is generated in the security mode command.
|
||||
bool nas::integrity_check(byte_buffer_t* pdu)
|
||||
bool nas_base::integrity_check(byte_buffer_t* pdu)
|
||||
{
|
||||
if (pdu == nullptr) {
|
||||
nas_log->error("Invalid PDU\n");
|
||||
|
@ -866,7 +866,7 @@ bool nas::integrity_check(byte_buffer_t* pdu)
|
|||
}
|
||||
}
|
||||
|
||||
void nas::cipher_encrypt(byte_buffer_t* pdu)
|
||||
void nas_base::cipher_encrypt(byte_buffer_t* pdu)
|
||||
{
|
||||
byte_buffer_t pdu_tmp;
|
||||
switch (ctxt.cipher_algo) {
|
||||
|
@ -908,7 +908,7 @@ void nas::cipher_encrypt(byte_buffer_t* pdu)
|
|||
}
|
||||
}
|
||||
|
||||
void nas::cipher_decrypt(byte_buffer_t* pdu)
|
||||
void nas_base::cipher_decrypt(byte_buffer_t* pdu)
|
||||
{
|
||||
byte_buffer_t tmp_pdu;
|
||||
switch (ctxt.cipher_algo) {
|
||||
|
|
|
@ -84,7 +84,11 @@ void nas_ext::init(usim_interface_nas* usim_, rrc_interface_nas* rrc_, gw_interf
|
|||
handle_rrctl_param(disc, payload, length);
|
||||
break;
|
||||
case rrctl::proto::RRCTL_SEC_MODE:
|
||||
handle_rrctl_sec_mode(disc, payload, length);
|
||||
break;
|
||||
case rrctl::proto::RRCTL_EXT_USIM:
|
||||
handle_rrctl_ext_usim(payload, length);
|
||||
break;
|
||||
case rrctl::proto::RRCTL_CONN_RELEASE:
|
||||
default:
|
||||
nas_log->warning("%s is not handled\n", desc.c_str());
|
||||
|
@ -113,7 +117,9 @@ void nas_ext::rrctl_send_error(rrctl::proto::msg_type type)
|
|||
|
||||
void nas_ext::handle_rrctl_reset(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len)
|
||||
{
|
||||
// TODO: do we need to reset anything?
|
||||
/* Reset security state (no EEA, no EIA) */
|
||||
memset(&ctxt, 0x00, sizeof(ctxt));
|
||||
|
||||
rrctl_send_confirm(rrctl::proto::RRCTL_RESET);
|
||||
}
|
||||
|
||||
|
@ -160,10 +166,16 @@ void nas_ext::handle_rrctl_conn_establish(rrctl::proto::msg_disc disc, const uin
|
|||
return;
|
||||
}
|
||||
|
||||
set_k_enb_count(ctxt.tx_count);
|
||||
ctxt.tx_count++;
|
||||
|
||||
// Allocate a new NAS PDU on heap
|
||||
unique_byte_buffer_t nas_pdu = srslte::allocate_unique_buffer(*pool, true);
|
||||
nas_pdu->append_bytes(pdu, pdu_len);
|
||||
|
||||
if (pcap != nullptr)
|
||||
pcap->write_nas(nas_pdu->msg, nas_pdu->N_bytes);
|
||||
|
||||
rrc->connection_request(cause, std::move(nas_pdu));
|
||||
}
|
||||
|
||||
|
@ -179,7 +191,18 @@ void nas_ext::handle_rrctl_data(rrctl::proto::msg_disc disc, const uint8_t* msg,
|
|||
unique_byte_buffer_t nas_pdu = srslte::allocate_unique_buffer(*pool, true);
|
||||
nas_pdu->append_bytes(msg, len);
|
||||
|
||||
if (pcap != nullptr)
|
||||
pcap->write_nas(nas_pdu->msg, nas_pdu->N_bytes);
|
||||
|
||||
// Apply pre-configured EEA algorythm (if enabled)
|
||||
cipher_encrypt(nas_pdu.get());
|
||||
// Apply pre-configured EIA algorythm (if enabled)
|
||||
integrity_generate(&k_nas_int[16], ctxt.tx_count, SECURITY_DIRECTION_UPLINK,
|
||||
&nas_pdu->msg[5], nas_pdu->N_bytes - 5, &nas_pdu->msg[1]);
|
||||
|
||||
rrc->write_sdu(std::move(nas_pdu));
|
||||
ctxt.tx_count++;
|
||||
|
||||
rrctl_send_confirm(rrctl::proto::RRCTL_DATA);
|
||||
}
|
||||
|
||||
|
@ -213,6 +236,159 @@ void nas_ext::handle_rrctl_param(rrctl::proto::msg_disc disc, const uint8_t* msg
|
|||
}
|
||||
}
|
||||
|
||||
void nas_ext::handle_rrctl_sec_mode(rrctl::proto::msg_disc disc, const uint8_t* msg, size_t len)
|
||||
{
|
||||
const struct rrctl::proto::msg_sec_mode_req* req;
|
||||
|
||||
req = reinterpret_cast<const struct rrctl::proto::msg_sec_mode_req*> (msg);
|
||||
|
||||
if (len < sizeof(*req)) { /* XXX: mandatory fields only */
|
||||
nas_log->error("Received malformed PARAM.req (len=%zu)\n", len);
|
||||
rrctl_send_error(rrctl::proto::RRCTL_SEC_MODE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Skip the header */
|
||||
len -= sizeof(*req);
|
||||
|
||||
nas_log->info("Rx SecurityMode.req (EEA%u, EIA%u)\n", req->eea, req->eia);
|
||||
|
||||
ctxt.cipher_algo = static_cast<srslte::CIPHERING_ALGORITHM_ID_ENUM> (req->eea);
|
||||
ctxt.integ_algo = static_cast<srslte::INTEGRITY_ALGORITHM_ID_ENUM> (req->eia);
|
||||
|
||||
if (req->flags & SEC_MODE_F_RESET_RX_CTR)
|
||||
ctxt.rx_count = 0;
|
||||
if (req->flags & SEC_MODE_F_RESET_TX_CTR)
|
||||
ctxt.tx_count = 0;
|
||||
|
||||
if (req->eea != 0x00 or req->eia != 0x00) {
|
||||
/* Ensure that Kasme is present */
|
||||
if (len != sizeof(ctxt.k_asme)) {
|
||||
nas_log->error("Kasme is expected, but not present");
|
||||
rrctl_send_error(rrctl::proto::RRCTL_SEC_MODE);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&ctxt.k_asme[0], &req->k_asme[0], sizeof(ctxt.k_asme));
|
||||
|
||||
/* Derive both Knas_enc and Knas_int from Kasme */
|
||||
/* NOTE: how is this related to (U)SIM at all?!? */
|
||||
usim->generate_nas_keys(&ctxt.k_asme[0], // in
|
||||
&k_nas_enc[0], // out
|
||||
&k_nas_int[0], // out
|
||||
ctxt.cipher_algo,
|
||||
ctxt.integ_algo);
|
||||
}
|
||||
|
||||
rrctl_send_confirm(rrctl::proto::RRCTL_SEC_MODE);
|
||||
}
|
||||
|
||||
void nas_ext::handle_rrctl_ext_usim(const uint8_t* _msg, size_t len)
|
||||
{
|
||||
enum rrctl::proto::ext_usim_msg_type msg_type;
|
||||
const struct rrctl::proto::ext_usim_msg* msg;
|
||||
std::string msg_desc;
|
||||
|
||||
if (len < 4) { /* XXX: type + padding */
|
||||
nas_log->error("Received too short (U)SIM specific message (len=%zu)\n", len);
|
||||
rrctl_send_error(rrctl::proto::RRCTL_EXT_USIM);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Skip the header */
|
||||
len -= 4;
|
||||
|
||||
msg = reinterpret_cast<const struct rrctl::proto::ext_usim_msg*> (_msg);
|
||||
msg_type = static_cast<rrctl::proto::ext_usim_msg_type> (msg->type);
|
||||
|
||||
switch (msg_type) {
|
||||
case rrctl::proto::EXT_USIM_GEN_AUTH_RESP:
|
||||
handle_usim_gen_auth_resp_req(msg, len);
|
||||
break;
|
||||
case rrctl::proto::EXT_USIM_RAW_APDU:
|
||||
case rrctl::proto::EXT_USIM_READ_FILE:
|
||||
case rrctl::proto::EXT_USIM_UPDATE_FILE:
|
||||
case rrctl::proto::EXT_USIM_RESERVED:
|
||||
default:
|
||||
nas_log->warning("(U)SIM specific message 0x%02x is not handled\n", msg->type);
|
||||
}
|
||||
}
|
||||
|
||||
void nas_ext::handle_usim_gen_auth_resp_req(const struct rrctl::proto::ext_usim_msg* msg, size_t len)
|
||||
{
|
||||
const struct rrctl::proto::ext_usim_gen_auth_resp_req* req;
|
||||
struct rrctl::proto::ext_usim_gen_auth_resp_rsp* rsp;
|
||||
struct rrctl::proto::ext_usim_msg* rsp_msg;
|
||||
std::pair<uint16_t, uint16_t> mcc_mnc;
|
||||
struct rrctl::proto::msg_hdr* hdr;
|
||||
srslte::byte_buffer_t pdu;
|
||||
|
||||
/* Allocate the response message in advance */
|
||||
hdr = rrctl::codec::enc_hdr(pdu, rrctl::proto::RRCTL_EXT_USIM, rrctl::proto::RRCTL_CNF, 4);
|
||||
rsp_msg = reinterpret_cast<struct rrctl::proto::ext_usim_msg*> (&pdu.msg[pdu.N_bytes]);
|
||||
rsp_msg->type = msg->type;
|
||||
pdu.N_bytes += 4;
|
||||
|
||||
if (len < sizeof(*req)) {
|
||||
nas_log->error("Received too short (U)SIM GenAuthResp.req (len=%zu)\n", len);
|
||||
hdr->disc = (uint8_t) rrctl::proto::RRCTL_ERR;
|
||||
iface->write(pdu);
|
||||
return;
|
||||
}
|
||||
|
||||
rsp = &rsp_msg->u.gen_auth_resp_rsp;
|
||||
req = &msg->u.gen_auth_resp_req;
|
||||
|
||||
// Parse PLMN ID
|
||||
try {
|
||||
/* HACK: generalize this function */
|
||||
rrctl::codec::dec_plmn_select_req(mcc_mnc, &req->mcc[0], len);
|
||||
} catch (const rrctl::codec::error& e) {
|
||||
nas_log->warning("Failed to parse MCC/MNC: %s\n", e.what());
|
||||
hdr->disc = (uint8_t) rrctl::proto::RRCTL_ERR;
|
||||
iface->write(pdu);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t k_asme[32];
|
||||
uint8_t res[16];
|
||||
int res_len;
|
||||
|
||||
/* NOTE: this is a blocking call => no other RRCTL messages can be processed in parallel?
|
||||
* FIXME: the authors of srsUE apparently are not aware of 'const', so we have to cast. */
|
||||
auth_result_t auth_res = usim->generate_authentication_response((uint8_t*) &req->rand[0],
|
||||
(uint8_t*) &req->autn[0],
|
||||
mcc_mnc.first, mcc_mnc.second,
|
||||
&res[0], &res_len, &k_asme[0]);
|
||||
switch (auth_res) {
|
||||
case AUTH_OK:
|
||||
nas_log->info("Authentication vector has been generated successfully\n");
|
||||
|
||||
set_k_enb_count(0);
|
||||
|
||||
pdu.N_bytes += sizeof(*rsp);
|
||||
pdu.append_bytes(&k_asme[0], sizeof(k_asme));
|
||||
pdu.append_bytes(&res[0], res_len);
|
||||
rsp->res_len = (uint8_t) res_len;
|
||||
break;
|
||||
case AUTH_SYNCH_FAILURE:
|
||||
nas_log->warning("Synchronization is required to generate an authentication vector\n");
|
||||
|
||||
pdu.N_bytes += sizeof(*rsp);
|
||||
pdu.append_bytes(&res[0], res_len);
|
||||
rsp->res_len = (uint8_t) res_len;
|
||||
rsp->out_of_sync = true;
|
||||
break;
|
||||
case AUTH_FAILED:
|
||||
default:
|
||||
nas_log->warning("Could not generate an authentication vector\n");
|
||||
hdr->disc = (uint8_t) rrctl::proto::RRCTL_ERR;
|
||||
}
|
||||
|
||||
hdr->len = htons(pdu.N_bytes - sizeof(*hdr));
|
||||
iface->write(pdu);
|
||||
}
|
||||
|
||||
void nas_ext::get_metrics(nas_metrics_t* m)
|
||||
{
|
||||
nas_metrics_t metrics = {};
|
||||
|
@ -274,19 +450,34 @@ bool nas_ext::paging(srslte::s_tmsi_t* ue_identity)
|
|||
void nas_ext::write_pdu(uint32_t lcid, srslte::unique_byte_buffer_t pdu)
|
||||
{
|
||||
srslte::byte_buffer_t msg;
|
||||
uint8 pd, sec_hdr_type;
|
||||
|
||||
nas_log->info_hex(pdu->msg, pdu->N_bytes, "Received DL %s PDU from RRC\n", rrc->get_rb_name(lcid).c_str());
|
||||
|
||||
// Parse the message security header
|
||||
liblte_mme_parse_msg_sec_header((LIBLTE_BYTE_MSG_STRUCT*) pdu.get(), &pd, &sec_hdr_type);
|
||||
switch (sec_hdr_type) {
|
||||
case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT:
|
||||
case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT:
|
||||
case LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST:
|
||||
case LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS:
|
||||
case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY:
|
||||
break;
|
||||
case LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED:
|
||||
// Apply pre-configured EEA algorythm (if enabled)
|
||||
cipher_decrypt(pdu.get());
|
||||
break;
|
||||
default:
|
||||
nas_log->error("Received DL NAS PDU with unknown sec_hdr=%02x\n", sec_hdr_type);
|
||||
}
|
||||
|
||||
if (pcap != nullptr)
|
||||
pcap->write_nas(pdu->msg, pdu->N_bytes);
|
||||
|
||||
rrctl::codec::enc_data_ind(msg, pdu->msg, pdu->N_bytes, lcid);
|
||||
iface->write(msg);
|
||||
}
|
||||
|
||||
uint32_t nas_ext::get_k_enb_count()
|
||||
{
|
||||
// FIXME: we probably need to maintain a security context
|
||||
return 0; // return a dummy value for now
|
||||
}
|
||||
|
||||
bool nas_ext::is_attached()
|
||||
{
|
||||
// FIXME: we probably need to maintain the state
|
||||
|
|
|
@ -102,10 +102,10 @@ std::string msg_hdr_desc(proto::msg_type type, proto::msg_disc disc, uint16_t le
|
|||
|
||||
namespace codec {
|
||||
|
||||
void enc_hdr(srslte::byte_buffer_t& buf,
|
||||
proto::msg_type type,
|
||||
proto::msg_disc disc,
|
||||
uint16_t len)
|
||||
struct proto::msg_hdr* enc_hdr(srslte::byte_buffer_t& buf,
|
||||
proto::msg_type type,
|
||||
proto::msg_disc disc,
|
||||
uint16_t len)
|
||||
{
|
||||
struct proto::msg_hdr hdr = {
|
||||
#if defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
|
@ -121,6 +121,8 @@ void enc_hdr(srslte::byte_buffer_t& buf,
|
|||
};
|
||||
|
||||
buf.append_bytes((const uint8_t*) &hdr, sizeof(hdr));
|
||||
|
||||
return reinterpret_cast<struct proto::msg_hdr*> (&buf.msg[0]);
|
||||
}
|
||||
|
||||
const uint8_t* dec_hdr(const srslte::byte_buffer_t& buf,
|
||||
|
|
Loading…
Reference in New Issue