/* hnb-gw specific code for RANAP */ /* (C) 2015 by Harald Welte * 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 . * */ #include #include #include #include #include #include "asn1helpers.h" #include #include #include #include #include static int ranap_tx_reset_ack(struct hnb_context *hnb, RANAP_CN_DomainIndicator_t domain) { struct msgb *msg; int rc; msg = ranap_new_msg_reset_ack(domain, NULL); if (!msg) return -1; rc = rua_tx_udt(hnb, msg->data, msgb_length(msg)); msgb_free(msg); return rc; } static int ranap_rx_init_reset(struct hnb_context *hnb, ANY_t *in) { RANAP_ResetIEs_t ies; int rc, is_ps = 0; rc = ranap_decode_reseties(&ies, in); if (rc < 0) return rc; if (ies.cN_DomainIndicator == RANAP_CN_DomainIndicator_ps_domain) is_ps=1; LOGHNB(hnb, DRANAP, LOGL_INFO, "Rx RESET.req(%s,%s)\n", is_ps ? "ps" : "cs", ranap_cause_str(&ies.cause)); /* FIXME: Actually we have to wait for some guard time? */ /* FIXME: Reset all resources related to this HNB/RNC */ ranap_tx_reset_ack(hnb, ies.cN_DomainIndicator); return 0; } static int ranap_rx_error_ind(struct hnb_context *hnb, ANY_t *in) { RANAP_ErrorIndicationIEs_t ies; int rc; rc = ranap_decode_errorindicationies(&ies, in); if (rc < 0) return rc; if (ies.presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT) { LOGHNB(hnb, DRANAP, LOGL_ERROR, "Rx ERROR.ind(%s)\n", ranap_cause_str(&ies.cause)); } else LOGHNB(hnb, DRANAP, LOGL_ERROR, "Rx ERROR.ind\n"); return 0; } static int ranap_rx_initiating_msg(struct hnb_context *hnb, RANAP_InitiatingMessage_t *imsg) { int rc = 0; /* according tot the spec, we can primarily receive Overload, * Reset, Reset ACK, Error Indication, reset Resource, Reset * Resurce Acknowledge as connecitonless RANAP. There are some * more messages regarding Information Transfer, Direct * Information Transfer and Uplink Information Trnansfer that we * can ignore. In either case, it is RANAP that we need to * decode... */ switch (imsg->procedureCode) { case RANAP_ProcedureCode_id_Reset: /* Reset request */ rc = ranap_rx_init_reset(hnb, &imsg->value); break; case RANAP_ProcedureCode_id_OverloadControl: /* Overload ind */ break; case RANAP_ProcedureCode_id_ErrorIndication: /* Error ind */ rc = ranap_rx_error_ind(hnb, &imsg->value); break; case RANAP_ProcedureCode_id_ResetResource: /* request */ case RANAP_ProcedureCode_id_InformationTransfer: case RANAP_ProcedureCode_id_DirectInformationTransfer: case RANAP_ProcedureCode_id_UplinkInformationExchange: LOGHNB(hnb, DRANAP, LOGL_NOTICE, "Received unsupported RANAP " "Procedure %lu from HNB, ignoring\n", imsg->procedureCode); break; default: LOGHNB(hnb, DRANAP, LOGL_NOTICE, "Received suspicious RANAP " "Procedure %lu from HNB, ignoring\n", imsg->procedureCode); break; } return rc; } static int ranap_rx_successful_msg(struct hnb_context *hnb, RANAP_SuccessfulOutcome_t *imsg) { /* according tot the spec, we can primarily receive Overload, * Reset, Reset ACK, Error Indication, reset Resource, Reset * Resurce Acknowledge as connecitonless RANAP. There are some * more messages regarding Information Transfer, Direct * Information Transfer and Uplink Information Trnansfer that we * can ignore. In either case, it is RANAP that we need to * decode... */ switch (imsg->procedureCode) { case RANAP_ProcedureCode_id_Reset: /* Reset acknowledge */ break; case RANAP_ProcedureCode_id_ResetResource: /* response */ case RANAP_ProcedureCode_id_InformationTransfer: case RANAP_ProcedureCode_id_DirectInformationTransfer: case RANAP_ProcedureCode_id_UplinkInformationExchange: LOGHNB(hnb, DRANAP, LOGL_NOTICE, "Received unsupported RANAP " "Procedure %lu from HNB, ignoring\n", imsg->procedureCode); break; default: LOGHNB(hnb, DRANAP, LOGL_NOTICE, "Received suspicious RANAP " "Procedure %lu from HNB, ignoring\n", imsg->procedureCode); break; } return 0; } static int _hnbgw_ranap_rx(struct hnb_context *hnb, RANAP_RANAP_PDU_t *pdu) { int rc = 0; switch (pdu->present) { case RANAP_RANAP_PDU_PR_initiatingMessage: rc = ranap_rx_initiating_msg(hnb, &pdu->choice.initiatingMessage); break; case RANAP_RANAP_PDU_PR_successfulOutcome: rc = ranap_rx_successful_msg(hnb, &pdu->choice.successfulOutcome); break; case RANAP_RANAP_PDU_PR_unsuccessfulOutcome: LOGHNB(hnb, DRANAP, LOGL_NOTICE, "Received unsupported RANAP " "unsuccessful outcome procedure %lu from HNB, ignoring\n", pdu->choice.unsuccessfulOutcome.procedureCode); break; default: LOGHNB(hnb, DRANAP, LOGL_NOTICE, "Received suspicious RANAP " "presence %u from HNB, ignoring\n", pdu->present); break; } return rc; } int hnbgw_ranap_rx(struct msgb *msg, uint8_t *data, size_t len) { RANAP_RANAP_PDU_t _pdu, *pdu = &_pdu; struct hnb_context *hnb = msg->dst; asn_dec_rval_t dec_ret; int rc; memset(pdu, 0, sizeof(*pdu)); dec_ret = aper_decode(NULL,&asn_DEF_RANAP_RANAP_PDU, (void **) &pdu, data, len, 0, 0); if (dec_ret.code != RC_OK) { LOGHNB(hnb, DRANAP, LOGL_ERROR, "Error in RANAP ASN.1 decode\n"); return -1; } rc = _hnbgw_ranap_rx(hnb, pdu); return rc; } int hnbgw_ranap_init(void) { return 0; }