diff options
Diffstat (limited to 'openbsc/src/nat/bsc_nat.c')
-rw-r--r-- | openbsc/src/nat/bsc_nat.c | 88 |
1 files changed, 79 insertions, 9 deletions
diff --git a/openbsc/src/nat/bsc_nat.c b/openbsc/src/nat/bsc_nat.c index 6485102df..738b7ef39 100644 --- a/openbsc/src/nat/bsc_nat.c +++ b/openbsc/src/nat/bsc_nat.c @@ -303,6 +303,63 @@ static void bsc_send_data(struct bsc_connection *bsc, const uint8_t *data, unsig bsc_write(bsc, msg, proto); } +/* + * Release an established connection. We will have to release it to the BSC + * and to the network and we do it the following way. + * 1.) Give up on the MSC side + * 1.1) Send a RLSD message, it is a bit non standard but should work, we + * ignore the RLC... we might complain about it. Other options would + * be to send a Release Request, handle the Release Complete.. + * 1.2) Mark the data structure to be con_local and wait for 2nd + * + * 2.) Give up on the BSC side + * 2.1) Depending on the con type reject the service, or just close it + */ +static void bsc_send_con_release(struct bsc_connection *bsc, struct sccp_connections *con) +{ + struct msgb *rlsd; + /* 1. release the network */ + rlsd = sccp_create_rlsd(&con->patched_ref, &con->remote_ref, + SCCP_RELEASE_CAUSE_END_USER_ORIGINATED); + if (!rlsd) + LOGP(DNAT, LOGL_ERROR, "Failed to create RLSD message.\n"); + else { + ipaccess_prepend_header(rlsd, IPAC_PROTO_SCCP); + queue_for_msc(con->msc_con, rlsd); + } + con->con_local = 1; + + /* 2. release the BSC side */ + if (con->con_type == NAT_CON_TYPE_LU) { + struct msgb *payload, *udt; + payload = gsm48_create_loc_upd_rej(GSM48_REJECT_PLMN_NOT_ALLOWED); + + if (payload) { + gsm0808_prepend_dtap_header(payload, 0); + udt = sccp_create_dt1(&con->real_ref, payload->data, payload->len); + if (udt) + bsc_write(bsc, udt, IPAC_PROTO_SCCP); + else + LOGP(DNAT, LOGL_ERROR, "Failed to create DT1\n"); + + msgb_free(payload); + } else { + LOGP(DNAT, LOGL_ERROR, "Failed to allocate LU Reject.\n"); + } + } + + rlsd = sccp_create_rlsd(&con->remote_ref, &con->real_ref, + SCCP_RELEASE_CAUSE_END_USER_ORIGINATED); + if (!rlsd) { + LOGP(DNAT, LOGL_ERROR, "Failed to allocate RLSD for the BSC.\n"); + sccp_connection_destroy(con); + return; + } + + con->con_type = NAT_CON_TYPE_LOCAL_REJECT; + bsc_write(bsc, rlsd, IPAC_PROTO_SCCP); +} + static void bsc_send_con_refuse(struct bsc_connection *bsc, struct bsc_nat_parsed *parsed, int con_type) { @@ -708,10 +765,12 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg) /* modify the SCCP entries */ if (parsed->ipa_proto == IPAC_PROTO_SCCP) { + int filter; struct sccp_connections *con; switch (parsed->sccp_type) { case SCCP_MSG_TYPE_CR: - if (bsc_nat_filter_sccp_cr(bsc, msg, parsed, &con_type) != 0) + filter = bsc_nat_filter_sccp_cr(bsc, msg, parsed, &con_type); + if (filter < 0) goto exit3; if (!create_sccp_src_ref(bsc, parsed)) goto exit2; @@ -719,6 +778,7 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg) con->msc_con = bsc->nat->msc_con; con_msc = con->msc_con; con->con_type = con_type; + con->imsi_checked = filter; con_bsc = con->bsc; break; case SCCP_MSG_TYPE_RLSD: @@ -728,9 +788,16 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg) case SCCP_MSG_TYPE_IT: con = patch_sccp_src_ref_to_msc(msg, parsed, bsc); if (con) { - con_bsc = con->bsc; - con_msc = con->msc_con; - con_filter = con->con_local; + filter = bsc_nat_filter_dt(bsc, msg, con, parsed); + if (filter == 0) { + con_bsc = con->bsc; + con_msc = con->msc_con; + con_filter = con->con_local; + } else { + bsc_send_con_release(bsc, con); + con = NULL; + goto exit2; + } } break; case SCCP_MSG_TYPE_RLC: @@ -766,15 +833,18 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg) goto exit2; } - if (!con_msc) { - LOGP(DNAT, LOGL_ERROR, "No connection found, dropping data.\n"); - goto exit2; - } - /* do not forward messages to the MSC */ if (con_filter) goto exit2; + if (!con_msc) { + LOGP(DNAT, LOGL_ERROR, "Not forwarding data bsc_nr: %d ipa: %d type: 0x%x\n", + bsc->cfg->nr, + parsed ? parsed->ipa_proto : -1, + parsed ? parsed->sccp_type : -1); + goto exit2; + } + /* send the non-filtered but maybe modified msg */ queue_for_msc(con_msc, msg); talloc_free(parsed); |