904 lines
28 KiB
C
904 lines
28 KiB
C
/* high-level RANAP messsage generation code */
|
|
|
|
/* (C) 2015 by Harald Welte <laforge@gnumonks.org>
|
|
* All Rights Reserved
|
|
*
|
|
* This program 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.
|
|
*
|
|
* This program 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.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include <osmocom/core/utils.h>
|
|
#include <osmocom/core/msgb.h>
|
|
|
|
#include "asn1helpers.h"
|
|
#include <osmocom/ranap/iu_helpers.h>
|
|
|
|
#include <osmocom/ranap/ranap_common.h>
|
|
#include <osmocom/ranap/ranap_ies_defs.h>
|
|
#include <osmocom/ranap/ranap_msg_factory.h>
|
|
|
|
#define DRANAP _ranap_DRANAP
|
|
|
|
/*! \brief allocate a new long and assing a value to it */
|
|
static long *new_long(long in)
|
|
{
|
|
long *out = CALLOC(1, sizeof(long));
|
|
*out = in;
|
|
return out;
|
|
}
|
|
|
|
/*! \brief generate RANAP RESET message */
|
|
struct msgb *ranap_new_msg_reset(RANAP_CN_DomainIndicator_t domain,
|
|
const RANAP_Cause_t *cause)
|
|
{
|
|
RANAP_ResetIEs_t ies;
|
|
RANAP_Reset_t out;
|
|
struct msgb *msg;
|
|
int rc;
|
|
|
|
memset(&ies, 0, sizeof(ies));
|
|
ies.cN_DomainIndicator = domain;
|
|
if (cause)
|
|
memcpy(&ies.cause, cause, sizeof(ies.cause));
|
|
|
|
memset(&out, 0, sizeof(out));
|
|
rc = ranap_encode_reseties(&out, &ies);
|
|
if (rc < 0) {
|
|
LOGP(DRANAP, LOGL_ERROR, "error encoding reset IEs: %d\n", rc);
|
|
return NULL;
|
|
}
|
|
|
|
msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_Reset,
|
|
RANAP_Criticality_reject,
|
|
&asn_DEF_RANAP_Reset,
|
|
&out);
|
|
|
|
/* release dynamic allocations attached to dt */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_Reset, &out);
|
|
|
|
return msg;
|
|
}
|
|
|
|
/*! \brief generate RANAP RESET ACK message */
|
|
struct msgb *ranap_new_msg_reset_ack(RANAP_CN_DomainIndicator_t domain,
|
|
RANAP_GlobalRNC_ID_t *rnc_id)
|
|
{
|
|
RANAP_ResetAcknowledgeIEs_t ies;
|
|
RANAP_ResetAcknowledge_t out;
|
|
struct msgb *msg;
|
|
int rc;
|
|
|
|
memset(&ies, 0, sizeof(ies));
|
|
ies.cN_DomainIndicator = domain;
|
|
|
|
/* The RNC shall include the globalRNC_ID in the RESET
|
|
* ACKNOWLEDGE message to the CN */
|
|
if (rnc_id) {
|
|
ies.presenceMask = RESETACKNOWLEDGEIES_RANAP_GLOBALRNC_ID_PRESENT;
|
|
OCTET_STRING_noalloc(&ies.globalRNC_ID.pLMNidentity,
|
|
rnc_id->pLMNidentity.buf,
|
|
rnc_id->pLMNidentity.size);
|
|
ies.globalRNC_ID.rNC_ID = rnc_id->rNC_ID;
|
|
}
|
|
|
|
/* FIXME: Do we need criticalityDiagnostics */
|
|
|
|
memset(&out, 0, sizeof(out));
|
|
rc = ranap_encode_resetacknowledgeies(&out, &ies);
|
|
if (rc < 0) {
|
|
LOGP(DRANAP, LOGL_ERROR, "error encoding reset ack IEs: %d\n", rc);
|
|
return NULL;
|
|
}
|
|
|
|
msg = ranap_generate_successful_outcome(RANAP_ProcedureCode_id_Reset,
|
|
RANAP_Criticality_reject,
|
|
&asn_DEF_RANAP_ResetAcknowledge,
|
|
&out);
|
|
|
|
/* release dynamic allocations attached to dt */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_ResetAcknowledge, &out);
|
|
|
|
return msg;
|
|
}
|
|
|
|
/*! \brief generate RANAP INITIAL UE message */
|
|
struct msgb *ranap_new_msg_initial_ue(uint32_t conn_id, int is_ps,
|
|
RANAP_GlobalRNC_ID_t *rnc_id,
|
|
uint8_t *nas_pdu, unsigned int nas_len)
|
|
{
|
|
RANAP_InitialUE_MessageIEs_t ies;
|
|
RANAP_InitialUE_Message_t out;
|
|
struct msgb *msg;
|
|
uint32_t ctxidbuf;
|
|
int rc;
|
|
uint16_t buf0 = 0x2342;
|
|
|
|
memset(&ies, 0, sizeof(ies));
|
|
if (is_ps)
|
|
ies.cN_DomainIndicator = RANAP_CN_DomainIndicator_ps_domain;
|
|
else
|
|
ies.cN_DomainIndicator = RANAP_CN_DomainIndicator_cs_domain;
|
|
|
|
OCTET_STRING_noalloc(&ies.lai.pLMNidentity, rnc_id->pLMNidentity.buf, rnc_id->pLMNidentity.size);
|
|
OCTET_STRING_noalloc(&ies.lai.lAC, (uint8_t *)&buf0, sizeof(buf0));
|
|
|
|
OCTET_STRING_noalloc(&ies.sai.pLMNidentity, rnc_id->pLMNidentity.buf, rnc_id->pLMNidentity.size);
|
|
OCTET_STRING_noalloc(&ies.sai.lAC, (uint8_t *)&buf0, sizeof(buf0));
|
|
OCTET_STRING_noalloc(&ies.sai.sAC, (uint8_t *)&buf0, sizeof(buf0));
|
|
|
|
OCTET_STRING_noalloc(&ies.nas_pdu, nas_pdu, nas_len);
|
|
asn1_u24_to_bitstring(&ies.iuSigConId, &ctxidbuf, conn_id);
|
|
OCTET_STRING_noalloc(&ies.globalRNC_ID.pLMNidentity, rnc_id->pLMNidentity.buf, rnc_id->pLMNidentity.size);
|
|
ies.globalRNC_ID.rNC_ID = rnc_id->rNC_ID;
|
|
|
|
memset(&out, 0, sizeof(out));
|
|
rc = ranap_encode_initialue_messageies(&out, &ies);
|
|
if (rc < 0) {
|
|
LOGP(DRANAP, LOGL_ERROR, "error encoding initial UE IEs: %d\n", rc);
|
|
return NULL;
|
|
}
|
|
|
|
msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_InitialUE_Message,
|
|
RANAP_Criticality_reject,
|
|
&asn_DEF_RANAP_InitialUE_Message,
|
|
&out);
|
|
|
|
/* release dynamic allocations attached to dt */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_InitialUE_Message, &out);
|
|
|
|
return msg;
|
|
}
|
|
|
|
|
|
/*! \brief generate RANAP DIRECT TRANSFER message */
|
|
struct msgb *ranap_new_msg_dt(uint8_t sapi, const uint8_t *nas, unsigned int nas_len)
|
|
{
|
|
RANAP_DirectTransferIEs_t ies;
|
|
RANAP_DirectTransfer_t dt;
|
|
struct msgb *msg;
|
|
int rc;
|
|
|
|
memset(&ies, 0, sizeof(ies));
|
|
memset(&dt, 0, sizeof(dt));
|
|
|
|
/* only SAPI optional field shall be present for CN->RNC */
|
|
ies.presenceMask = DIRECTTRANSFERIES_RANAP_SAPI_PRESENT;
|
|
|
|
if (sapi == 3)
|
|
ies.sapi = RANAP_SAPI_sapi_3;
|
|
else
|
|
ies.sapi = RANAP_SAPI_sapi_0;
|
|
|
|
/* Avoid copying + later freeing of OCTET STRING */
|
|
OCTET_STRING_noalloc(&ies.nas_pdu, nas, nas_len);
|
|
|
|
/* ies -> dt */
|
|
rc = ranap_encode_directtransferies(&dt, &ies);
|
|
|
|
/* dt -> msg */
|
|
msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_DirectTransfer,
|
|
RANAP_Criticality_reject,
|
|
&asn_DEF_RANAP_DirectTransfer,
|
|
&dt);
|
|
|
|
/* release dynamic allocations attached to dt */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_DirectTransfer, &dt);
|
|
|
|
return msg;
|
|
}
|
|
|
|
static const enum RANAP_IntegrityProtectionAlgorithm ip_alg[2] = {
|
|
RANAP_IntegrityProtectionAlgorithm_standard_UMTS_integrity_algorithm_UIA1,
|
|
RANAP_IntegrityProtectionAlgorithm_standard_UMTS_integrity_algorithm_UIA2,
|
|
};
|
|
|
|
static const RANAP_EncryptionAlgorithm_t enc_alg[2] = {
|
|
RANAP_EncryptionAlgorithm_standard_UMTS_encryption_algorith_UEA1,
|
|
RANAP_EncryptionAlgorithm_standard_UMTS_encryption_algorithm_UEA2,
|
|
};
|
|
|
|
/*! \brief generate RANAP SECURITY MODE COMMAND message */
|
|
struct msgb *ranap_new_msg_sec_mod_cmd(const uint8_t *ik, const uint8_t *ck, enum RANAP_KeyStatus status)
|
|
{
|
|
RANAP_SecurityModeCommandIEs_t ies;
|
|
RANAP_SecurityModeCommand_t out;
|
|
struct msgb *msg;
|
|
int i, rc;
|
|
|
|
memset(&ies, 0, sizeof(ies));
|
|
memset(&out, 0, sizeof(out));
|
|
|
|
for (i = 0; i < ARRAY_SIZE(ip_alg); i++) {
|
|
/* needs to be dynamically allocated, as
|
|
* SET_OF_free() will call FREEMEM() on it */
|
|
RANAP_IntegrityProtectionAlgorithm_t *alg = CALLOC(1, sizeof(*alg));
|
|
*alg = ip_alg[i];
|
|
ASN_SEQUENCE_ADD(&ies.integrityProtectionInformation.permittedAlgorithms, alg);
|
|
}
|
|
|
|
BIT_STRING_fromBuf(&ies.integrityProtectionInformation.key, ik, 16*8);
|
|
|
|
if (ck) {
|
|
ies.presenceMask = SECURITYMODECOMMANDIES_RANAP_ENCRYPTIONINFORMATION_PRESENT;
|
|
for (i = 0; i < ARRAY_SIZE(ip_alg); i++) {
|
|
/* needs to be dynamically allocated, as
|
|
* SET_OF_free() will call FREEMEM() on it */
|
|
RANAP_EncryptionAlgorithm_t *alg = CALLOC(1, sizeof(*alg));
|
|
*alg = enc_alg[i];
|
|
ASN_SEQUENCE_ADD(&ies.encryptionInformation.permittedAlgorithms, alg);
|
|
}
|
|
BIT_STRING_fromBuf(&ies.encryptionInformation.key, ck, 16*8);
|
|
}
|
|
|
|
ies.keyStatus = status;
|
|
|
|
/* ies -> out */
|
|
rc = ranap_encode_securitymodecommandies(&out, &ies);
|
|
|
|
/* release dynamic allocations attached to ies */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_IntegrityProtectionInformation, &ies.integrityProtectionInformation);
|
|
if (ck)
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_EncryptionInformation, &ies.encryptionInformation);
|
|
|
|
/* out -> msg */
|
|
msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_SecurityModeControl,
|
|
RANAP_Criticality_reject,
|
|
&asn_DEF_RANAP_SecurityModeCommand,
|
|
&out);
|
|
|
|
/* release dynamic allocations attached to out */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_SecurityModeCommand, &out);
|
|
|
|
return msg;
|
|
}
|
|
|
|
/*! \brief generate RANAP SECURITY MODE COMPLETE message */
|
|
struct msgb *ranap_new_msg_sec_mod_compl(
|
|
RANAP_ChosenIntegrityProtectionAlgorithm_t chosen_ip_alg,
|
|
RANAP_ChosenEncryptionAlgorithm_t chosen_enc_alg)
|
|
{
|
|
RANAP_SecurityModeCompleteIEs_t ies;
|
|
RANAP_SecurityModeComplete_t out;
|
|
struct msgb *msg;
|
|
int i, rc;
|
|
|
|
memset(&ies, 0, sizeof(ies));
|
|
memset(&out, 0, sizeof(out));
|
|
|
|
ies.presenceMask = SECURITYMODECOMPLETEIES_RANAP_CHOSENENCRYPTIONALGORITHM_PRESENT;
|
|
ies.chosenIntegrityProtectionAlgorithm = chosen_ip_alg;
|
|
ies.chosenEncryptionAlgorithm = chosen_enc_alg;
|
|
|
|
/* ies -> out */
|
|
rc = ranap_encode_securitymodecompleteies(&out, &ies);
|
|
|
|
/* out -> msg */
|
|
msg = ranap_generate_successful_outcome(RANAP_ProcedureCode_id_SecurityModeControl,
|
|
RANAP_Criticality_reject,
|
|
&asn_DEF_RANAP_SecurityModeComplete,
|
|
&out);
|
|
|
|
/* release dynamic allocations attached to out */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_SecurityModeComplete, &out);
|
|
|
|
return msg;
|
|
}
|
|
|
|
/*! \brief generate RANAP COMMON ID message */
|
|
struct msgb *ranap_new_msg_common_id(const char *imsi)
|
|
{
|
|
RANAP_CommonID_IEs_t ies;
|
|
RANAP_CommonID_t out;
|
|
struct msgb *msg;
|
|
int rc;
|
|
|
|
memset(&ies, 0, sizeof(ies));
|
|
memset(&out, 0, sizeof(out));
|
|
|
|
if (imsi) {
|
|
uint8_t *imsi_buf = CALLOC(1, 16);
|
|
rc = ranap_imsi_encode(imsi_buf, 16, imsi);
|
|
ies.permanentNAS_UE_ID.present = RANAP_PermanentNAS_UE_ID_PR_iMSI;
|
|
ies.permanentNAS_UE_ID.choice.iMSI.buf = imsi_buf;
|
|
ies.permanentNAS_UE_ID.choice.iMSI.size = rc;
|
|
} else
|
|
ies.permanentNAS_UE_ID.present = RANAP_PermanentNAS_UE_ID_PR_NOTHING;
|
|
|
|
/* ies -> out */
|
|
rc = ranap_encode_commonid_ies(&out, &ies);
|
|
/* release dynamic allocations attached to ies */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_PermanentNAS_UE_ID, &ies.permanentNAS_UE_ID);
|
|
if (rc < 0)
|
|
return NULL;
|
|
|
|
/* out -> msg */
|
|
msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_CommonID,
|
|
RANAP_Criticality_ignore,
|
|
&asn_DEF_RANAP_CommonID,
|
|
&out);
|
|
|
|
/* release dynamic allocations attached to out */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_CommonID, &out);
|
|
|
|
return msg;
|
|
}
|
|
|
|
/*! \brief generate RANAP IU RELEASE COMMAND message */
|
|
struct msgb *ranap_new_msg_iu_rel_cmd(const RANAP_Cause_t *cause_in)
|
|
{
|
|
RANAP_Iu_ReleaseCommandIEs_t ies;
|
|
RANAP_Iu_ReleaseCommand_t out;
|
|
struct msgb *msg;
|
|
int rc;
|
|
|
|
memset(&ies, 0, sizeof(ies));
|
|
memset(&out, 0, sizeof(out));
|
|
|
|
memcpy(&ies.cause, cause_in, sizeof(ies.cause));
|
|
|
|
/* ies -> out */
|
|
rc = ranap_encode_iu_releasecommandies(&out, &ies);
|
|
if (rc < 0)
|
|
return NULL;
|
|
|
|
/* out -> msg */
|
|
msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_Iu_Release,
|
|
RANAP_Criticality_reject,
|
|
&asn_DEF_RANAP_Iu_ReleaseCommand,
|
|
&out);
|
|
|
|
/* release dynamic allocations attached to out */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_Iu_ReleaseCommand, &out);
|
|
|
|
return msg;
|
|
}
|
|
|
|
/*! \brief generate RAPAP IU RELEASE COMPLETE message */
|
|
struct msgb *ranap_new_msg_iu_rel_compl(void)
|
|
{
|
|
RANAP_Iu_ReleaseCompleteIEs_t ies;
|
|
RANAP_Iu_ReleaseComplete_t out;
|
|
struct msgb *msg;
|
|
int rc;
|
|
|
|
memset(&ies, 0, sizeof(ies));
|
|
memset(&out, 0, sizeof(out));
|
|
|
|
/* ies -> out */
|
|
rc = ranap_encode_iu_releasecompleteies(&out, &ies);
|
|
if (rc < 0)
|
|
return NULL;
|
|
|
|
/* out -> msg */
|
|
msg = ranap_generate_successful_outcome(RANAP_ProcedureCode_id_Iu_Release,
|
|
RANAP_Criticality_reject,
|
|
&asn_DEF_RANAP_Iu_ReleaseComplete,
|
|
&out);
|
|
|
|
/* release dynamic allocations attached to out */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_Iu_ReleaseComplete, &out);
|
|
|
|
return msg;
|
|
}
|
|
|
|
/*! \brief generate RANAP PAGING COMMAND message */
|
|
struct msgb *ranap_new_msg_paging_cmd(const char *imsi, const uint32_t *tmsi, int is_ps, uint32_t cause)
|
|
{
|
|
RANAP_PagingIEs_t ies;
|
|
RANAP_Paging_t out;
|
|
struct msgb *msg;
|
|
uint8_t *imsi_buf = CALLOC(1, 16);
|
|
int rc;
|
|
|
|
memset(&ies, 0, sizeof(ies));
|
|
memset(&out, 0, sizeof(out));
|
|
|
|
/* put together the 'ies' */
|
|
if (is_ps)
|
|
ies.cN_DomainIndicator = RANAP_CN_DomainIndicator_ps_domain;
|
|
else
|
|
ies.cN_DomainIndicator = RANAP_CN_DomainIndicator_cs_domain;
|
|
|
|
rc = ranap_imsi_encode(imsi_buf, 16, imsi);
|
|
ies.permanentNAS_UE_ID.present = RANAP_PermanentNAS_UE_ID_PR_iMSI;
|
|
ies.permanentNAS_UE_ID.choice.iMSI.buf = imsi_buf;
|
|
ies.permanentNAS_UE_ID.choice.iMSI.size = rc;
|
|
|
|
if (tmsi) {
|
|
uint32_t *tmsi_buf = CALLOC(1, sizeof(*tmsi_buf));
|
|
*tmsi_buf = *tmsi;
|
|
ies.presenceMask |= PAGINGIES_RANAP_TEMPORARYUE_ID_PRESENT;
|
|
if (is_ps) {
|
|
ies.temporaryUE_ID.present = RANAP_TemporaryUE_ID_PR_p_TMSI;
|
|
ies.temporaryUE_ID.choice.tMSI.buf = (uint8_t *) tmsi_buf;
|
|
ies.temporaryUE_ID.choice.tMSI.size = sizeof(*tmsi_buf);
|
|
} else {
|
|
ies.temporaryUE_ID.present = RANAP_TemporaryUE_ID_PR_tMSI;
|
|
ies.temporaryUE_ID.choice.p_TMSI.buf = (uint8_t *) tmsi_buf;
|
|
ies.temporaryUE_ID.choice.p_TMSI.size = sizeof(*tmsi_buf);
|
|
}
|
|
}
|
|
|
|
if (cause) {
|
|
ies.presenceMask |= PAGINGIES_RANAP_PAGINGCAUSE_PRESENT;
|
|
ies.pagingCause = cause;
|
|
}
|
|
|
|
/* ies -> out */
|
|
rc = ranap_encode_pagingies(&out, &ies);
|
|
/* release dynamic allocation attached to ies */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_PermanentNAS_UE_ID, &ies.permanentNAS_UE_ID);
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_TemporaryUE_ID, &ies.temporaryUE_ID);
|
|
if (rc < 0)
|
|
return NULL;
|
|
|
|
/* out -> msg */
|
|
msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_Paging,
|
|
RANAP_Criticality_reject,
|
|
&asn_DEF_RANAP_Paging,
|
|
&out);
|
|
|
|
/* release dynamic allocations attached to out */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_Paging, &out);
|
|
|
|
return msg;
|
|
}
|
|
|
|
static RANAP_SDU_ErrorRatio_t *new_sdu_error_ratio(long mantissa, long exponent)
|
|
{
|
|
RANAP_SDU_ErrorRatio_t *err = CALLOC(1, sizeof(*err));
|
|
|
|
err->mantissa = mantissa;
|
|
err->exponent = exponent;
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
static RANAP_SDU_FormatInformationParameterItem_t *
|
|
new_format_info_pars(long sdu_size)
|
|
{
|
|
RANAP_SDU_FormatInformationParameterItem_t *fmti = CALLOC(1, sizeof(*fmti));
|
|
fmti->subflowSDU_Size = new_long(sdu_size);
|
|
return fmti;
|
|
}
|
|
|
|
enum sdu_par_profile {
|
|
SDUPAR_P_VOICE0,
|
|
SDUPAR_P_VOICE1,
|
|
SDUPAR_P_VOICE2,
|
|
SDUPAR_P_DATA,
|
|
};
|
|
|
|
/* See Chapter 5 of TS 26.102 */
|
|
static RANAP_SDU_ParameterItem_t *new_sdu_par_item(enum sdu_par_profile profile)
|
|
{
|
|
RANAP_SDU_ParameterItem_t *sdui = CALLOC(1, sizeof(*sdui));
|
|
RANAP_SDU_FormatInformationParameters_t *fmtip = CALLOC(1, sizeof(*fmtip));
|
|
RANAP_SDU_FormatInformationParameterItem_t *fmti;
|
|
|
|
switch (profile) {
|
|
case SDUPAR_P_VOICE0:
|
|
sdui->sDU_ErrorRatio = new_sdu_error_ratio(1, 5);
|
|
sdui->residualBitErrorRatio.mantissa = 1;
|
|
sdui->residualBitErrorRatio.exponent = 6;
|
|
sdui->deliveryOfErroneousSDU = RANAP_DeliveryOfErroneousSDU_yes;
|
|
sdui->sDU_FormatInformationParameters = fmtip;
|
|
fmti = new_format_info_pars(81);
|
|
ASN_SEQUENCE_ADD(fmtip, fmti);
|
|
fmti = new_format_info_pars(39);
|
|
ASN_SEQUENCE_ADD(fmtip, fmti);
|
|
/* FIXME: could be 10 SDU descriptors for AMR! */
|
|
break;
|
|
case SDUPAR_P_VOICE1:
|
|
sdui->residualBitErrorRatio.mantissa = 1;
|
|
sdui->residualBitErrorRatio.exponent = 3;
|
|
sdui->deliveryOfErroneousSDU = RANAP_DeliveryOfErroneousSDU_no_error_detection_consideration;
|
|
sdui->sDU_FormatInformationParameters = fmtip;
|
|
fmti = new_format_info_pars(103);
|
|
ASN_SEQUENCE_ADD(fmtip, fmti);
|
|
fmti = new_format_info_pars(0);
|
|
ASN_SEQUENCE_ADD(fmtip, fmti);
|
|
/* FIXME: could be 10 SDU descriptors for AMR! */
|
|
break;
|
|
case SDUPAR_P_VOICE2:
|
|
sdui->residualBitErrorRatio.mantissa = 5;
|
|
sdui->residualBitErrorRatio.exponent = 3;
|
|
sdui->deliveryOfErroneousSDU = RANAP_DeliveryOfErroneousSDU_no_error_detection_consideration;
|
|
sdui->sDU_FormatInformationParameters = fmtip;
|
|
fmti = new_format_info_pars(60);
|
|
ASN_SEQUENCE_ADD(fmtip, fmti);
|
|
fmti = new_format_info_pars(0);
|
|
ASN_SEQUENCE_ADD(fmtip, fmti);
|
|
/* FIXME: could be 10 SDU descriptors for AMR! */
|
|
break;
|
|
case SDUPAR_P_DATA:
|
|
sdui->sDU_ErrorRatio = new_sdu_error_ratio(1, 4);
|
|
sdui->residualBitErrorRatio.mantissa = 1;
|
|
sdui->residualBitErrorRatio.exponent = 5;
|
|
sdui->deliveryOfErroneousSDU = RANAP_DeliveryOfErroneousSDU_no;
|
|
FREEMEM(fmtip);
|
|
break;
|
|
}
|
|
|
|
return sdui;
|
|
}
|
|
|
|
static RANAP_AllocationOrRetentionPriority_t *
|
|
new_alloc_ret_prio(RANAP_PriorityLevel_t level, int capability, int vulnerability,
|
|
int queueing_allowed)
|
|
{
|
|
RANAP_AllocationOrRetentionPriority_t *arp = CALLOC(1, sizeof(*arp));
|
|
|
|
arp->priorityLevel = level;
|
|
|
|
if (capability)
|
|
arp->pre_emptionCapability = RANAP_Pre_emptionCapability_may_trigger_pre_emption;
|
|
else
|
|
arp->pre_emptionCapability = RANAP_Pre_emptionCapability_shall_not_trigger_pre_emption;
|
|
|
|
if (vulnerability)
|
|
arp->pre_emptionVulnerability = RANAP_Pre_emptionVulnerability_pre_emptable;
|
|
else
|
|
arp->pre_emptionVulnerability = RANAP_Pre_emptionVulnerability_not_pre_emptable;
|
|
|
|
if (queueing_allowed)
|
|
arp->queuingAllowed = RANAP_QueuingAllowed_queueing_allowed;
|
|
else
|
|
arp->queuingAllowed = RANAP_QueuingAllowed_queueing_not_allowed;
|
|
|
|
return arp;
|
|
}
|
|
|
|
/* See Chapter 5 of TS 26.102 */
|
|
static RANAP_RAB_Parameters_t *new_rab_par_voice(void)
|
|
{
|
|
RANAP_RAB_Parameters_t *rab = CALLOC(1, sizeof(*rab));
|
|
RANAP_SDU_ParameterItem_t *sdui;
|
|
|
|
rab->trafficClass = RANAP_TrafficClass_conversational;
|
|
rab->rAB_AsymmetryIndicator = RANAP_RAB_AsymmetryIndicator_symmetric_bidirectional;
|
|
|
|
ASN_SEQUENCE_ADD(&rab->maxBitrate.list, new_long(12200));
|
|
rab->guaranteedBitRate = CALLOC(1, sizeof(*rab->guaranteedBitRate));
|
|
ASN_SEQUENCE_ADD(rab->guaranteedBitRate, new_long(12200));
|
|
rab->deliveryOrder = RANAP_DeliveryOrder_delivery_order_requested;
|
|
rab->maxSDU_Size = 244;
|
|
|
|
sdui = new_sdu_par_item(SDUPAR_P_VOICE0);
|
|
ASN_SEQUENCE_ADD(&rab->sDU_Parameters, sdui);
|
|
sdui = new_sdu_par_item(SDUPAR_P_VOICE1);
|
|
ASN_SEQUENCE_ADD(&rab->sDU_Parameters, sdui);
|
|
sdui = new_sdu_par_item(SDUPAR_P_VOICE2);
|
|
ASN_SEQUENCE_ADD(&rab->sDU_Parameters, sdui);
|
|
|
|
rab->transferDelay = new_long(80);
|
|
rab->allocationOrRetentionPriority = new_alloc_ret_prio(RANAP_PriorityLevel_no_priority, 0, 1, 0);
|
|
|
|
rab->sourceStatisticsDescriptor = new_long(RANAP_SourceStatisticsDescriptor_speech);
|
|
|
|
return rab;
|
|
}
|
|
|
|
static RANAP_RAB_Parameters_t *new_rab_par_data(uint32_t dl_max_bitrate, uint32_t ul_max_bitrate)
|
|
{
|
|
RANAP_RAB_Parameters_t *rab = CALLOC(1, sizeof(*rab));
|
|
RANAP_SDU_ParameterItem_t *sdui;
|
|
|
|
rab->trafficClass = RANAP_TrafficClass_background;
|
|
rab->rAB_AsymmetryIndicator = RANAP_RAB_AsymmetryIndicator_asymmetric_bidirectional;
|
|
|
|
ASN_SEQUENCE_ADD(&rab->maxBitrate.list, new_long(dl_max_bitrate));
|
|
ASN_SEQUENCE_ADD(&rab->maxBitrate.list, new_long(ul_max_bitrate));
|
|
rab->deliveryOrder = RANAP_DeliveryOrder_delivery_order_requested;
|
|
rab->maxSDU_Size = 8000;
|
|
|
|
sdui = new_sdu_par_item(SDUPAR_P_DATA);
|
|
ASN_SEQUENCE_ADD(&rab->sDU_Parameters, sdui);
|
|
|
|
rab->allocationOrRetentionPriority = new_alloc_ret_prio(RANAP_PriorityLevel_no_priority, 0, 0, 0);
|
|
|
|
/* FIXME: RAB-Parameter-ExtendedMaxBitrateList for 42Mbps? */
|
|
|
|
return rab;
|
|
}
|
|
|
|
static void new_transp_layer_addr(BIT_STRING_t *out, uint32_t ip, int use_x213_nsap)
|
|
{
|
|
uint8_t *buf;
|
|
unsigned int len;
|
|
|
|
if (use_x213_nsap) {
|
|
len = 7;
|
|
buf = CALLOC(len, sizeof(uint8_t));
|
|
buf[0] = 0x35; /* AFI For IANA ICP */
|
|
buf[1] = 0x00; /* See A.5.2.1.2.7 of X.213 */
|
|
buf[2] = 0x01;
|
|
*(uint32_t *)&buf[3] = ntohl(ip);
|
|
} else {
|
|
len = 4;
|
|
buf = CALLOC(len, sizeof(uint8_t));
|
|
*(uint32_t *)buf = ip;
|
|
}
|
|
out->buf = buf;
|
|
out->size = len;
|
|
out->bits_unused = 0;
|
|
}
|
|
|
|
static RANAP_TransportLayerInformation_t *new_transp_info_rtp(uint32_t ip, uint16_t port)
|
|
{
|
|
RANAP_TransportLayerInformation_t *tli = CALLOC(1, sizeof(*tli));
|
|
uint8_t binding_id[4];
|
|
|
|
#if 0
|
|
binding_id[0] = port >> 8;
|
|
binding_id[1] = port & 0xff;
|
|
binding_id[2] = binding_id[3] = 0;
|
|
#else
|
|
binding_id[0] = binding_id[1] = binding_id[2] = 0;
|
|
binding_id[3] = 1;
|
|
#endif
|
|
|
|
new_transp_layer_addr(&tli->transportLayerAddress, ip, 1);
|
|
tli->iuTransportAssociation.present = RANAP_IuTransportAssociation_PR_bindingID;
|
|
OCTET_STRING_fromBuf(&tli->iuTransportAssociation.choice.bindingID,
|
|
(const char *) binding_id, sizeof(binding_id));
|
|
|
|
return tli;
|
|
}
|
|
|
|
static RANAP_TransportLayerInformation_t *new_transp_info_gtp(uint32_t ip, uint32_t tei)
|
|
{
|
|
RANAP_TransportLayerInformation_t *tli = CALLOC(1, sizeof(*tli));
|
|
uint32_t binding_buf = htonl(tei);
|
|
|
|
new_transp_layer_addr(&tli->transportLayerAddress, ip, 1);
|
|
tli->iuTransportAssociation.present = RANAP_IuTransportAssociation_PR_gTP_TEI;
|
|
OCTET_STRING_fromBuf(&tli->iuTransportAssociation.choice.gTP_TEI,
|
|
(const char *) &binding_buf, sizeof(binding_buf));
|
|
|
|
return tli;
|
|
}
|
|
|
|
static RANAP_UserPlaneInformation_t *new_upi(long mode, uint8_t mode_versions)
|
|
{
|
|
RANAP_UserPlaneInformation_t *upi = CALLOC(1, sizeof(*upi));
|
|
uint16_t *buf = CALLOC(1, sizeof(*buf));
|
|
|
|
*buf = ntohs(mode_versions);
|
|
|
|
upi->userPlaneMode = mode;
|
|
upi->uP_ModeVersions.buf = (uint8_t *) buf;
|
|
upi->uP_ModeVersions.size = sizeof(*buf);
|
|
upi->uP_ModeVersions.bits_unused = 0;
|
|
|
|
return upi;
|
|
}
|
|
|
|
|
|
static void assign_new_ra_id(RANAP_RAB_ID_t *id, uint8_t rab_id)
|
|
{
|
|
uint8_t *buf = CALLOC(1, sizeof(*buf));
|
|
*buf = rab_id;
|
|
|
|
id->buf = buf;
|
|
id->size = 1;
|
|
id->bits_unused = 0;
|
|
}
|
|
|
|
/*! \brief generate RANAP RAB ASSIGNMENT REQUEST message for CS (voice) */
|
|
struct msgb *ranap_new_msg_rab_assign_voice(uint8_t rab_id, uint32_t rtp_ip, uint16_t rtp_port)
|
|
{
|
|
RANAP_ProtocolIE_FieldPair_t *pair;
|
|
RANAP_RAB_AssignmentRequestIEs_t ies;
|
|
RANAP_RAB_AssignmentRequest_t out;
|
|
struct msgb *msg;
|
|
int rc;
|
|
|
|
memset(&ies, 0, sizeof(ies));
|
|
memset(&out, 0, sizeof(out));
|
|
|
|
/* only assingnment is present, no release */
|
|
ies.presenceMask = RAB_ASSIGNMENTREQUESTIES_RANAP_RAB_SETUPORMODIFYLIST_PRESENT;
|
|
|
|
/* put together the 'First' part */
|
|
RANAP_RAB_SetupOrModifyItemFirst_t first;
|
|
memset(&first, 0, sizeof(first));
|
|
assign_new_ra_id(&first.rAB_ID, rab_id);
|
|
//first.nAS_SynchronisationIndicator = FIXME;
|
|
first.rAB_Parameters = new_rab_par_voice();
|
|
first.userPlaneInformation = new_upi(RANAP_UserPlaneMode_support_mode_for_predefined_SDU_sizes, 1); /* 2? */
|
|
first.transportLayerInformation = new_transp_info_rtp(rtp_ip, rtp_port);
|
|
|
|
/* put together the 'Second' part */
|
|
RANAP_RAB_SetupOrModifyItemSecond_t second;
|
|
memset(&second, 0, sizeof(second));
|
|
|
|
/* Build an IE Pair out of first and second part:
|
|
* (first, second) -> pair */
|
|
pair = ranap_new_ie_pair(RANAP_ProtocolIE_ID_id_RAB_SetupOrModifyItem,
|
|
RANAP_Criticality_reject,
|
|
&asn_DEF_RANAP_RAB_SetupOrModifyItemFirst, &first,
|
|
RANAP_Criticality_ignore,
|
|
&asn_DEF_RANAP_RAB_SetupOrModifyItemSecond, &second);
|
|
|
|
/* the pair has been made, we can release any of its elements */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifyItemFirst, &first);
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifyItemSecond, &second);
|
|
|
|
RANAP_ProtocolIE_ContainerPair_t *container_pair = CALLOC(1, sizeof(*container_pair));
|
|
/* Add the pair to the list of IEs of the RAB ass.req */
|
|
ASN_SEQUENCE_ADD(container_pair, pair);
|
|
ASN_SEQUENCE_ADD(&ies.raB_SetupOrModifyList.list, container_pair);
|
|
|
|
/* encode the IEs into the actual assignment request:
|
|
* ies -> out */
|
|
rc = ranap_encode_rab_assignmentrequesties(&out, &ies);
|
|
/* 'out' has been generated, we can now release the input */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifyList,
|
|
&ies.raB_SetupOrModifyList);
|
|
if (rc < 0)
|
|
return NULL;
|
|
|
|
/* generate an Initiating Mesasage: out -> msg */
|
|
msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_RAB_Assignment,
|
|
RANAP_Criticality_reject,
|
|
&asn_DEF_RANAP_RAB_AssignmentRequest, &out);
|
|
|
|
/* 'msg' has been generated, we cann now release the input 'out' */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_AssignmentRequest, &out);
|
|
|
|
return msg;
|
|
}
|
|
|
|
/*! \brief generate RANAP RAB ASSIGNMENT REQUEST message for PS (data) */
|
|
struct msgb *ranap_new_msg_rab_assign_data(uint8_t rab_id, uint32_t gtp_ip, uint32_t gtp_tei)
|
|
{
|
|
RANAP_ProtocolIE_FieldPair_t *pair;
|
|
RANAP_RAB_AssignmentRequestIEs_t ies;
|
|
RANAP_RAB_AssignmentRequest_t out;
|
|
RANAP_DataVolumeReportingIndication_t *dat_vol_ind;
|
|
struct msgb *msg;
|
|
int rc;
|
|
|
|
memset(&ies, 0, sizeof(ies));
|
|
memset(&out, 0, sizeof(out));
|
|
|
|
/* only assingnment is present, no release */
|
|
ies.presenceMask = RAB_ASSIGNMENTREQUESTIES_RANAP_RAB_SETUPORMODIFYLIST_PRESENT;
|
|
|
|
/* put together the 'First' part */
|
|
RANAP_RAB_SetupOrModifyItemFirst_t first;
|
|
memset(&first, 0, sizeof(first));
|
|
assign_new_ra_id(&first.rAB_ID, rab_id);
|
|
//first.nAS_SynchronisationIndicator = FIXME;
|
|
|
|
first.rAB_Parameters = new_rab_par_data(1600000, 800000);
|
|
first.userPlaneInformation = new_upi(RANAP_UserPlaneMode_transparent_mode, 1);
|
|
first.transportLayerInformation = new_transp_info_gtp(gtp_ip, gtp_tei);
|
|
|
|
/* put together the 'Second' part */
|
|
RANAP_RAB_SetupOrModifyItemSecond_t second;
|
|
memset(&second, 0, sizeof(second));
|
|
second.pDP_TypeInformation = CALLOC(1, sizeof(*second.pDP_TypeInformation));
|
|
ASN_SEQUENCE_ADD(second.pDP_TypeInformation, new_long(RANAP_PDP_Type_ipv4));
|
|
dat_vol_ind = CALLOC(1, sizeof(*dat_vol_ind));
|
|
*dat_vol_ind = RANAP_DataVolumeReportingIndication_do_not_report;
|
|
second.dataVolumeReportingIndication = dat_vol_ind;
|
|
second.dl_GTP_PDU_SequenceNumber = new_long(0);
|
|
second.ul_GTP_PDU_SequenceNumber = new_long(0);
|
|
|
|
/* Build an IE Pair out of first and second part:
|
|
* (first, second) -> pair */
|
|
pair = ranap_new_ie_pair(RANAP_ProtocolIE_ID_id_RAB_SetupOrModifyItem,
|
|
RANAP_Criticality_reject,
|
|
&asn_DEF_RANAP_RAB_SetupOrModifyItemFirst,
|
|
&first, RANAP_Criticality_ignore,
|
|
&asn_DEF_RANAP_RAB_SetupOrModifyItemSecond,
|
|
&second);
|
|
|
|
/* the pair has been made, we can release any of its elements */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifyItemFirst, &first);
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifyItemSecond, &second);
|
|
|
|
RANAP_ProtocolIE_ContainerPair_t *container_pair = CALLOC(1, sizeof(*container_pair));
|
|
/* Add the pair to the list of IEs of the RAB ass.req */
|
|
ASN_SEQUENCE_ADD(container_pair, pair);
|
|
/* Add the pair to the list of IEs of the RAB ass.req */
|
|
ASN_SEQUENCE_ADD(&ies.raB_SetupOrModifyList.list, container_pair);
|
|
|
|
/* encode the IEs into the actual assignment request:
|
|
* ies -> out */
|
|
rc = ranap_encode_rab_assignmentrequesties(&out, &ies);
|
|
/* 'out' has been generated, we can now release the input */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifyList,
|
|
&ies.raB_SetupOrModifyList);
|
|
if (rc < 0)
|
|
return NULL;
|
|
|
|
/* generate an Initiating Mesasage: out -> msg */
|
|
msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_RAB_Assignment,
|
|
RANAP_Criticality_reject,
|
|
&asn_DEF_RANAP_RAB_AssignmentRequest, &out);
|
|
|
|
/* 'msg' has been generated, we cann now release the input 'out' */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_AssignmentRequest, &out);
|
|
|
|
return msg;
|
|
}
|
|
|
|
struct msgb *ranap_new_msg_iu_rel_req(const RANAP_Cause_t *cause)
|
|
{
|
|
RANAP_Iu_ReleaseRequestIEs_t ies;
|
|
RANAP_Iu_ReleaseRequest_t out;
|
|
struct msgb *msg;
|
|
int rc;
|
|
|
|
memset(&ies, 0, sizeof(ies));
|
|
memset(&out, 0, sizeof(out));
|
|
|
|
memcpy(&ies.cause, cause, sizeof(ies.cause));
|
|
|
|
rc = ranap_encode_iu_releaserequesties(&out, &ies);
|
|
if (rc < 0)
|
|
return NULL;
|
|
|
|
/* encode the output into the msgb */
|
|
msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_Iu_ReleaseRequest,
|
|
RANAP_Criticality_reject,
|
|
&asn_DEF_RANAP_Iu_ReleaseRequest, &out);
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_Iu_ReleaseRequest, &out);
|
|
|
|
return msg;
|
|
}
|
|
|
|
struct msgb *ranap_new_msg_rab_rel_req(uint8_t rab_id, const RANAP_Cause_t *cause)
|
|
{
|
|
RANAP_RAB_ReleaseItemIEs_t item_ies;
|
|
RANAP_RAB_ReleaseRequestIEs_t ies;
|
|
RANAP_RAB_ReleaseRequest_t out;
|
|
struct msgb *msg;
|
|
int rc;
|
|
|
|
memset(&item_ies, 0, sizeof(item_ies));
|
|
memset(&ies, 0, sizeof(ies));
|
|
memset(&out, 0, sizeof(out));
|
|
|
|
/* put together the ReleaseItem */
|
|
assign_new_ra_id(&item_ies.raB_ReleaseItem.rAB_ID, rab_id);
|
|
memcpy(&item_ies.raB_ReleaseItem.cause, cause, sizeof(item_ies.raB_ReleaseItem.cause));
|
|
|
|
/* add to the list */
|
|
rc = ranap_encode_rab_releaseitemies(&ies.raB_ReleaseList, &item_ies);
|
|
if (rc < 0)
|
|
return NULL;
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_ReleaseItem, &item_ies.raB_ReleaseItem);
|
|
|
|
/* encoe the list IEs into the output */
|
|
rc = ranap_encode_rab_releaserequesties(&out, &ies);
|
|
if (rc < 0)
|
|
return NULL;
|
|
/* 'out' has been generated, we can release the input */
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_ReleaseList, &ies.raB_ReleaseList);
|
|
|
|
/* encode the output into the msgb */
|
|
msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_RAB_ReleaseRequest,
|
|
RANAP_Criticality_reject,
|
|
&asn_DEF_RANAP_RAB_ReleaseRequest, &out);
|
|
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_ReleaseRequest, &out);
|
|
|
|
return msg;
|
|
}
|