2015-08-29 18:33:16 +00:00
|
|
|
#include <osmocom/core/msgb.h>
|
2015-08-30 10:20:09 +00:00
|
|
|
#include <osmocom/core/utils.h>
|
2015-08-29 18:33:16 +00:00
|
|
|
|
2015-08-30 10:20:09 +00:00
|
|
|
#include <unistd.h>
|
2015-08-30 14:57:53 +00:00
|
|
|
#include <errno.h>
|
2015-08-30 10:20:09 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
2015-08-30 10:28:29 +00:00
|
|
|
#include "asn1helpers.h"
|
|
|
|
|
2015-08-30 10:20:09 +00:00
|
|
|
#include "hnbap.h"
|
2015-08-29 18:33:16 +00:00
|
|
|
#include "hnbgw.h"
|
|
|
|
#include "hnbap_const.h"
|
|
|
|
|
2015-08-30 14:57:53 +00:00
|
|
|
#define IU_MSG_NUM_IES 32
|
|
|
|
#define IU_MSG_NUM_EXT_IES 32
|
|
|
|
|
|
|
|
/* common structure of a HNBAP / RUA / RANAP message, must have identical
|
|
|
|
* memory footprint as the other messages, such as HNBRegisterRequest */
|
|
|
|
struct iu_common_msg {
|
|
|
|
ProtocolIE_Container_1 protocolIEs;
|
|
|
|
BOOL protocolExtensions_option;
|
|
|
|
ProtocolIE_Container_1 protocolExtensions;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Add an IE to a Iu message
|
|
|
|
* \param _msg Message to which we want to add
|
|
|
|
* \param[in] ie Information Element to be added (ffasn1c generated struct)
|
|
|
|
* \param[in] iei Information Element Identifier
|
|
|
|
* \param[in] type asn1_type of the IE
|
|
|
|
* \param[in] ext should this be an extension field?
|
|
|
|
*/
|
|
|
|
int iu_msg_add_ie(void *_msg, void *ie, int iei, ASN1CType *type, int ext)
|
|
|
|
{
|
|
|
|
struct iu_common_msg *msg = _msg;
|
|
|
|
ProtocolIE_Field_1 *field;
|
|
|
|
|
|
|
|
if (ext) {
|
|
|
|
msg->protocolExtensions_option = TRUE;
|
|
|
|
if (msg->protocolExtensions.count >= IU_MSG_NUM_EXT_IES)
|
|
|
|
return -ERANGE;
|
|
|
|
field = &msg->protocolExtensions.tab[msg->protocolExtensions.count++];
|
|
|
|
} else {
|
|
|
|
if (msg->protocolIEs.count >= IU_MSG_NUM_IES)
|
|
|
|
return -ERANGE;
|
|
|
|
field = &msg->protocolIEs.tab[msg->protocolIEs.count++];
|
|
|
|
}
|
|
|
|
|
|
|
|
field->id = iei;
|
|
|
|
//field->criticality = FIXME;
|
|
|
|
field->value.type = type;
|
|
|
|
field->value.u.data = ie;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-30 10:20:09 +00:00
|
|
|
|
2015-08-29 18:33:16 +00:00
|
|
|
static int hnbgw_hnbap_tx(struct HNBAP_PDU *pdu)
|
|
|
|
{
|
|
|
|
/* FIXME */
|
|
|
|
}
|
|
|
|
|
|
|
|
static int hnbgw_tx_hnb_register_acc()
|
|
|
|
{
|
|
|
|
/* FIXME */
|
|
|
|
/* Single required response IE: RNC-ID */
|
|
|
|
}
|
|
|
|
|
|
|
|
static int hnbgw_tx_ue_register_acc()
|
|
|
|
{
|
2015-08-30 14:57:53 +00:00
|
|
|
#if 0
|
|
|
|
HNBAP_PDU pdu;
|
|
|
|
HNBRegisterAccept hnb_reg_acc;
|
|
|
|
|
|
|
|
hnb_reg_acc.protocol_IEs
|
|
|
|
|
|
|
|
pdu.choice = HNBAP_PDU_successfulOutcome;
|
|
|
|
pdu.u.successfulOutcome.procedureCode = HNBAP_PC_HNBRegister;
|
|
|
|
pdu.u.successfulOutcome.criticality = ;
|
|
|
|
pdu.u.successfulOutcome.value.type = asn1_type_HNBRegisterAccept;
|
|
|
|
pdu.u.successfulOutcome.value.u.data = &hnb_reg_acc;
|
|
|
|
#endif
|
2015-08-29 18:33:16 +00:00
|
|
|
/* FIXME */
|
|
|
|
/* Single required response IE: RNC-ID */
|
|
|
|
}
|
|
|
|
|
2015-08-30 14:57:53 +00:00
|
|
|
/* we type-cast to ProtocolIE_Container_1, as all the containers structs have
|
|
|
|
* the same definiition. This is of course ugly, but I see no cleaner way.
|
|
|
|
* Similarly, from the IEI it is clear what the type should be, but in a
|
|
|
|
* statically typed language we can only return 'void *' and hope the caller
|
|
|
|
* doesn the right typecast. */
|
2015-08-30 10:20:09 +00:00
|
|
|
#define FIND_IE(cont, id) find_ie((const struct ProtocolIE_Container_1 *)cont, id)
|
|
|
|
static void *find_ie(const struct ProtocolIE_Container_1 *cont, ProtocolIE_ID id)
|
2015-08-29 18:33:16 +00:00
|
|
|
{
|
2015-08-30 10:20:09 +00:00
|
|
|
int i;
|
|
|
|
|
2015-08-30 14:57:53 +00:00
|
|
|
/* iterate over the array of IEs in the IE container and look for the first
|
|
|
|
* occurrence of the right IEI */
|
2015-08-29 18:33:16 +00:00
|
|
|
for (i = 0; i < cont->count; i++) {
|
2015-08-30 10:20:09 +00:00
|
|
|
ProtocolIE_Field_1 *field = &cont->tab[i];
|
|
|
|
if (field->id == id) {
|
|
|
|
OSMO_ASSERT(field->value.type);
|
|
|
|
/* FIXME: we shoudl check if it is the correct type, not just any type */
|
|
|
|
return field->value.u.data;
|
|
|
|
}
|
2015-08-29 18:33:16 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-08-29 19:47:39 +00:00
|
|
|
static int hnbgw_rx_hnb_register_req(struct hnb_context *ctx, struct HNBRegisterRequest *req)
|
2015-08-29 18:33:16 +00:00
|
|
|
{
|
|
|
|
HNB_Identity *identity =
|
2015-08-30 10:20:09 +00:00
|
|
|
FIND_IE(&req->protocolIEs, HNBAP_IEI_HNB_Identity);
|
2015-08-29 18:33:16 +00:00
|
|
|
HNB_Location_Information *loc =
|
2015-08-30 10:20:09 +00:00
|
|
|
FIND_IE(&req->protocolIEs, HNBAP_IEI_HNB_Location_Information);
|
2015-08-29 18:33:16 +00:00
|
|
|
PLMNidentity *plmn_id =
|
2015-08-30 10:20:09 +00:00
|
|
|
FIND_IE(&req->protocolIEs, HNBAP_IEI_PLMNidentity);
|
2015-08-29 18:33:16 +00:00
|
|
|
CellIdentity *cell_id =
|
2015-08-30 10:20:09 +00:00
|
|
|
FIND_IE(&req->protocolIEs, HNBAP_IEI_CellIdentity);
|
|
|
|
LAC *lac = FIND_IE(&req->protocolIEs, HNBAP_IEI_LAC);
|
|
|
|
RAC *rac = FIND_IE(&req->protocolIEs, HNBAP_IEI_RAC);
|
|
|
|
SAC *sac = FIND_IE(&req->protocolIEs, HNBAP_IEI_SAC);
|
2015-08-29 18:33:16 +00:00
|
|
|
/* Optional: CSG-ID */
|
|
|
|
|
|
|
|
if(!identity || !loc || !plmn_id || !cell_id || !lac || !rac || !sac)
|
|
|
|
return -1;
|
|
|
|
|
2015-08-29 19:47:39 +00:00
|
|
|
/* copy all identity parameters from the message to ctx */
|
2015-08-30 10:28:29 +00:00
|
|
|
asn1_strncpy(ctx->identity_info, &identity->hNB_Identity_Info,
|
2015-08-30 10:20:09 +00:00
|
|
|
sizeof(ctx->identity_info));
|
2015-08-29 19:47:39 +00:00
|
|
|
ctx->id.lac = asn1str_to_u16(lac);
|
|
|
|
ctx->id.sac = asn1str_to_u16(sac);
|
|
|
|
ctx->id.rac = asn1str_to_u8(rac);
|
|
|
|
ctx->id.cid = asn1bitstr_to_u32(cell_id);
|
2015-08-30 10:20:09 +00:00
|
|
|
//ctx->id.mcc FIXME
|
|
|
|
//ctx->id.mnc FIXME
|
2015-08-29 19:47:39 +00:00
|
|
|
|
2015-08-30 14:57:53 +00:00
|
|
|
DEBUGP(DMAIN, "HNB-REGISTER-REQ from %s\n", ctx->identity_info);
|
|
|
|
|
2015-08-29 18:33:16 +00:00
|
|
|
/* FIXME: Send HNBRegisterAccept */
|
|
|
|
}
|
|
|
|
|
2015-08-29 19:47:39 +00:00
|
|
|
static int hnbgw_rx_ue_register_req(struct hnb_context *ctx, struct UERegisterRequest *req)
|
2015-08-29 18:33:16 +00:00
|
|
|
{
|
|
|
|
UE_Identity *id =
|
2015-08-30 10:20:09 +00:00
|
|
|
FIND_IE(&req->protocolIEs, HNBAP_IEI_UE_Identity);
|
2015-08-29 18:33:16 +00:00
|
|
|
Registration_Cause *reg_cause =
|
2015-08-30 10:20:09 +00:00
|
|
|
FIND_IE(&req->protocolIEs, HNBAP_IEI_RegistrationCause);
|
2015-08-29 18:33:16 +00:00
|
|
|
UE_Capabilities *ue_cap =
|
2015-08-30 10:20:09 +00:00
|
|
|
FIND_IE(&req->protocolIEs, HNBAP_IEI_UE_Capabilities);
|
2015-08-29 18:33:16 +00:00
|
|
|
|
|
|
|
if (!id || !reg_cause || !ue_cap)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* FIXME: Send UERegisterAccept */
|
|
|
|
}
|
|
|
|
|
2015-08-30 10:20:09 +00:00
|
|
|
static int hnbgw_rx_initiating_msg(struct hnb_context *hnb, struct InitiatingMessage *imsg)
|
2015-08-29 18:33:16 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
2015-08-30 10:20:09 +00:00
|
|
|
switch (imsg->procedureCode) {
|
2015-08-29 18:33:16 +00:00
|
|
|
case HNBAP_PC_HNBRegister: /* 8.2 */
|
2015-08-30 10:20:09 +00:00
|
|
|
if (imsg->value.type != asn1_type_HNBRegisterRequest)
|
2015-08-29 18:33:16 +00:00
|
|
|
return -1;
|
2015-08-30 10:20:09 +00:00
|
|
|
rc = hnbgw_rx_hnb_register_req(hnb, imsg->value.u.data);
|
2015-08-29 18:33:16 +00:00
|
|
|
break;
|
|
|
|
case HNBAP_PC_HNBDe_Register: /* 8.3 */
|
|
|
|
break;
|
|
|
|
case HNBAP_PC_UERegister: /* 8.4 */
|
2015-08-30 10:20:09 +00:00
|
|
|
if (imsg->value.type != asn1_type_UERegisterRequest)
|
2015-08-29 18:33:16 +00:00
|
|
|
return -1;
|
2015-08-30 10:20:09 +00:00
|
|
|
rc = hnbgw_rx_ue_register_req(hnb, imsg->value.u.data);
|
2015-08-29 18:33:16 +00:00
|
|
|
break;
|
|
|
|
case HNBAP_PC_UEDe_Register: /* 8.5 */
|
|
|
|
break;
|
|
|
|
case HNBAP_PC_ErrorIndication: /* 8.6 */
|
|
|
|
case HNBAP_PC_TNLUpdate: /* 8.9 */
|
|
|
|
case HNBAP_PC_HNBConfigTransfer: /* 8.10 */
|
|
|
|
case HNBAP_PC_RelocationComplete: /* 8.11 */
|
|
|
|
case HNBAP_PC_U_RNTIQuery: /* 8.12 */
|
|
|
|
case HNBAP_PC_privateMessage:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-30 10:20:09 +00:00
|
|
|
static int hnbgw_rx_successful_outcome_msg(struct hnb_context *hnb, struct SuccessfulOutcome *msg)
|
2015-08-29 18:33:16 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-08-30 10:20:09 +00:00
|
|
|
static int hnbgw_rx_unsuccessful_outcome_msg(struct hnb_context *hnb, struct UnsuccessfulOutcome *msg)
|
2015-08-29 18:33:16 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-29 19:47:39 +00:00
|
|
|
static int _hnbgw_hnbap_rx(struct hnb_context *hnb, struct HNBAP_PDU *pdu)
|
2015-08-29 18:33:16 +00:00
|
|
|
{
|
2015-08-30 10:20:09 +00:00
|
|
|
int rc;
|
|
|
|
|
2015-08-29 18:33:16 +00:00
|
|
|
/* it's a bit odd that we can't dispatch on procedure code, but
|
|
|
|
* that's not possible */
|
|
|
|
switch (pdu->choice) {
|
|
|
|
case HNBAP_PDU_initiatingMessage:
|
2015-08-30 10:20:09 +00:00
|
|
|
rc = hnbgw_rx_initiating_msg(hnb, &pdu->u.initiatingMessage);
|
2015-08-29 18:33:16 +00:00
|
|
|
break;
|
|
|
|
case HNBAP_PDU_successfulOutcome:
|
2015-08-30 10:20:09 +00:00
|
|
|
rc = hnbgw_rx_successful_outcome_msg(hnb, &pdu->u.successfulOutcome);
|
2015-08-29 18:33:16 +00:00
|
|
|
break;
|
|
|
|
case HNBAP_PDU_unsuccessfulOutcome:
|
2015-08-30 10:20:09 +00:00
|
|
|
rc = hnbgw_rx_unsuccessful_outcome_msg(hnb, &pdu->u.unsuccessfulOutcome);
|
2015-08-29 18:33:16 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-29 19:47:39 +00:00
|
|
|
int hnbgw_hnbap_rx(struct hnb_context *hnb, struct msgb *msg)
|
2015-08-29 18:33:16 +00:00
|
|
|
{
|
2015-08-30 14:57:53 +00:00
|
|
|
HNBAP_PDU *pdu;
|
|
|
|
ASN1Error err;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/* decode and handle to _hnbgw_hnbap_rx() */
|
|
|
|
|
|
|
|
rc = asn1_aper_decode(&pdu, asn1_type_HNBAP_PDU, msg->data, msgb_length(msg), &err);
|
|
|
|
if (rc < 0) {
|
|
|
|
LOGP(DMAIN, LOGL_ERROR, "Error in ASN.1 decode (bit=%d): %s\n", err.bit_pos, err.msg);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = _hnbgw_hnbap_rx(hnb, pdu);
|
|
|
|
asn1_free_value(asn1_type_HNBAP_PDU, pdu);
|
|
|
|
|
|
|
|
return rc;
|
2015-08-29 18:33:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int hnbgw_hnbap_init(void)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|