#include #include #include #include #include #include "asn1helpers.h" #include "hnbap.h" #include "hnbgw.h" #include "hnbap_const.h" #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; } 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() { #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 /* FIXME */ /* Single required response IE: RNC-ID */ } /* 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. */ #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) { int i; /* iterate over the array of IEs in the IE container and look for the first * occurrence of the right IEI */ for (i = 0; i < cont->count; i++) { 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; } } return NULL; } static int hnbgw_rx_hnb_register_req(struct hnb_context *ctx, struct HNBRegisterRequest *req) { HNB_Identity *identity = FIND_IE(&req->protocolIEs, HNBAP_IEI_HNB_Identity); HNB_Location_Information *loc = FIND_IE(&req->protocolIEs, HNBAP_IEI_HNB_Location_Information); PLMNidentity *plmn_id = FIND_IE(&req->protocolIEs, HNBAP_IEI_PLMNidentity); CellIdentity *cell_id = 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); /* Optional: CSG-ID */ if(!identity || !loc || !plmn_id || !cell_id || !lac || !rac || !sac) return -1; /* copy all identity parameters from the message to ctx */ asn1_strncpy(ctx->identity_info, &identity->hNB_Identity_Info, sizeof(ctx->identity_info)); 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); //ctx->id.mcc FIXME //ctx->id.mnc FIXME DEBUGP(DMAIN, "HNB-REGISTER-REQ from %s\n", ctx->identity_info); /* FIXME: Send HNBRegisterAccept */ } static int hnbgw_rx_ue_register_req(struct hnb_context *ctx, struct UERegisterRequest *req) { UE_Identity *id = FIND_IE(&req->protocolIEs, HNBAP_IEI_UE_Identity); Registration_Cause *reg_cause = FIND_IE(&req->protocolIEs, HNBAP_IEI_RegistrationCause); UE_Capabilities *ue_cap = FIND_IE(&req->protocolIEs, HNBAP_IEI_UE_Capabilities); if (!id || !reg_cause || !ue_cap) return -1; /* FIXME: Send UERegisterAccept */ } static int hnbgw_rx_initiating_msg(struct hnb_context *hnb, struct InitiatingMessage *imsg) { int rc; switch (imsg->procedureCode) { case HNBAP_PC_HNBRegister: /* 8.2 */ if (imsg->value.type != asn1_type_HNBRegisterRequest) return -1; rc = hnbgw_rx_hnb_register_req(hnb, imsg->value.u.data); break; case HNBAP_PC_HNBDe_Register: /* 8.3 */ break; case HNBAP_PC_UERegister: /* 8.4 */ if (imsg->value.type != asn1_type_UERegisterRequest) return -1; rc = hnbgw_rx_ue_register_req(hnb, imsg->value.u.data); 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; } } static int hnbgw_rx_successful_outcome_msg(struct hnb_context *hnb, struct SuccessfulOutcome *msg) { } static int hnbgw_rx_unsuccessful_outcome_msg(struct hnb_context *hnb, struct UnsuccessfulOutcome *msg) { } static int _hnbgw_hnbap_rx(struct hnb_context *hnb, struct HNBAP_PDU *pdu) { int rc; /* 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: rc = hnbgw_rx_initiating_msg(hnb, &pdu->u.initiatingMessage); break; case HNBAP_PDU_successfulOutcome: rc = hnbgw_rx_successful_outcome_msg(hnb, &pdu->u.successfulOutcome); break; case HNBAP_PDU_unsuccessfulOutcome: rc = hnbgw_rx_unsuccessful_outcome_msg(hnb, &pdu->u.unsuccessfulOutcome); break; default: return -1; } } int hnbgw_hnbap_rx(struct hnb_context *hnb, struct msgb *msg) { 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; } int hnbgw_hnbap_init(void) { }