aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bsc_nat
diff options
context:
space:
mode:
Diffstat (limited to 'src/osmo-bsc_nat')
-rw-r--r--src/osmo-bsc_nat/Makefile.am61
-rw-r--r--src/osmo-bsc_nat/bsc_filter.c218
-rw-r--r--src/osmo-bsc_nat/bsc_mgcp_utils.c1151
-rw-r--r--src/osmo-bsc_nat/bsc_nat.c1739
-rw-r--r--src/osmo-bsc_nat/bsc_nat_ctrl.c525
-rw-r--r--src/osmo-bsc_nat/bsc_nat_filter.c119
-rw-r--r--src/osmo-bsc_nat/bsc_nat_rewrite.c714
-rw-r--r--src/osmo-bsc_nat/bsc_nat_rewrite_trie.c259
-rw-r--r--src/osmo-bsc_nat/bsc_nat_utils.c535
-rw-r--r--src/osmo-bsc_nat/bsc_nat_vty.c1336
-rw-r--r--src/osmo-bsc_nat/bsc_sccp.c247
-rw-r--r--src/osmo-bsc_nat/bsc_ussd.c454
12 files changed, 0 insertions, 7358 deletions
diff --git a/src/osmo-bsc_nat/Makefile.am b/src/osmo-bsc_nat/Makefile.am
deleted file mode 100644
index 1eec7aa1c..000000000
--- a/src/osmo-bsc_nat/Makefile.am
+++ /dev/null
@@ -1,61 +0,0 @@
-AM_CPPFLAGS = \
- $(all_includes) \
- -I$(top_srcdir)/include \
- -I$(top_builddir) \
- $(NULL)
-
-AM_CFLAGS = \
- -Wall \
- $(LIBOSMOCORE_CFLAGS) \
- $(LIBOSMOGSM_CFLAGS) \
- $(LIBOSMOVTY_CFLAGS) \
- $(LIBOSMOCTRL_CFLAGS) \
- $(LIBOSMOSCCP_CFLAGS) \
- $(LIBOSMOABIS_CFLAGS) \
- $(LIBOSMONETIF_CFLAGS) \
- $(LIBOSMOLEGACYMGCP_CFLAGS) \
- $(LIBCRYPTO_CFLAGS) \
- $(COVERAGE_CFLAGS) \
- $(NULL)
-
-AM_LDFLAGS = \
- $(COVERAGE_LDFLAGS) \
- $(NULL)
-
-bin_PROGRAMS = \
- osmo-bsc_nat \
- $(NULL)
-
-osmo_bsc_nat_SOURCES = \
- bsc_filter.c \
- bsc_mgcp_utils.c \
- bsc_nat.c \
- bsc_nat_utils.c \
- bsc_nat_vty.c \
- bsc_sccp.c \
- bsc_ussd.c \
- bsc_nat_ctrl.c \
- bsc_nat_rewrite.c \
- bsc_nat_rewrite_trie.c \
- bsc_nat_filter.c \
- $(NULL)
-
-osmo_bsc_nat_LDADD = \
- $(top_builddir)/src/libfilter/libfilter.a \
- $(top_builddir)/src/libbsc/libbsc.a \
- $(top_builddir)/src/libcommon-cs/libcommon-cs.a \
- $(top_builddir)/src/libtrau/libtrau.a \
- $(top_builddir)/src/libcommon/libcommon.a \
- $(LIBOSMOSCCP_LIBS) \
- $(LIBOSMOCORE_LIBS) \
- $(LIBOSMOGSM_LIBS) \
- $(LIBOSMOVTY_LIBS) \
- $(LIBOSMOCTRL_LIBS) \
- $(LIBOSMOABIS_LIBS) \
- $(LIBOSMONETIF_LIBS) \
- $(LIBOSMOSIGTRAN_LIBS) \
- $(LIBOSMOLEGACYMGCP_LIBS) \
- $(LIBCRYPTO_LIBS) \
- $(LIBRARY_GSM) \
- -lrt \
- $(NULL)
diff --git a/src/osmo-bsc_nat/bsc_filter.c b/src/osmo-bsc_nat/bsc_filter.c
deleted file mode 100644
index 6a9e99fb8..000000000
--- a/src/osmo-bsc_nat/bsc_filter.c
+++ /dev/null
@@ -1,218 +0,0 @@
-/* BSC Multiplexer/NAT */
-
-/*
- * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010 by On-Waves
- * 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 <openbsc/bsc_nat.h>
-#include <openbsc/bsc_nat_sccp.h>
-#include <openbsc/ipaccess.h>
-#include <openbsc/debug.h>
-
-#include <osmocom/core/talloc.h>
-#include <osmocom/gsm/protocol/gsm_08_08.h>
-
-#include <osmocom/sccp/sccp.h>
-
-/*
- * The idea is to have a simple struct describing a IPA packet with
- * SCCP SSN and the GSM 08.08 payload and decide. We will both have
- * a white and a blacklist of packets we want to handle.
- *
- * TODO: Implement a "NOT" in the filter language.
- */
-
-#define ALLOW_ANY -1
-
-#define FILTER_TO_BSC 1
-#define FILTER_TO_MSC 2
-#define FILTER_TO_BOTH 3
-
-
-struct bsc_pkt_filter {
- int ipa_proto;
- int dest_ssn;
- int bssap;
- int gsm;
- int filter_dir;
-};
-
-static struct bsc_pkt_filter black_list[] = {
- /* filter reset messages to the MSC */
- { IPAC_PROTO_SCCP, SCCP_SSN_BSSAP, 0, BSS_MAP_MSG_RESET, FILTER_TO_MSC },
-
- /* filter reset ack messages to the BSC */
- { IPAC_PROTO_SCCP, SCCP_SSN_BSSAP, 0, BSS_MAP_MSG_RESET_ACKNOWLEDGE, FILTER_TO_BSC },
-
- /* filter ip access */
- { IPAC_PROTO_IPACCESS, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_MSC },
-};
-
-static struct bsc_pkt_filter white_list[] = {
- /* allow IPAC_PROTO_SCCP messages to both sides */
- { IPAC_PROTO_SCCP, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_BOTH },
-
- /* allow MGCP messages to both sides */
- { IPAC_PROTO_MGCP_OLD, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_BOTH },
-};
-
-struct bsc_nat_parsed *bsc_nat_parse(struct msgb *msg)
-{
- struct sccp_parse_result result;
- struct bsc_nat_parsed *parsed;
- struct ipaccess_head *hh;
-
- /* quick fail */
- if (msg->len < 4)
- return NULL;
-
- parsed = talloc_zero(msg, struct bsc_nat_parsed);
- if (!parsed)
- return NULL;
-
- /* more init */
- parsed->ipa_proto = parsed->called_ssn = parsed->calling_ssn = -1;
- parsed->sccp_type = parsed->bssap = parsed->gsm_type = -1;
-
- /* start parsing */
- hh = (struct ipaccess_head *) msg->data;
- parsed->ipa_proto = hh->proto;
-
- msg->l2h = &hh->data[0];
-
- /* do a size check on the input */
- if (ntohs(hh->len) != msgb_l2len(msg)) {
- LOGP(DLINP, LOGL_ERROR, "Wrong input length?\n");
- talloc_free(parsed);
- return NULL;
- }
-
- /* analyze sccp down here */
- if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
- memset(&result, 0, sizeof(result));
- if (sccp_parse_header(msg, &result) != 0) {
- talloc_free(parsed);
- return 0;
- }
-
- if (msg->l3h && msgb_l3len(msg) < 3) {
- LOGP(DNAT, LOGL_ERROR, "Not enough space or GSM payload\n");
- talloc_free(parsed);
- return 0;
- }
-
- parsed->sccp_type = sccp_determine_msg_type(msg);
- parsed->src_local_ref = result.source_local_reference;
- parsed->dest_local_ref = result.destination_local_reference;
- if (parsed->dest_local_ref)
- parsed->original_dest_ref = *parsed->dest_local_ref;
- parsed->called_ssn = result.called.ssn;
- parsed->calling_ssn = result.calling.ssn;
-
- /* in case of connection confirm we have no payload */
- if (msg->l3h) {
- parsed->bssap = msg->l3h[0];
- parsed->gsm_type = msg->l3h[2];
- }
- }
-
- return parsed;
-}
-
-int bsc_nat_filter_ipa(int dir, struct msgb *msg, struct bsc_nat_parsed *parsed)
-{
- int i;
-
- /* go through the blacklist now */
- for (i = 0; i < ARRAY_SIZE(black_list); ++i) {
- /* ignore the rule? */
- if (black_list[i].filter_dir != FILTER_TO_BOTH
- && black_list[i].filter_dir != dir)
- continue;
-
- /* the proto is not blacklisted */
- if (black_list[i].ipa_proto != ALLOW_ANY
- && black_list[i].ipa_proto != parsed->ipa_proto)
- continue;
-
- if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
- /* the SSN is not blacklisted */
- if (black_list[i].dest_ssn != ALLOW_ANY
- && black_list[i].dest_ssn != parsed->called_ssn)
- continue;
-
- /* bssap */
- if (black_list[i].bssap != ALLOW_ANY
- && black_list[i].bssap != parsed->bssap)
- continue;
-
- /* gsm */
- if (black_list[i].gsm != ALLOW_ANY
- && black_list[i].gsm != parsed->gsm_type)
- continue;
-
- /* blacklisted */
- LOGP(DNAT, LOGL_INFO, "Blacklisted with rule %d\n", i);
- return 1;
- } else {
- /* blacklisted, we have no content sniffing yet */
- LOGP(DNAT, LOGL_INFO, "Blacklisted with rule %d\n", i);
- return 1;
- }
- }
-
- /* go through the whitelust now */
- for (i = 0; i < ARRAY_SIZE(white_list); ++i) {
- /* ignore the rule? */
- if (white_list[i].filter_dir != FILTER_TO_BOTH
- && white_list[i].filter_dir != dir)
- continue;
-
- /* the proto is not whitelisted */
- if (white_list[i].ipa_proto != ALLOW_ANY
- && white_list[i].ipa_proto != parsed->ipa_proto)
- continue;
-
- if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
- /* the SSN is not whitelisted */
- if (white_list[i].dest_ssn != ALLOW_ANY
- && white_list[i].dest_ssn != parsed->called_ssn)
- continue;
-
- /* bssap */
- if (white_list[i].bssap != ALLOW_ANY
- && white_list[i].bssap != parsed->bssap)
- continue;
-
- /* gsm */
- if (white_list[i].gsm != ALLOW_ANY
- && white_list[i].gsm != parsed->gsm_type)
- continue;
-
- /* whitelisted */
- LOGP(DNAT, LOGL_INFO, "Whitelisted with rule %d\n", i);
- return 0;
- } else {
- /* whitelisted */
- return 0;
- }
- }
-
- return 1;
-}
diff --git a/src/osmo-bsc_nat/bsc_mgcp_utils.c b/src/osmo-bsc_nat/bsc_mgcp_utils.c
deleted file mode 100644
index 49050fc89..000000000
--- a/src/osmo-bsc_nat/bsc_mgcp_utils.c
+++ /dev/null
@@ -1,1151 +0,0 @@
-/**
- * This file contains helper routines for MGCP Gateway handling.
- *
- * The first thing to remember is that each BSC has its own namespace/range
- * of endpoints. Whenever a BSSMAP ASSIGNMENT REQUEST is received this code
- * will be called to select an endpoint on the BSC. The mapping from original
- * multiplex/timeslot to BSC multiplex'/timeslot' will be stored.
- *
- * The second part is to take messages on the public MGCP GW interface
- * and forward them to the right BSC. This requires the MSC to first
- * assign the timeslot. This assumption has been true so far. We are using
- * the policy_cb of the MGCP protocol code to decide if the request should
- * be immediately answered or delayed. An extension "Z: noanswer" is used
- * to request the BSC to not respond. This is saving some bytes of bandwidth
- * and as we are using TCP to forward the message we know it will arrive.
- * The mgcp_do_read method reads these messages and hands them to the protocol
- * parsing code which will call the mentioned policy_cb. The bsc_mgcp_forward
- * method is used on the way back from the BSC to the network.
- *
- * The third part is to patch messages forwarded to the BSC. This includes
- * the endpoint number, the ports to be used inside the SDP file and maybe
- * some other bits.
- *
- */
-/*
- * (C) 2010-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010-2012 by On-Waves
- * 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 <openbsc/bsc_nat.h>
-#include <openbsc/bsc_nat_callstats.h>
-#include <openbsc/bsc_nat_sccp.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/debug.h>
-#include <openbsc/ipaccess.h>
-#include <osmocom/legacy_mgcp/mgcp.h>
-#include <osmocom/legacy_mgcp/mgcp_internal.h>
-#include <openbsc/osmux.h>
-
-#include <osmocom/ctrl/control_cmd.h>
-
-#include <osmocom/sccp/sccp.h>
-
-#include <osmocom/core/talloc.h>
-#include <osmocom/gsm/gsm0808.h>
-#include <osmocom/gsm/protocol/gsm_08_08.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <errno.h>
-#include <unistd.h>
-
-static void send_direct(struct bsc_nat *nat, struct msgb *output)
-{
- if (osmo_wqueue_enqueue(&nat->mgcp_cfg->gw_fd, output) != 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to queue MGCP msg.\n");
- msgb_free(output);
- }
-}
-
-static void mgcp_queue_for_call_agent(struct bsc_nat *nat, struct msgb *output)
-{
- if (nat->mgcp_ipa)
- bsc_nat_send_mgcp_to_msc(nat, output);
- else
- send_direct(nat, output);
-}
-
-int bsc_mgcp_nr_multiplexes(int max_endpoints)
-{
- int div = max_endpoints / 32;
-
- if ((max_endpoints % 32) != 0)
- div += 1;
-
- return div;
-}
-
-static int bsc_init_endps_if_needed(struct bsc_connection *con)
-{
- int multiplexes;
-
- /* we have done that */
- if (con->_endpoint_status)
- return 0;
-
- /* we have no config... */
- if (!con->cfg)
- return -1;
-
- multiplexes = bsc_mgcp_nr_multiplexes(con->cfg->max_endpoints);
- con->number_multiplexes = multiplexes;
- con->max_endpoints = con->cfg->max_endpoints;
- con->_endpoint_status = talloc_zero_array(con, char, 32 * multiplexes + 1);
- return con->_endpoint_status == NULL;
-}
-
-static int bsc_assign_endpoint(struct bsc_connection *bsc, struct nat_sccp_connection *con)
-{
- int multiplex;
- int timeslot;
- const int number_endpoints = bsc->max_endpoints;
- int i;
-
- mgcp_endpoint_to_timeslot(bsc->last_endpoint, &multiplex, &timeslot);
- timeslot += 1;
-
- for (i = 0; i < number_endpoints; ++i) {
- int endpoint;
-
- /* Wrap around timeslots */
- if (timeslot == 0)
- timeslot = 1;
-
- if (timeslot == 0x1f) {
- timeslot = 1;
- multiplex += 1;
- }
-
- /* Wrap around the multiplex */
- if (multiplex >= bsc->number_multiplexes)
- multiplex = 0;
-
- endpoint = mgcp_timeslot_to_endpoint(multiplex, timeslot);
-
- /* Now check if we are allowed to assign this one */
- if (endpoint >= bsc->max_endpoints) {
- multiplex = 0;
- timeslot = 1;
- endpoint = mgcp_timeslot_to_endpoint(multiplex, timeslot);
- }
-
-
- if (bsc->_endpoint_status[endpoint] == 0) {
- bsc->_endpoint_status[endpoint] = 1;
- con->bsc_endp = endpoint;
- bsc->last_endpoint = endpoint;
- return 0;
- }
-
- timeslot += 1;
- }
-
- return -1;
-}
-
-static uint16_t create_cic(int endpoint)
-{
- int timeslot, multiplex;
-
- mgcp_endpoint_to_timeslot(endpoint, &multiplex, &timeslot);
- return (multiplex << 5) | (timeslot & 0x1f);
-}
-
-int bsc_mgcp_assign_patch(struct nat_sccp_connection *con, struct msgb *msg)
-{
- struct nat_sccp_connection *mcon;
- struct tlv_parsed tp;
- uint16_t cic;
- uint8_t timeslot;
- uint8_t multiplex;
- unsigned int endp;
-
- if (!msg->l3h) {
- LOGP(DNAT, LOGL_ERROR, "Assignment message should have l3h pointer.\n");
- return -1;
- }
-
- if (msgb_l3len(msg) < 3) {
- LOGP(DNAT, LOGL_ERROR, "Assignment message has not enough space for GSM0808.\n");
- return -1;
- }
-
- tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0);
- if (!TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) {
- LOGP(DNAT, LOGL_ERROR, "Circuit identity code not found in assignment message.\n");
- return -1;
- }
-
- cic = ntohs(tlvp_val16_unal(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE));
- timeslot = cic & 0x1f;
- multiplex = (cic & ~0x1f) >> 5;
-
-
- endp = mgcp_timeslot_to_endpoint(multiplex, timeslot);
-
- if (endp >= con->bsc->nat->mgcp_cfg->trunk.number_endpoints) {
- LOGP(DNAT, LOGL_ERROR,
- "MSC attempted to assign bad endpoint 0x%x\n",
- endp);
- return -1;
- }
-
- /* find stale connections using that endpoint */
- llist_for_each_entry(mcon, &con->bsc->nat->sccp_connections, list_entry) {
- if (mcon->msc_endp == endp) {
- LOGP(DNAT, LOGL_ERROR,
- "Endpoint %d was assigned to 0x%x and now 0x%x\n",
- endp,
- sccp_src_ref_to_int(&mcon->patched_ref),
- sccp_src_ref_to_int(&con->patched_ref));
- bsc_mgcp_dlcx(mcon);
- }
- }
-
- con->msc_endp = endp;
- if (bsc_init_endps_if_needed(con->bsc) != 0)
- return -1;
- if (bsc_assign_endpoint(con->bsc, con) != 0)
- return -1;
-
- /*
- * now patch the message for the new CIC...
- * still assumed to be one multiplex only
- */
- cic = htons(create_cic(con->bsc_endp));
- memcpy((uint8_t *) TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE),
- &cic, sizeof(cic));
-
- return 0;
-}
-
-static void bsc_mgcp_free_endpoint(struct bsc_nat *nat, int i)
-{
- if (nat->bsc_endpoints[i].transaction_id) {
- talloc_free(nat->bsc_endpoints[i].transaction_id);
- nat->bsc_endpoints[i].transaction_id = NULL;
- }
-
- nat->bsc_endpoints[i].transaction_state = 0;
- nat->bsc_endpoints[i].bsc = NULL;
-}
-
-void bsc_mgcp_free_endpoints(struct bsc_nat *nat)
-{
- int i;
-
- for (i = 1; i < nat->mgcp_cfg->trunk.number_endpoints; ++i){
- bsc_mgcp_free_endpoint(nat, i);
- mgcp_release_endp(&nat->mgcp_cfg->trunk.endpoints[i]);
- }
-}
-
-/* send a MDCX where we do not want a response */
-static void bsc_mgcp_send_mdcx(struct bsc_connection *bsc, int port, struct mgcp_endpoint *endp)
-{
- char buf[2096];
- int len;
-
- len = snprintf(buf, sizeof(buf),
- "MDCX 23 %x@mgw MGCP 1.0\r\n"
- "Z: noanswer\r\n"
- "\r\n"
- "c=IN IP4 %s\r\n"
- "m=audio %d RTP/AVP 255\r\n",
- port, mgcp_bts_src_addr(endp),
- endp->bts_end.local_port);
- if (len < 0) {
- LOGP(DMGCP, LOGL_ERROR, "snprintf for MDCX failed.\n");
- return;
- }
-
- bsc_write_mgcp(bsc, (uint8_t *) buf, len);
-}
-
-static void bsc_mgcp_send_dlcx(struct bsc_connection *bsc, int endpoint, int trans)
-{
- char buf[2096];
- int len;
-
- /*
- * The following is a bit of a spec violation. According to the
- * MGCP grammar the transaction id is are upto 9 digits but we
- * prefix it with an alpha numeric value so we can easily recognize
- * it as a response.
- */
- len = snprintf(buf, sizeof(buf),
- "DLCX nat-%u %x@mgw MGCP 1.0\r\n",
- trans, endpoint);
- if (len < 0) {
- LOGP(DMGCP, LOGL_ERROR, "snprintf for DLCX failed.\n");
- return;
- }
-
- bsc_write_mgcp(bsc, (uint8_t *) buf, len);
-}
-
-void bsc_mgcp_init(struct nat_sccp_connection *con)
-{
- con->msc_endp = -1;
- con->bsc_endp = -1;
-}
-
-/**
- * This code will remember the network side of the audio statistics and
- * once the internal DLCX response arrives this can be combined with the
- * the BSC side and forwarded as a trap.
- */
-static void remember_pending_dlcx(struct nat_sccp_connection *con, uint32_t transaction)
-{
- struct bsc_nat_call_stats *stats;
- struct bsc_connection *bsc = con->bsc;
- struct mgcp_endpoint *endp;
-
- stats = talloc_zero(bsc, struct bsc_nat_call_stats);
- if (!stats) {
- LOGP(DNAT, LOGL_NOTICE,
- "Failed to allocate statistics for endpoint 0x%x\n",
- con->msc_endp);
- return;
- }
-
- /* take the endpoint here */
- endp = &bsc->nat->mgcp_cfg->trunk.endpoints[con->msc_endp];
-
- stats->remote_ref = con->remote_ref;
- stats->src_ref = con->patched_ref;
-
- stats->ci = endp->ci;
- stats->bts_rtp_port = endp->bts_end.rtp_port;
- stats->bts_addr = endp->bts_end.addr;
- stats->net_rtp_port = endp->net_end.rtp_port;
- stats->net_addr = endp->net_end.addr;
-
- stats->net_ps = endp->net_end.packets;
- stats->net_os = endp->net_end.octets;
- stats->bts_pr = endp->bts_end.packets;
- stats->bts_or = endp->bts_end.octets;
- mgcp_state_calc_loss(&endp->bts_state, &endp->bts_end,
- &stats->bts_expected, &stats->bts_loss);
- stats->bts_jitter = mgcp_state_calc_jitter(&endp->bts_state);
-
- stats->trans_id = transaction;
- stats->msc_endpoint = con->msc_endp;
-
- /*
- * Too many pending requests.. let's remove the first two items.
- */
- if (!llist_empty(&bsc->pending_dlcx) &&
- bsc->pending_dlcx_count >= bsc->cfg->max_endpoints * 3) {
- struct bsc_nat_call_stats *tmp;
- LOGP(DNAT, LOGL_ERROR,
- "Too many(%d) pending DLCX responses on BSC: %d\n",
- bsc->pending_dlcx_count, bsc->cfg->nr);
- bsc->pending_dlcx_count -= 1;
- tmp = (struct bsc_nat_call_stats *) bsc->pending_dlcx.next;
- llist_del(&tmp->entry);
- talloc_free(tmp);
- }
-
- bsc->pending_dlcx_count += 1;
- llist_add_tail(&stats->entry, &bsc->pending_dlcx);
-}
-
-void bsc_mgcp_dlcx(struct nat_sccp_connection *con)
-{
- /* send a DLCX down the stream */
- if (con->bsc_endp != -1 && con->bsc->_endpoint_status) {
- LOGP(DNAT, LOGL_NOTICE,
- "Endpoint 0x%x was allocated for bsc: %d. Freeing it.\n",
- con->bsc_endp, con->bsc->cfg->nr);
- if (con->bsc->_endpoint_status[con->bsc_endp] != 1)
- LOGP(DNAT, LOGL_ERROR, "Endpoint 0x%x was not in use\n", con->bsc_endp);
- remember_pending_dlcx(con, con->bsc->next_transaction);
- con->bsc->_endpoint_status[con->bsc_endp] = 0;
- bsc_mgcp_send_dlcx(con->bsc, con->bsc_endp, con->bsc->next_transaction++);
- bsc_mgcp_free_endpoint(con->bsc->nat, con->msc_endp);
- }
-
- bsc_mgcp_init(con);
-
-}
-
-/*
- * Search for the pending request
- */
-static void handle_dlcx_response(struct bsc_connection *bsc, struct msgb *msg,
- int code, const char *transaction)
-{
- uint32_t trans_id = UINT32_MAX;
- uint32_t b_ps, b_os, n_pr, n_or, jitter;
- int loss;
- struct bsc_nat_call_stats *tmp, *stat = NULL;
- struct ctrl_cmd *cmd;
-
- /* parse the transaction identifier */
- int rc = sscanf(transaction, "nat-%u", &trans_id);
- if (rc != 1) {
- LOGP(DNAT, LOGL_ERROR, "Can not parse transaction id: '%s'\n",
- transaction);
- return;
- }
-
- /* find the answer for the request we made */
- llist_for_each_entry(tmp, &bsc->pending_dlcx, entry) {
- if (trans_id != tmp->trans_id)
- continue;
-
- stat = tmp;
- break;
- }
-
- if (!stat) {
- LOGP(DNAT, LOGL_ERROR,
- "Can not find transaction for: %u\n", trans_id);
- return;
- }
-
- /* attempt to parse the data now */
- rc = mgcp_parse_stats(msg, &b_ps, &b_os, &n_pr, &n_or, &loss, &jitter);
- if (rc != 0)
- LOGP(DNAT, LOGL_ERROR,
- "Can not parse connection statistics: %d\n", rc);
-
- /* send a trap now */
- cmd = ctrl_cmd_create(bsc, CTRL_TYPE_TRAP);
- if (!cmd) {
- LOGP(DNAT, LOGL_ERROR,
- "Creating a ctrl cmd failed.\n");
- goto free_stat;
- }
-
- cmd->id = "0";
- cmd->variable = talloc_asprintf(cmd, "net.0.bsc.%d.call_stats.v2",
- bsc->cfg->nr);
- cmd->reply = talloc_asprintf(cmd,
- "mg_ip_addr=%s,mg_port=%d,",
- inet_ntoa(stat->net_addr),
- stat->net_rtp_port);
- cmd->reply = talloc_asprintf_append(cmd->reply,
- "endpoint_ip_addr=%s,endpoint_port=%d,",
- inet_ntoa(stat->bts_addr),
- stat->bts_rtp_port);
- cmd->reply = talloc_asprintf_append(cmd->reply,
- "nat_pkt_in=%u,nat_pkt_out=%u,"
- "nat_bytes_in=%u,nat_bytes_out=%u,"
- "nat_jitter=%u,nat_pkt_lost=%d,",
- stat->bts_pr, stat->net_ps,
- stat->bts_or, stat->net_os,
- stat->bts_jitter, stat->bts_loss);
- cmd->reply = talloc_asprintf_append(cmd->reply,
- "bsc_pkt_in=%u,bsc_pkt_out=%u,"
- "bsc_bytes_in=%u,bsc_bytes_out=%u,"
- "bsc_jitter=%u,bsc_pkt_lost=%d,",
- n_pr, b_ps,
- n_or, b_os,
- jitter, loss);
- cmd->reply = talloc_asprintf_append(cmd->reply,
- "sccp_src_ref=%u,sccp_dst_ref=%u",
- sccp_src_ref_to_int(&stat->src_ref),
- sccp_src_ref_to_int(&stat->remote_ref));
-
- /* send it and be done */
- ctrl_cmd_send_to_all(bsc->nat->ctrl, cmd);
- talloc_free(cmd);
-
-free_stat:
- bsc->pending_dlcx_count -= 1;
- llist_del(&stat->entry);
- talloc_free(stat);
-}
-
-
-struct nat_sccp_connection *bsc_mgcp_find_con(struct bsc_nat *nat, int endpoint)
-{
- struct nat_sccp_connection *con = NULL;
- struct nat_sccp_connection *sccp;
-
- llist_for_each_entry(sccp, &nat->sccp_connections, list_entry) {
- if (sccp->msc_endp == -1)
- continue;
- if (sccp->msc_endp != endpoint)
- continue;
-
- con = sccp;
- }
-
- if (con)
- return con;
-
- LOGP(DMGCP, LOGL_ERROR,
- "Failed to find the connection for endpoint: 0x%x\n", endpoint);
- return NULL;
-}
-
-static int nat_osmux_only(struct mgcp_config *mgcp_cfg, struct bsc_config *bsc_cfg)
-{
- if (mgcp_cfg->osmux == OSMUX_USAGE_ONLY)
- return 1;
- if (bsc_cfg->osmux == OSMUX_USAGE_ONLY)
- return 1;
- return 0;
-}
-
-static int bsc_mgcp_policy_cb(struct mgcp_trunk_config *tcfg, int endpoint, int state, const char *transaction_id)
-{
- struct bsc_nat *nat;
- struct bsc_endpoint *bsc_endp;
- struct nat_sccp_connection *sccp;
- struct mgcp_endpoint *mgcp_endp;
- struct msgb *bsc_msg;
-
- nat = tcfg->cfg->data;
- bsc_endp = &nat->bsc_endpoints[endpoint];
- mgcp_endp = &nat->mgcp_cfg->trunk.endpoints[endpoint];
-
- if (bsc_endp->transaction_id) {
- LOGP(DMGCP, LOGL_ERROR, "Endpoint 0x%x had pending transaction: '%s'\n",
- endpoint, bsc_endp->transaction_id);
- talloc_free(bsc_endp->transaction_id);
- bsc_endp->transaction_id = NULL;
- bsc_endp->transaction_state = 0;
- }
- bsc_endp->bsc = NULL;
-
- sccp = bsc_mgcp_find_con(nat, endpoint);
-
- if (!sccp) {
- LOGP(DMGCP, LOGL_ERROR, "Did not find BSC for change on endpoint: 0x%x state: %d\n", endpoint, state);
-
- switch (state) {
- case MGCP_ENDP_CRCX:
- return MGCP_POLICY_REJECT;
- break;
- case MGCP_ENDP_DLCX:
- return MGCP_POLICY_CONT;
- break;
- case MGCP_ENDP_MDCX:
- return MGCP_POLICY_CONT;
- break;
- default:
- LOGP(DMGCP, LOGL_FATAL, "Unhandled state: %d\n", state);
- return MGCP_POLICY_CONT;
- break;
- }
- }
-
- /* Allocate a Osmux circuit ID */
- if (state == MGCP_ENDP_CRCX) {
- if (nat->mgcp_cfg->osmux && sccp->bsc->cfg->osmux) {
- osmux_allocate_cid(mgcp_endp);
- if (mgcp_endp->osmux.allocated_cid < 0 &&
- nat_osmux_only(nat->mgcp_cfg, sccp->bsc->cfg)) {
- LOGP(DMGCP, LOGL_ERROR,
- "Rejecting usage of endpoint\n");
- return MGCP_POLICY_REJECT;
- }
- }
- }
-
- /* we need to generate a new and patched message */
- bsc_msg = bsc_mgcp_rewrite((char *) nat->mgcp_msg, nat->mgcp_length,
- sccp->bsc_endp, mgcp_bts_src_addr(mgcp_endp),
- mgcp_endp->bts_end.local_port,
- mgcp_endp->osmux.allocated_cid,
- &mgcp_endp->net_end.codec.payload_type,
- nat->sdp_ensure_amr_mode_set);
- if (!bsc_msg) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to patch the msg.\n");
- return MGCP_POLICY_CONT;
- }
-
-
- bsc_endp->transaction_id = talloc_strdup(nat, transaction_id);
- bsc_endp->transaction_state = state;
- bsc_endp->bsc = sccp->bsc;
-
- /* we need to update some bits */
- if (state == MGCP_ENDP_CRCX) {
- struct sockaddr_in sock;
-
- /* Annotate the allocated Osmux CID until the bsc confirms that
- * it agrees to use Osmux for this voice flow.
- */
- if (mgcp_endp->osmux.allocated_cid >= 0 &&
- mgcp_endp->osmux.state != OSMUX_STATE_ENABLED) {
- mgcp_endp->osmux.state = OSMUX_STATE_NEGOTIATING;
- mgcp_endp->osmux.cid = mgcp_endp->osmux.allocated_cid;
- }
-
- socklen_t len = sizeof(sock);
- if (getpeername(sccp->bsc->write_queue.bfd.fd, (struct sockaddr *) &sock, &len) != 0) {
- LOGP(DMGCP, LOGL_ERROR, "Can not get the peername...%d/%s\n",
- errno, strerror(errno));
- } else {
- mgcp_endp->bts_end.addr = sock.sin_addr;
- }
-
- /* send the message and a fake MDCX to force sending of a dummy packet */
- bsc_write(sccp->bsc, bsc_msg, IPAC_PROTO_MGCP_OLD);
- bsc_mgcp_send_mdcx(sccp->bsc, sccp->bsc_endp, mgcp_endp);
- return MGCP_POLICY_DEFER;
- } else if (state == MGCP_ENDP_DLCX) {
- /* we will free the endpoint now and send a DLCX to the BSC */
- msgb_free(bsc_msg);
- bsc_mgcp_dlcx(sccp);
-
- /* libmgcp clears the MGCP endpoint for us */
- if (mgcp_endp->osmux.state == OSMUX_STATE_ENABLED)
- osmux_release_cid(mgcp_endp);
-
- return MGCP_POLICY_CONT;
- } else {
- bsc_write(sccp->bsc, bsc_msg, IPAC_PROTO_MGCP_OLD);
- return MGCP_POLICY_DEFER;
- }
-}
-
-/*
- * We do have a failure, free data downstream..
- */
-static void free_chan_downstream(struct mgcp_endpoint *endp, struct bsc_endpoint *bsc_endp,
- struct bsc_connection *bsc)
-{
- LOGP(DMGCP, LOGL_ERROR, "No CI, freeing endpoint 0x%x in state %d\n",
- ENDPOINT_NUMBER(endp), bsc_endp->transaction_state);
-
- /* if a CRCX failed... send a DLCX down the stream */
- if (bsc_endp->transaction_state == MGCP_ENDP_CRCX) {
- struct nat_sccp_connection *con;
- con = bsc_mgcp_find_con(bsc->nat, ENDPOINT_NUMBER(endp));
- if (!con) {
- LOGP(DMGCP, LOGL_ERROR,
- "No SCCP connection for endp 0x%x\n",
- ENDPOINT_NUMBER(endp));
- } else {
- if (con->bsc == bsc) {
- bsc_mgcp_send_dlcx(bsc, con->bsc_endp, con->bsc->next_transaction++);
- } else {
- LOGP(DMGCP, LOGL_ERROR,
- "Endpoint belongs to a different BSC\n");
- }
- }
- }
-
- bsc_mgcp_free_endpoint(bsc->nat, ENDPOINT_NUMBER(endp));
- mgcp_release_endp(endp);
-}
-
-static void bsc_mgcp_osmux_confirm(struct mgcp_endpoint *endp, const char *str)
-{
- unsigned int osmux_cid;
- char *res;
-
- res = strstr(str, "X-Osmux: ");
- if (!res) {
- LOGP(DMGCP, LOGL_INFO,
- "BSC doesn't want to use Osmux, failing back to RTP\n");
- goto err;
- }
-
- if (sscanf(res, "X-Osmux: %u", &osmux_cid) != 1) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to parse Osmux CID '%s'\n",
- str);
- goto err;
- }
-
- if (endp->osmux.cid != osmux_cid) {
- LOGP(DMGCP, LOGL_ERROR,
- "BSC sent us wrong CID %u, we expected %u",
- osmux_cid, endp->osmux.cid);
- goto err;
- }
-
- LOGP(DMGCP, LOGL_NOTICE, "bsc accepted to use Osmux (cid=%u)\n",
- osmux_cid);
- endp->osmux.state = OSMUX_STATE_ACTIVATING;
- return;
-err:
- osmux_release_cid(endp);
- endp->osmux.state = OSMUX_STATE_DISABLED;
-}
-
-/*
- * We have received a msg from the BSC. We will see if we know
- * this transaction and if it belongs to the BSC. Then we will
- * need to patch the content to point to the local network and we
- * need to update the I: that was assigned by the BSS.
- *
- * Only responses to CRCX and DLCX should arrive here. The DLCX
- * needs to be handled specially to combine the two statistics.
- */
-void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg)
-{
- struct msgb *output;
- struct bsc_endpoint *bsc_endp = NULL;
- struct mgcp_endpoint *endp = NULL;
- int i, code;
- char transaction_id[60];
-
- /* Some assumption that our buffer is big enough.. and null terminate */
- if (msgb_l2len(msg) > 2000) {
- LOGP(DMGCP, LOGL_ERROR, "MGCP message too long.\n");
- return;
- }
-
- msg->l2h[msgb_l2len(msg)] = '\0';
-
- if (bsc_mgcp_parse_response((const char *) msg->l2h, &code, transaction_id) != 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to parse response code.\n");
- return;
- }
-
- for (i = 1; i < bsc->nat->mgcp_cfg->trunk.number_endpoints; ++i) {
- if (bsc->nat->bsc_endpoints[i].bsc != bsc)
- continue;
- /* no one listening? a bug? */
- if (!bsc->nat->bsc_endpoints[i].transaction_id)
- continue;
- if (strcmp(transaction_id, bsc->nat->bsc_endpoints[i].transaction_id) != 0)
- continue;
-
- endp = &bsc->nat->mgcp_cfg->trunk.endpoints[i];
- bsc_endp = &bsc->nat->bsc_endpoints[i];
- break;
- }
-
- if (!bsc_endp && strncmp("nat-", transaction_id, 4) == 0) {
- handle_dlcx_response(bsc, msg, code, transaction_id);
- return;
- }
-
- if (!bsc_endp) {
- LOGP(DMGCP, LOGL_ERROR, "Could not find active endpoint: %s for msg: '%s'\n",
- transaction_id, (const char *) msg->l2h);
- return;
- }
-
- endp->ci = bsc_mgcp_extract_ci((const char *) msg->l2h);
- if (endp->ci == CI_UNUSED) {
- free_chan_downstream(endp, bsc_endp, bsc);
- return;
- }
-
- if (endp->osmux.state == OSMUX_STATE_NEGOTIATING)
- bsc_mgcp_osmux_confirm(endp, (const char *) msg->l2h);
-
- /* If we require osmux and it is disabled.. fail */
- if (nat_osmux_only(bsc->nat->mgcp_cfg, bsc->cfg) &&
- endp->osmux.state == OSMUX_STATE_DISABLED) {
- LOGP(DMGCP, LOGL_ERROR,
- "Failed to activate osmux endpoint 0x%x\n",
- ENDPOINT_NUMBER(endp));
- free_chan_downstream(endp, bsc_endp, bsc);
- return;
- }
-
- /* free some stuff */
- talloc_free(bsc_endp->transaction_id);
- bsc_endp->transaction_id = NULL;
- bsc_endp->transaction_state = 0;
-
- /*
- * rewrite the information. In case the endpoint was deleted
- * there should be nothing for us to rewrite so putting endp->rtp_port
- * with the value of 0 should be no problem.
- */
- output = bsc_mgcp_rewrite((char * ) msg->l2h, msgb_l2len(msg), -1,
- mgcp_net_src_addr(endp),
- endp->net_end.local_port, -1,
- &endp->bts_end.codec.payload_type,
- bsc->nat->sdp_ensure_amr_mode_set);
- if (!output) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to rewrite MGCP msg.\n");
- return;
- }
-
- mgcp_queue_for_call_agent(bsc->nat, output);
-}
-
-int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60])
-{
- int rc;
- /* we want to parse two strings */
- rc = sscanf(str, "%3d %59s\n", code, transaction) != 2;
- transaction[59] = '\0';
- return rc;
-}
-
-uint32_t bsc_mgcp_extract_ci(const char *str)
-{
- unsigned int ci;
- char *res = strstr(str, "I: ");
- if (!res) {
- LOGP(DMGCP, LOGL_ERROR, "No CI in msg '%s'\n", str);
- return CI_UNUSED;
- }
-
- if (sscanf(res, "I: %u", &ci) != 1) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to parse CI in msg '%s'\n", str);
- return CI_UNUSED;
- }
-
- return ci;
-}
-
-/**
- * Create a new MGCPCommand based on the input and endpoint from a message
- */
-static void patch_mgcp(struct msgb *output, const char *op, const char *tok,
- int endp, int len, int cr, int osmux_cid)
-{
- int slen;
- int ret;
- char buf[40];
- char osmux_extension[strlen("\nX-Osmux: 255") + 1];
-
- buf[0] = buf[39] = '\0';
- ret = sscanf(tok, "%*s %s", buf);
- if (ret != 1) {
- LOGP(DMGCP, LOGL_ERROR,
- "Failed to find Endpoint in: %s\n", tok);
- return;
- }
-
- if (osmux_cid >= 0)
- sprintf(osmux_extension, "\nX-Osmux: %u", osmux_cid & 0xff);
- else
- osmux_extension[0] = '\0';
-
- slen = sprintf((char *) output->l3h, "%s %s %x@mgw MGCP 1.0%s%s",
- op, buf, endp, osmux_extension, cr ? "\r\n" : "\n");
- output->l3h = msgb_put(output, slen);
-}
-
-/* we need to replace some strings... */
-struct msgb *bsc_mgcp_rewrite(char *input, int length, int endpoint,
- const char *ip, int port, int osmux_cid,
- int *first_payload_type, int ensure_mode_set)
-{
- static const char crcx_str[] = "CRCX ";
- static const char dlcx_str[] = "DLCX ";
- static const char mdcx_str[] = "MDCX ";
-
- static const char ip_str[] = "c=IN IP4 ";
- static const char aud_str[] = "m=audio ";
- static const char fmt_str[] = "a=fmtp:";
-
- char buf[128];
- char *running, *token;
- struct msgb *output;
-
- /* keep state to add the a=fmtp line */
- int found_fmtp = 0;
- int payload = -1;
- int cr = 1;
-
- if (length > 4096 - 256) {
- LOGP(DMGCP, LOGL_ERROR, "Input is too long.\n");
- return NULL;
- }
-
- output = msgb_alloc_headroom(4096, 128, "MGCP rewritten");
- if (!output) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to allocate new MGCP msg.\n");
- return NULL;
- }
-
- running = input;
- output->l2h = output->data;
- output->l3h = output->l2h;
- for (token = strsep(&running, "\n"); running; token = strsep(&running, "\n")) {
- int len = strlen(token);
- cr = len > 0 && token[len - 1] == '\r';
-
- if (strncmp(crcx_str, token, (sizeof crcx_str) - 1) == 0) {
- patch_mgcp(output, "CRCX", token, endpoint, len, cr, osmux_cid);
- } else if (strncmp(dlcx_str, token, (sizeof dlcx_str) - 1) == 0) {
- patch_mgcp(output, "DLCX", token, endpoint, len, cr, -1);
- } else if (strncmp(mdcx_str, token, (sizeof mdcx_str) - 1) == 0) {
- patch_mgcp(output, "MDCX", token, endpoint, len, cr, -1);
- } else if (strncmp(ip_str, token, (sizeof ip_str) - 1) == 0) {
- output->l3h = msgb_put(output, strlen(ip_str));
- memcpy(output->l3h, ip_str, strlen(ip_str));
- output->l3h = msgb_put(output, strlen(ip));
- memcpy(output->l3h, ip, strlen(ip));
-
- if (cr) {
- output->l3h = msgb_put(output, 2);
- output->l3h[0] = '\r';
- output->l3h[1] = '\n';
- } else {
- output->l3h = msgb_put(output, 1);
- output->l3h[0] = '\n';
- }
- } else if (strncmp(aud_str, token, (sizeof aud_str) - 1) == 0) {
- int offset;
- if (sscanf(token, "m=audio %*d RTP/AVP %n%d", &offset, &payload) != 1) {
- LOGP(DMGCP, LOGL_ERROR, "Could not parsed audio line.\n");
- msgb_free(output);
- return NULL;
- }
-
- snprintf(buf, sizeof(buf)-1, "m=audio %d RTP/AVP %s\n",
- port, &token[offset]);
- buf[sizeof(buf)-1] = '\0';
-
- output->l3h = msgb_put(output, strlen(buf));
- memcpy(output->l3h, buf, strlen(buf));
- } else if (strncmp(fmt_str, token, (sizeof fmt_str) - 1) == 0) {
- found_fmtp = 1;
- goto copy;
- } else {
-copy:
- output->l3h = msgb_put(output, len + 1);
- memcpy(output->l3h, token, len);
- output->l3h[len] = '\n';
- }
- }
-
- /*
- * the above code made sure that we have 128 bytes lefts. So we can
- * safely append another line.
- */
- if (ensure_mode_set && !found_fmtp && payload != -1) {
- snprintf(buf, sizeof(buf) - 1, "a=fmtp:%d mode-set=2%s",
- payload, cr ? "\r\n" : "\n");
- buf[sizeof(buf) - 1] = '\0';
- output->l3h = msgb_put(output, strlen(buf));
- memcpy(output->l3h, buf, strlen(buf));
- }
-
- if (payload != -1 && first_payload_type)
- *first_payload_type = payload;
-
- return output;
-}
-
-/*
- * This comes from the MSC and we will now parse it. The caller needs
- * to free the msgb.
- */
-void bsc_nat_handle_mgcp(struct bsc_nat *nat, struct msgb *msg)
-{
- struct msgb *resp;
-
- if (!nat->mgcp_ipa) {
- LOGP(DMGCP, LOGL_ERROR, "MGCP message not allowed on IPA.\n");
- return;
- }
-
- if (msgb_l2len(msg) > sizeof(nat->mgcp_msg) - 1) {
- LOGP(DMGCP, LOGL_ERROR, "MGCP msg too big for handling.\n");
- return;
- }
-
- memcpy(nat->mgcp_msg, msg->l2h, msgb_l2len(msg));
- nat->mgcp_length = msgb_l2len(msg);
- nat->mgcp_msg[nat->mgcp_length] = '\0';
-
- /* now handle the message */
- resp = mgcp_handle_message(nat->mgcp_cfg, msg);
-
- /* we do have a direct answer... e.g. AUEP */
- if (resp)
- mgcp_queue_for_call_agent(nat, resp);
-
- return;
-}
-
-static int mgcp_do_read(struct osmo_fd *fd)
-{
- struct bsc_nat *nat;
- struct msgb *msg, *resp;
- int rc;
-
- nat = fd->data;
-
- rc = read(fd->fd, nat->mgcp_msg, sizeof(nat->mgcp_msg) - 1);
- if (rc <= 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to read errno: %d\n", errno);
- return -1;
- }
-
- nat->mgcp_msg[rc] = '\0';
- nat->mgcp_length = rc;
-
- msg = msgb_alloc(sizeof(nat->mgcp_msg), "MGCP GW Read");
- if (!msg) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to create buffer.\n");
- return -1;
- }
-
- msg->l2h = msgb_put(msg, rc);
- memcpy(msg->l2h, nat->mgcp_msg, msgb_l2len(msg));
- resp = mgcp_handle_message(nat->mgcp_cfg, msg);
- msgb_free(msg);
-
- /* we do have a direct answer... e.g. AUEP */
- if (resp)
- mgcp_queue_for_call_agent(nat, resp);
-
- return 0;
-}
-
-static int mgcp_do_write(struct osmo_fd *bfd, struct msgb *msg)
-{
- int rc;
-
- rc = write(bfd->fd, msg->data, msg->len);
-
- if (rc != msg->len) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to write msg to MGCP CallAgent.\n");
- return -1;
- }
-
- return rc;
-}
-
-static int init_mgcp_socket(struct bsc_nat *nat, struct mgcp_config *cfg)
-{
- struct sockaddr_in addr;
- int on;
-
- cfg->gw_fd.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (cfg->gw_fd.bfd.fd < 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to create MGCP socket. errno: %d\n", errno);
- return -1;
- }
-
- on = 1;
- setsockopt(cfg->gw_fd.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(cfg->source_port);
- inet_aton(cfg->source_addr, &addr.sin_addr);
-
- if (bind(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to bind on %s:%d errno: %d\n",
- cfg->source_addr, cfg->source_port, errno);
- close(cfg->gw_fd.bfd.fd);
- cfg->gw_fd.bfd.fd = -1;
- return -1;
- }
-
- addr.sin_port = htons(2727);
- inet_aton(cfg->call_agent_addr, &addr.sin_addr);
- if (connect(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to connect to: '%s'. errno: %d\n",
- cfg->call_agent_addr, errno);
- close(cfg->gw_fd.bfd.fd);
- cfg->gw_fd.bfd.fd = -1;
- return -1;
- }
-
- osmo_wqueue_init(&cfg->gw_fd, 10);
- cfg->gw_fd.bfd.when = BSC_FD_READ;
- cfg->gw_fd.bfd.data = nat;
- cfg->gw_fd.read_cb = mgcp_do_read;
- cfg->gw_fd.write_cb = mgcp_do_write;
-
- if (osmo_fd_register(&cfg->gw_fd.bfd) != 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to register MGCP fd.\n");
- close(cfg->gw_fd.bfd.fd);
- cfg->gw_fd.bfd.fd = -1;
- return -1;
- }
-
- return 0;
-}
-
-int bsc_mgcp_nat_init(struct bsc_nat *nat)
-{
- struct mgcp_config *cfg = nat->mgcp_cfg;
-
- if (!cfg->call_agent_addr) {
- LOGP(DMGCP, LOGL_ERROR, "The BSC nat requires the call agent ip to be set.\n");
- return -1;
- }
-
- if (cfg->bts_ip) {
- LOGP(DMGCP, LOGL_ERROR, "Do not set the BTS ip for the nat.\n");
- return -1;
- }
-
- /* initialize the MGCP socket */
- if (!nat->mgcp_ipa) {
- int rc = init_mgcp_socket(nat, cfg);
- if (rc != 0)
- return rc;
- }
-
-
- /* some more MGCP config handling */
- cfg->data = nat;
- cfg->policy_cb = bsc_mgcp_policy_cb;
-
- if (cfg->bts_ip)
- talloc_free(cfg->bts_ip);
- cfg->bts_ip = "";
-
- nat->bsc_endpoints = talloc_zero_array(nat,
- struct bsc_endpoint,
- cfg->trunk.number_endpoints + 1);
- if (!nat->bsc_endpoints) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to allocate nat endpoints\n");
- close(cfg->gw_fd.bfd.fd);
- cfg->gw_fd.bfd.fd = -1;
- return -1;
- }
-
- if (mgcp_reset_transcoder(cfg) < 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to send packet to the transcoder.\n");
- talloc_free(nat->bsc_endpoints);
- nat->bsc_endpoints = NULL;
- close(cfg->gw_fd.bfd.fd);
- cfg->gw_fd.bfd.fd = -1;
- return -1;
- }
-
- return 0;
-}
-
-void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc)
-{
- struct rate_ctr *ctr = NULL;
- int i;
-
- if (bsc->cfg)
- ctr = &bsc->cfg->stats.ctrg->ctr[BCFG_CTR_DROPPED_CALLS];
-
- for (i = 1; i < bsc->nat->mgcp_cfg->trunk.number_endpoints; ++i) {
- struct bsc_endpoint *bsc_endp = &bsc->nat->bsc_endpoints[i];
-
- if (bsc_endp->bsc != bsc)
- continue;
-
- if (ctr)
- rate_ctr_inc(ctr);
-
- bsc_mgcp_free_endpoint(bsc->nat, i);
- mgcp_release_endp(&bsc->nat->mgcp_cfg->trunk.endpoints[i]);
- }
-}
diff --git a/src/osmo-bsc_nat/bsc_nat.c b/src/osmo-bsc_nat/bsc_nat.c
deleted file mode 100644
index 401288d84..000000000
--- a/src/osmo-bsc_nat/bsc_nat.c
+++ /dev/null
@@ -1,1739 +0,0 @@
-/* BSC Multiplexer/NAT */
-
-/*
- * (C) 2010-2013 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010-2013 by On-Waves
- * (C) 2009 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 <sys/socket.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <libgen.h>
-
-#define _GNU_SOURCE
-#include <getopt.h>
-
-#include <openbsc/debug.h>
-#include <openbsc/bsc_msc.h>
-#include <openbsc/bsc_nat.h>
-#include <openbsc/bsc_nat_sccp.h>
-#include <openbsc/bsc_msg_filter.h>
-#include <openbsc/ipaccess.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/socket.h>
-#include <openbsc/vty.h>
-
-#include <osmocom/ctrl/control_cmd.h>
-#include <osmocom/ctrl/control_if.h>
-#include <osmocom/ctrl/ports.h>
-#include <osmocom/ctrl/control_vty.h>
-
-#include <osmocom/crypt/auth.h>
-
-#include <osmocom/core/application.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/stats.h>
-
-#include <osmocom/gsm/tlv.h>
-#include <osmocom/gsm/gsm0808.h>
-#include <osmocom/gsm/protocol/gsm_08_08.h>
-
-#include <osmocom/vty/telnet_interface.h>
-#include <osmocom/vty/vty.h>
-#include <osmocom/vty/logging.h>
-#include <osmocom/vty/stats.h>
-#include <osmocom/vty/ports.h>
-
-#include <osmocom/sccp/sccp.h>
-
-#include <osmocom/abis/ipa.h>
-
-#include <openssl/rand.h>
-
-#include "../../bscconfig.h"
-
-#define SCCP_CLOSE_TIME 20
-#define SCCP_CLOSE_TIME_TIMEOUT 19
-
-static const char *config_file = "bsc-nat.cfg";
-static struct in_addr local_addr;
-static struct osmo_fd bsc_listen;
-static const char *msc_ip = NULL;
-static struct osmo_timer_list sccp_close;
-static int daemonize = 0;
-
-const char *openbsc_copyright =
- "Copyright (C) 2010 Holger Hans Peter Freyther and On-Waves\r\n"
- "License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
- "This is free software: you are free to change and redistribute it.\r\n"
- "There is NO WARRANTY, to the extent permitted by law.\r\n";
-
-static struct bsc_nat *nat;
-static void bsc_send_data(struct bsc_connection *bsc, const uint8_t *data, unsigned int length, int);
-static void msc_send_reset(struct bsc_msc_connection *con);
-static void bsc_stat_reject(int filter, struct bsc_connection *bsc, int normal);
-
-struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num)
-{
- struct bsc_config *conf;
-
- llist_for_each_entry(conf, &nat->bsc_configs, entry)
- if (conf->nr == num)
- return conf;
-
- return NULL;
-}
-
-static void queue_for_msc(struct bsc_msc_connection *con, struct msgb *msg)
-{
- if (!con) {
- LOGP(DLINP, LOGL_ERROR, "No MSC Connection assigned. Check your code.\n");
- msgb_free(msg);
- return;
- }
-
-
- if (osmo_wqueue_enqueue(&con->write_queue, msg) != 0) {
- LOGP(DLINP, LOGL_ERROR, "Failed to enqueue the write.\n");
- msgb_free(msg);
- }
-}
-
-static void send_reset_ack(struct bsc_connection *bsc)
-{
- static const uint8_t gsm_reset_ack[] = {
- 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01,
- 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03,
- 0x00, 0x01, 0x31,
- };
-
- bsc_send_data(bsc, gsm_reset_ack, sizeof(gsm_reset_ack), IPAC_PROTO_SCCP);
-}
-
-static void send_ping(struct bsc_connection *bsc)
-{
- static const uint8_t id_ping[] = {
- IPAC_MSGT_PING,
- };
-
- bsc_send_data(bsc, id_ping, sizeof(id_ping), IPAC_PROTO_IPACCESS);
-}
-
-static void send_pong(struct bsc_connection *bsc)
-{
- static const uint8_t id_pong[] = {
- IPAC_MSGT_PONG,
- };
-
- bsc_send_data(bsc, id_pong, sizeof(id_pong), IPAC_PROTO_IPACCESS);
-}
-
-static void bsc_pong_timeout(void *_bsc)
-{
- struct bsc_connection *bsc = _bsc;
-
- LOGP(DNAT, LOGL_ERROR, "BSC Nr: %d PONG timeout.\n", bsc->cfg->nr);
- bsc_close_connection(bsc);
-}
-
-static void bsc_ping_timeout(void *_bsc)
-{
- struct bsc_connection *bsc = _bsc;
-
- if (bsc->nat->ping_timeout < 0)
- return;
-
- send_ping(bsc);
-
- /* send another ping in 20 seconds */
- osmo_timer_schedule(&bsc->ping_timeout, bsc->nat->ping_timeout, 0);
-
- /* also start a pong timer */
- osmo_timer_schedule(&bsc->pong_timeout, bsc->nat->pong_timeout, 0);
-}
-
-static void start_ping_pong(struct bsc_connection *bsc)
-{
- osmo_timer_setup(&bsc->pong_timeout, bsc_pong_timeout, bsc);
- osmo_timer_setup(&bsc->ping_timeout, bsc_ping_timeout, bsc);
-
- bsc_ping_timeout(bsc);
-}
-
-static void send_id_ack(struct bsc_connection *bsc)
-{
- static const uint8_t id_ack[] = {
- IPAC_MSGT_ID_ACK
- };
-
- bsc_send_data(bsc, id_ack, sizeof(id_ack), IPAC_PROTO_IPACCESS);
-}
-
-static void send_id_req(struct bsc_nat *nat, struct bsc_connection *bsc)
-{
- static const uint8_t s_id_req[] = {
- IPAC_MSGT_ID_GET,
- 0x01, IPAC_IDTAG_UNIT,
- 0x01, IPAC_IDTAG_MACADDR,
- 0x01, IPAC_IDTAG_LOCATION1,
- 0x01, IPAC_IDTAG_LOCATION2,
- 0x01, IPAC_IDTAG_EQUIPVERS,
- 0x01, IPAC_IDTAG_SWVERSION,
- 0x01, IPAC_IDTAG_UNITNAME,
- 0x01, IPAC_IDTAG_SERNR,
- };
-
- uint8_t *mrand;
- uint8_t id_req[sizeof(s_id_req) + (2+16)];
- uint8_t *buf = &id_req[sizeof(s_id_req)];
-
- /* copy the static data */
- memcpy(id_req, s_id_req, sizeof(s_id_req));
-
- /* put the RAND with length, tag, value */
- buf = v_put(buf, 0x11);
- buf = v_put(buf, 0x23);
- mrand = bsc->last_rand;
-
- if (RAND_bytes(mrand, 16) != 1)
- goto failed_random;
-
- memcpy(buf, mrand, 16);
- buf += 16;
-
- bsc_send_data(bsc, id_req, sizeof(id_req), IPAC_PROTO_IPACCESS);
- return;
-
-failed_random:
- /* the timeout will trigger and close this connection */
- LOGP(DNAT, LOGL_ERROR, "Failed to read from urandom.\n");
- return;
-}
-
-static struct msgb *nat_create_rlsd(struct nat_sccp_connection *conn)
-{
- struct sccp_connection_released *rel;
- struct msgb *msg;
-
- msg = msgb_alloc_headroom(4096, 128, "rlsd");
- if (!msg) {
- LOGP(DNAT, LOGL_ERROR, "Failed to allocate released.\n");
- return NULL;
- }
-
- msg->l2h = msgb_put(msg, sizeof(*rel));
- rel = (struct sccp_connection_released *) msg->l2h;
- rel->type = SCCP_MSG_TYPE_RLSD;
- rel->release_cause = SCCP_RELEASE_CAUSE_SCCP_FAILURE;
- rel->destination_local_reference = conn->remote_ref;
- rel->source_local_reference = conn->patched_ref;
-
- return msg;
-}
-
-static void nat_send_rlsd_ussd(struct bsc_nat *nat, struct nat_sccp_connection *conn)
-{
- struct msgb *msg;
-
- if (!nat->ussd_con)
- return;
-
- msg = nat_create_rlsd(conn);
- if (!msg)
- return;
-
- bsc_do_write(&nat->ussd_con->queue, msg, IPAC_PROTO_SCCP);
-}
-
-static void nat_send_rlsd_msc(struct nat_sccp_connection *conn)
-{
- struct msgb *msg;
-
- msg = nat_create_rlsd(conn);
- if (!msg)
- return;
-
- ipa_prepend_header(msg, IPAC_PROTO_SCCP);
- queue_for_msc(conn->msc_con, msg);
-}
-
-static void nat_send_rlsd_bsc(struct nat_sccp_connection *conn)
-{
- struct msgb *msg;
- struct sccp_connection_released *rel;
-
- msg = msgb_alloc_headroom(4096, 128, "rlsd");
- if (!msg) {
- LOGP(DNAT, LOGL_ERROR, "Failed to allocate clear command.\n");
- return;
- }
-
- msg->l2h = msgb_put(msg, sizeof(*rel));
- rel = (struct sccp_connection_released *) msg->l2h;
- rel->type = SCCP_MSG_TYPE_RLSD;
- rel->release_cause = SCCP_RELEASE_CAUSE_SCCP_FAILURE;
- rel->destination_local_reference = conn->real_ref;
- rel->source_local_reference = conn->remote_ref;
-
- bsc_write(conn->bsc, msg, IPAC_PROTO_SCCP);
-}
-
-static struct msgb *nat_creat_clrc(struct nat_sccp_connection *conn, uint8_t cause)
-{
- struct msgb *msg;
- struct msgb *sccp;
-
- msg = gsm0808_create_clear_command(cause);
- if (!msg) {
- LOGP(DNAT, LOGL_ERROR, "Failed to allocate clear command.\n");
- return NULL;
- }
-
- sccp = sccp_create_dt1(&conn->real_ref, msg->data, msg->len);
- if (!sccp) {
- LOGP(DNAT, LOGL_ERROR, "Failed to allocate SCCP msg.\n");
- msgb_free(msg);
- return NULL;
- }
-
- msgb_free(msg);
- return sccp;
-}
-
-static int nat_send_clrc_bsc(struct nat_sccp_connection *conn)
-{
- struct msgb *sccp;
-
- sccp = nat_creat_clrc(conn, 0x20);
- if (!sccp)
- return -1;
- return bsc_write(conn->bsc, sccp, IPAC_PROTO_SCCP);
-}
-
-static void nat_send_rlc(struct bsc_msc_connection *msc_con,
- struct sccp_source_reference *src,
- struct sccp_source_reference *dst)
-{
- struct sccp_connection_release_complete *rlc;
- struct msgb *msg;
-
- msg = msgb_alloc_headroom(4096, 128, "rlc");
- if (!msg) {
- LOGP(DNAT, LOGL_ERROR, "Failed to sccp rlc.\n");
- return;
- }
-
- msg->l2h = msgb_put(msg, sizeof(*rlc));
- rlc = (struct sccp_connection_release_complete *) msg->l2h;
- rlc->type = SCCP_MSG_TYPE_RLC;
- rlc->destination_local_reference = *dst;
- rlc->source_local_reference = *src;
-
- ipa_prepend_header(msg, IPAC_PROTO_SCCP);
-
- queue_for_msc(msc_con, msg);
-}
-
-static void send_mgcp_reset(struct bsc_connection *bsc)
-{
- static const uint8_t mgcp_reset[] = {
- "RSIP 1 13@mgw MGCP 1.0\r\n"
- };
-
- bsc_write_mgcp(bsc, mgcp_reset, sizeof mgcp_reset - 1);
-}
-
-void bsc_nat_send_mgcp_to_msc(struct bsc_nat *nat, struct msgb *msg)
-{
- ipa_prepend_header(msg, IPAC_PROTO_MGCP_OLD);
- queue_for_msc(nat->msc_con, msg);
-}
-
-/*
- * Below is the handling of messages coming
- * from the MSC and need to be forwarded to
- * a real BSC.
- */
-static void initialize_msc_if_needed(struct bsc_msc_connection *msc_con)
-{
- if (msc_con->first_contact)
- return;
-
- msc_con->first_contact = 1;
- msc_send_reset(msc_con);
-}
-
-static void send_id_get_response(struct bsc_msc_connection *msc_con)
-{
- struct msgb *msg = bsc_msc_id_get_resp(0, nat->token, NULL, 0);
- if (!msg)
- return;
-
- ipa_prepend_header(msg, IPAC_PROTO_IPACCESS);
- queue_for_msc(msc_con, msg);
-}
-
-/*
- * Currently we are lacking refcounting so we need to copy each message.
- */
-static void bsc_send_data(struct bsc_connection *bsc, const uint8_t *data, unsigned int length, int proto)
-{
- struct msgb *msg;
-
- if (length > 4096 - 128) {
- LOGP(DLINP, LOGL_ERROR, "Can not send message of that size.\n");
- return;
- }
-
- msg = msgb_alloc_headroom(4096, 128, "to-bsc");
- if (!msg) {
- LOGP(DLINP, LOGL_ERROR, "Failed to allocate memory for BSC msg.\n");
- return;
- }
-
- msg->l2h = msgb_put(msg, length);
- memcpy(msg->data, data, length);
-
- bsc_write(bsc, msg, proto);
-}
-
-/*
- * Update the release statistics
- */
-static void bsc_stat_reject(int filter, struct bsc_connection *bsc, int normal)
-{
- if (!bsc->cfg) {
- LOGP(DNAT, LOGL_ERROR, "BSC is not authenticated.");
- return;
- }
-
- if (filter >= 0) {
- LOGP(DNAT, LOGL_ERROR, "Connection was not rejected");
- return;
- }
-
- if (filter == -1)
- rate_ctr_inc(&bsc->cfg->stats.ctrg->ctr[BCFG_CTR_ILL_PACKET]);
- else if (normal)
- rate_ctr_inc(&bsc->cfg->stats.ctrg->ctr[BCFG_CTR_REJECTED_MSG]);
- else
- rate_ctr_inc(&bsc->cfg->stats.ctrg->ctr[BCFG_CTR_REJECTED_CR]);
-}
-
-/*
- * 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 nat_sccp_connection *con,
- struct bsc_filter_reject_cause *cause)
-{
- 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 {
- ipa_prepend_header(rlsd, IPAC_PROTO_SCCP);
- queue_for_msc(con->msc_con, rlsd);
- }
- con->con_local = NAT_CON_END_LOCAL;
- con->msc_con = NULL;
-
- /* 2. release the BSC side */
- if (con->filter_state.con_type == FLT_CON_TYPE_LU) {
- struct msgb *payload, *udt;
- payload = gsm48_create_loc_upd_rej(cause->lu_reject_cause);
-
- 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");
- }
- }
-
- nat_send_clrc_bsc(con);
-
- 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->filter_state.con_type = FLT_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,
- struct bsc_filter_reject_cause *cause)
-{
- struct msgb *payload;
- struct msgb *refuse;
-
- if (con_type == FLT_CON_TYPE_LU)
- payload = gsm48_create_loc_upd_rej(cause->lu_reject_cause);
- else if (con_type == FLT_CON_TYPE_CM_SERV_REQ || con_type == FLT_CON_TYPE_SSA)
- payload = gsm48_create_mm_serv_rej(cause->cm_reject_cause);
- else {
- LOGP(DNAT, LOGL_ERROR, "Unknown connection type: %d\n", con_type);
- payload = NULL;
- }
-
- /*
- * Some BSCs do not handle the payload inside a SCCP CREF msg
- * so we will need to:
- * 1.) Allocate a local connection and mark it as local..
- * 2.) queue data for downstream.. and the RLC should delete everything
- */
- if (payload) {
- struct msgb *cc, *udt, *clear, *rlsd;
- struct nat_sccp_connection *con;
- con = create_sccp_src_ref(bsc, parsed);
- if (!con)
- goto send_refuse;
-
- /* declare it local and assign a unique remote_ref */
- con->filter_state.con_type = FLT_CON_TYPE_LOCAL_REJECT;
- con->con_local = NAT_CON_END_LOCAL;
- con->has_remote_ref = 1;
- con->remote_ref = con->patched_ref;
-
- /* 1. create a confirmation */
- cc = sccp_create_cc(&con->remote_ref, &con->real_ref);
- if (!cc)
- goto send_refuse;
-
- /* 2. create the DT1 */
- gsm0808_prepend_dtap_header(payload, 0);
- udt = sccp_create_dt1(&con->real_ref, payload->data, payload->len);
- if (!udt) {
- msgb_free(cc);
- goto send_refuse;
- }
-
- /* 3. send a Clear Command */
- clear = nat_creat_clrc(con, 0x20);
- if (!clear) {
- msgb_free(cc);
- msgb_free(udt);
- goto send_refuse;
- }
-
- /* 4. send a RLSD */
- rlsd = sccp_create_rlsd(&con->remote_ref, &con->real_ref,
- SCCP_RELEASE_CAUSE_END_USER_ORIGINATED);
- if (!rlsd) {
- msgb_free(cc);
- msgb_free(udt);
- msgb_free(clear);
- goto send_refuse;
- }
-
- bsc_write(bsc, cc, IPAC_PROTO_SCCP);
- bsc_write(bsc, udt, IPAC_PROTO_SCCP);
- bsc_write(bsc, clear, IPAC_PROTO_SCCP);
- bsc_write(bsc, rlsd, IPAC_PROTO_SCCP);
- msgb_free(payload);
- return;
- }
-
-
-send_refuse:
- if (payload)
- msgb_free(payload);
-
- refuse = sccp_create_refuse(parsed->src_local_ref,
- SCCP_REFUSAL_SCCP_FAILURE, NULL, 0);
- if (!refuse) {
- LOGP(DNAT, LOGL_ERROR,
- "Creating refuse msg failed for SCCP 0x%x on BSC Nr: %d.\n",
- sccp_src_ref_to_int(parsed->src_local_ref), bsc->cfg->nr);
- return;
- }
-
- bsc_write(bsc, refuse, IPAC_PROTO_SCCP);
-}
-
-static void bsc_nat_send_paging(struct bsc_connection *bsc, struct msgb *msg)
-{
- if (bsc->cfg->forbid_paging) {
- LOGP(DNAT, LOGL_DEBUG, "Paging forbidden for BTS: %d\n", bsc->cfg->nr);
- return;
- }
-
- bsc_send_data(bsc, msg->l2h, msgb_l2len(msg), IPAC_PROTO_SCCP);
-}
-
-static void bsc_nat_handle_paging(struct bsc_nat *nat, struct msgb *msg)
-{
- struct bsc_connection *bsc;
- const uint8_t *paging_start;
- int paging_length, i, ret;
-
- ret = bsc_nat_find_paging(msg, &paging_start, &paging_length);
- if (ret != 0) {
- LOGP(DNAT, LOGL_ERROR, "Could not parse paging message: %d\n", ret);
- return;
- }
-
- /* This is quite expensive now */
- for (i = 0; i < paging_length; i += 2) {
- unsigned int _lac = ntohs(*(unsigned int *) &paging_start[i]);
- unsigned int paged = 0;
- llist_for_each_entry(bsc, &nat->bsc_connections, list_entry) {
- if (!bsc->cfg)
- continue;
- if (!bsc->authenticated)
- continue;
- if (!bsc_config_handles_lac(bsc->cfg, _lac))
- continue;
- bsc_nat_send_paging(bsc, msg);
- paged += 1;
- }
-
- /* highlight a possible config issue */
- if (paged == 0)
- LOGP(DNAT, LOGL_ERROR, "No BSC for LAC %d/0x%d\n", _lac, _lac);
-
- }
-}
-
-
-/*
- * Update the auth status. This can be either a CIPHER MODE COMMAND or
- * a CM Serivce Accept. Maybe also LU Accept or such in the future.
- */
-static void update_con_authorize(struct nat_sccp_connection *con,
- struct bsc_nat_parsed *parsed,
- struct msgb *msg)
-{
- if (!con)
- return;
- if (con->authorized)
- return;
-
- if (parsed->bssap == BSSAP_MSG_BSS_MANAGEMENT &&
- parsed->gsm_type == BSS_MAP_MSG_CIPHER_MODE_CMD) {
- con->authorized = 1;
- } else if (parsed->bssap == BSSAP_MSG_DTAP) {
- uint8_t msg_type, proto;
- uint32_t len;
- struct gsm48_hdr *hdr48;
- hdr48 = bsc_unpack_dtap(parsed, msg, &len);
- if (!hdr48)
- return;
-
- proto = gsm48_hdr_pdisc(hdr48);
- msg_type = gsm48_hdr_msg_type(hdr48);
- if (proto == GSM48_PDISC_MM &&
- msg_type == GSM48_MT_MM_CM_SERV_ACC)
- con->authorized = 1;
- }
-}
-
-static int forward_sccp_to_bts(struct bsc_msc_connection *msc_con, struct msgb *msg)
-{
- struct nat_sccp_connection *con = NULL;
- struct bsc_connection *bsc;
- struct bsc_nat_parsed *parsed;
- int proto;
-
- /* filter, drop, patch the message? */
- parsed = bsc_nat_parse(msg);
- if (!parsed) {
- LOGP(DNAT, LOGL_ERROR, "Can not parse msg from BSC.\n");
- return -1;
- }
-
- if (bsc_nat_filter_ipa(DIR_BSC, msg, parsed))
- goto exit;
-
- proto = parsed->ipa_proto;
-
- /* Route and modify the SCCP packet */
- if (proto == IPAC_PROTO_SCCP) {
- switch (parsed->sccp_type) {
- case SCCP_MSG_TYPE_UDT:
- /* forward UDT messages to every BSC */
- goto send_to_all;
- break;
- case SCCP_MSG_TYPE_RLSD:
- case SCCP_MSG_TYPE_CREF:
- case SCCP_MSG_TYPE_DT1:
- case SCCP_MSG_TYPE_IT:
- con = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
- if (parsed->gsm_type == BSS_MAP_MSG_ASSIGMENT_RQST) {
- osmo_counter_inc(nat->stats.sccp.calls);
-
- if (con) {
- struct rate_ctr_group *ctrg;
- ctrg = con->bsc->cfg->stats.ctrg;
- rate_ctr_inc(&ctrg->ctr[BCFG_CTR_SCCP_CALLS]);
- if (bsc_mgcp_assign_patch(con, msg) != 0)
- LOGP(DNAT, LOGL_ERROR, "Failed to assign...\n");
- } else
- LOGP(DNAT, LOGL_ERROR, "Assignment command but no BSC.\n");
- } else if (con && con->con_local == NAT_CON_END_USSD &&
- parsed->gsm_type == BSS_MAP_MSG_CLEAR_CMD) {
- LOGP(DNAT, LOGL_NOTICE, "Clear Command for USSD Connection. Ignoring.\n");
- con = NULL;
- }
- break;
- case SCCP_MSG_TYPE_CC:
- con = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
- if (!con || update_sccp_src_ref(con, parsed) != 0)
- goto exit;
- break;
- case SCCP_MSG_TYPE_RLC:
- LOGP(DNAT, LOGL_ERROR, "Unexpected release complete from MSC.\n");
- goto exit;
- break;
- case SCCP_MSG_TYPE_CR:
- /* MSC never opens a SCCP connection, fall through */
- default:
- goto exit;
- }
-
- if (!con && parsed->sccp_type == SCCP_MSG_TYPE_RLSD) {
- LOGP(DNAT, LOGL_NOTICE, "Sending fake RLC on RLSD message to network.\n");
- /* Exchange src/dest for the reply */
- nat_send_rlc(msc_con, &parsed->original_dest_ref,
- parsed->src_local_ref);
- } else if (!con)
- LOGP(DNAT, LOGL_ERROR, "Unknown connection for msg type: 0x%x from the MSC.\n", parsed->sccp_type);
- }
-
- if (!con) {
- talloc_free(parsed);
- return -1;
- }
- if (!con->bsc->authenticated) {
- talloc_free(parsed);
- LOGP(DNAT, LOGL_ERROR, "Selected BSC not authenticated.\n");
- return -1;
- }
-
- update_con_authorize(con, parsed, msg);
- talloc_free(parsed);
-
- bsc_send_data(con->bsc, msg->l2h, msgb_l2len(msg), proto);
- return 0;
-
-send_to_all:
- /*
- * Filter Paging from the network. We do not want to send a PAGING
- * Command to every BSC in our network. We will analys the PAGING
- * message and then send it to the authenticated messages...
- */
- if (parsed->ipa_proto == IPAC_PROTO_SCCP && parsed->gsm_type == BSS_MAP_MSG_PAGING) {
- bsc_nat_handle_paging(nat, msg);
- goto exit;
- }
- /* currently send this to every BSC connected */
- llist_for_each_entry(bsc, &nat->bsc_connections, list_entry) {
- if (!bsc->authenticated)
- continue;
-
- bsc_send_data(bsc, msg->l2h, msgb_l2len(msg), parsed->ipa_proto);
- }
-
-exit:
- talloc_free(parsed);
- return 0;
-}
-
-static void msc_connection_was_lost(struct bsc_msc_connection *con)
-{
- struct bsc_connection *bsc, *tmp;
-
- LOGP(DMSC, LOGL_ERROR, "Closing all connections downstream.\n");
- llist_for_each_entry_safe(bsc, tmp, &nat->bsc_connections, list_entry)
- bsc_close_connection(bsc);
-
- bsc_mgcp_free_endpoints(nat);
- bsc_msc_schedule_connect(con);
-}
-
-static void msc_connection_connected(struct bsc_msc_connection *con)
-{
- osmo_counter_inc(nat->stats.msc.reconn);
-}
-
-static void msc_send_reset(struct bsc_msc_connection *msc_con)
-{
- static const uint8_t reset[] = {
- 0x00, 0x12, 0xfd,
- 0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe,
- 0x02, 0x42, 0xfe, 0x06, 0x00, 0x04, 0x30, 0x04,
- 0x01, 0x20
- };
-
- struct msgb *msg;
-
- msg = msgb_alloc_headroom(4096, 128, "08.08 reset");
- if (!msg) {
- LOGP(DMSC, LOGL_ERROR, "Failed to allocate reset msg.\n");
- return;
- }
-
- msg->l2h = msgb_put(msg, sizeof(reset));
- memcpy(msg->l2h, reset, msgb_l2len(msg));
-
- queue_for_msc(msc_con, msg);
-
- LOGP(DMSC, LOGL_NOTICE, "Scheduled GSM0808 reset msg for the MSC.\n");
-}
-
-static int ipaccess_msc_read_cb(struct osmo_fd *bfd)
-{
- struct bsc_msc_connection *msc_con;
- struct msgb *msg = NULL;
- struct ipaccess_head *hh;
- int ret;
-
- msc_con = (struct bsc_msc_connection *) bfd->data;
-
- ret = ipa_msg_recv_buffered(bfd->fd, &msg, &msc_con->pending_msg);
- if (ret <= 0) {
- if (ret == -EAGAIN)
- return 0;
- if (ret == 0)
- LOGP(DNAT, LOGL_FATAL,
- "The connection the MSC(%s) was lost, exiting\n",
- msc_con->name);
- else
- LOGP(DNAT, LOGL_ERROR,
- "Failed to parse ip access message on %s: %d\n",
- msc_con->name, ret);
-
- bsc_msc_lost(msc_con);
- return -1;
- }
-
- LOGP(DNAT, LOGL_DEBUG,
- "MSG from MSC(%s): %s proto: %d\n", msc_con->name,
- osmo_hexdump(msg->data, msg->len), msg->l2h[0]);
-
- /* handle base message handling */
- hh = (struct ipaccess_head *) msg->data;
-
- /* initialize the networking. This includes sending a GSM08.08 message */
- if (hh->proto == IPAC_PROTO_IPACCESS) {
- ipa_ccm_rcvmsg_base(msg, bfd);
- if (msg->l2h[0] == IPAC_MSGT_ID_ACK)
- initialize_msc_if_needed(msc_con);
- else if (msg->l2h[0] == IPAC_MSGT_ID_GET)
- send_id_get_response(msc_con);
- } else if (hh->proto == IPAC_PROTO_SCCP) {
- forward_sccp_to_bts(msc_con, msg);
- } else if (hh->proto == IPAC_PROTO_MGCP_OLD) {
- bsc_nat_handle_mgcp(nat, msg);
- }
-
- msgb_free(msg);
- return 0;
-}
-
-static int ipaccess_msc_write_cb(struct osmo_fd *bfd, struct msgb *msg)
-{
- int rc;
- rc = write(bfd->fd, msg->data, msg->len);
-
- if (rc != msg->len) {
- LOGP(DNAT, LOGL_ERROR, "Failed to write MSG to MSC.\n");
- return -1;
- }
-
- return rc;
-}
-
-/*
- * Below is the handling of messages coming
- * from the BSC and need to be forwarded to
- * a real BSC.
- */
-
-/*
- * Remove the connection from the connections list,
- * remove it from the patching of SCCP header lists
- * as well. Maybe in the future even close connection..
- */
-void bsc_close_connection(struct bsc_connection *connection)
-{
- struct nat_sccp_connection *sccp_patch, *tmp;
- struct bsc_cmd_list *cmd_entry, *cmd_tmp;
- struct rate_ctr *ctr = NULL;
-
- /* stop the timeout timer */
- osmo_timer_del(&connection->id_timeout);
- osmo_timer_del(&connection->ping_timeout);
- osmo_timer_del(&connection->pong_timeout);
-
- if (connection->cfg)
- ctr = &connection->cfg->stats.ctrg->ctr[BCFG_CTR_DROPPED_SCCP];
-
- /* remove all SCCP connections */
- llist_for_each_entry_safe(sccp_patch, tmp, &nat->sccp_connections, list_entry) {
- if (sccp_patch->bsc != connection)
- continue;
-
- if (ctr)
- rate_ctr_inc(ctr);
- if (sccp_patch->has_remote_ref) {
- if (sccp_patch->con_local == NAT_CON_END_MSC)
- nat_send_rlsd_msc(sccp_patch);
- else if (sccp_patch->con_local == NAT_CON_END_USSD)
- nat_send_rlsd_ussd(nat, sccp_patch);
- }
-
- sccp_connection_destroy(sccp_patch);
- }
-
- /* Reply to all outstanding commands */
- llist_for_each_entry_safe(cmd_entry, cmd_tmp, &connection->cmd_pending, list_entry) {
- cmd_entry->cmd->type = CTRL_TYPE_ERROR;
- cmd_entry->cmd->reply = "BSC closed the connection";
- ctrl_cmd_send(&cmd_entry->ccon->write_queue, cmd_entry->cmd);
- bsc_nat_ctrl_del_pending(cmd_entry);
- }
-
- /* close endpoints allocated by this BSC */
- bsc_mgcp_clear_endpoints_for(connection);
-
- osmo_fd_unregister(&connection->write_queue.bfd);
- close(connection->write_queue.bfd.fd);
- osmo_wqueue_clear(&connection->write_queue);
- llist_del(&connection->list_entry);
-
- if (connection->pending_msg) {
- LOGP(DNAT, LOGL_ERROR, "Dropping partial message on connection %d.\n",
- connection->cfg ? connection->cfg->nr : -1);
- msgb_free(connection->pending_msg);
- connection->pending_msg = NULL;
- }
-
- talloc_free(connection);
-}
-
-static void bsc_maybe_close(struct bsc_connection *bsc)
-{
- struct nat_sccp_connection *sccp;
- if (!bsc->nat->blocked)
- return;
-
- /* are there any connections left */
- llist_for_each_entry(sccp, &bsc->nat->sccp_connections, list_entry)
- if (sccp->bsc == bsc)
- return;
-
- /* nothing left, close the BSC */
- LOGP(DNAT, LOGL_NOTICE, "Cleaning up BSC %d in blocking mode.\n",
- bsc->cfg ? bsc->cfg->nr : -1);
- bsc_close_connection(bsc);
-}
-
-static void ipaccess_close_bsc(void *data)
-{
- struct sockaddr_in sock;
- socklen_t len = sizeof(sock);
- struct bsc_connection *conn = data;
-
-
- getpeername(conn->write_queue.bfd.fd, (struct sockaddr *) &sock, &len);
- LOGP(DNAT, LOGL_ERROR, "BSC on %s didn't respond to identity request. Closing.\n",
- inet_ntoa(sock.sin_addr));
- bsc_close_connection(conn);
-}
-
-static int verify_key(struct bsc_connection *conn, struct bsc_config *conf, const uint8_t *key, const int keylen)
-{
- struct osmo_auth_vector vec;
-
- struct osmo_sub_auth_data auth = {
- .type = OSMO_AUTH_TYPE_GSM,
- .algo = OSMO_AUTH_ALG_MILENAGE,
- };
-
- /* expect a specific keylen */
- if (keylen != 8) {
- LOGP(DNAT, LOGL_ERROR, "Key length is wrong: %d for bsc nr %d\n",
- keylen, conf->nr);
- return 0;
- }
-
- memcpy(auth.u.umts.opc, conf->key, 16);
- memcpy(auth.u.umts.k, conf->key, 16);
- memset(auth.u.umts.amf, 0, 2);
- auth.u.umts.sqn = 0;
-
- memset(&vec, 0, sizeof(vec));
- osmo_auth_gen_vec(&vec, &auth, conn->last_rand);
-
- if (vec.res_len != 8) {
- LOGP(DNAT, LOGL_ERROR, "Res length is wrong: %d for bsc nr %d\n",
- vec.res_len, conf->nr);
- return 0;
- }
-
- return osmo_constant_time_cmp(vec.res, key, 8) == 0;
-}
-
-static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc)
-{
- struct bsc_config *conf;
- const char *token = (const char *) TLVP_VAL(tvp, IPAC_IDTAG_UNITNAME);
- int len = TLVP_LEN(tvp, IPAC_IDTAG_UNITNAME);
- const uint8_t *xres = TLVP_VAL(tvp, 0x24);
- const int xlen = TLVP_LEN(tvp, 0x24);
-
- if (bsc->cfg) {
- LOGP(DNAT, LOGL_ERROR, "Reauth on fd %d bsc nr %d\n",
- bsc->write_queue.bfd.fd, bsc->cfg->nr);
- return;
- }
-
- if (len <= 0) {
- LOGP(DNAT, LOGL_ERROR, "Token with length zero on fd: %d\n",
- bsc->write_queue.bfd.fd);
- return;
- }
-
- if (token[len - 1] != '\0') {
- LOGP(DNAT, LOGL_ERROR, "Token not null terminated on fd: %d\n",
- bsc->write_queue.bfd.fd);
- return;
- }
-
- /*
- * New systems have fixed the structure of the message but
- * we need to support old ones too.
- */
- if (len >= 2 && token[len - 2] == '\0')
- len -= 1;
-
- conf = bsc_config_by_token(bsc->nat, token, len);
- if (!conf) {
- LOGP(DNAT, LOGL_ERROR,
- "No bsc found for token '%s' len %d on fd: %d.\n", token,
- bsc->write_queue.bfd.fd, len);
- bsc_close_connection(bsc);
- return;
- }
-
- /* We have set a key and expect it to be present */
- if (conf->key_present && !verify_key(bsc, conf, xres, xlen - 1)) {
- LOGP(DNAT, LOGL_ERROR,
- "Wrong key for bsc nr %d fd: %d.\n", conf->nr,
- bsc->write_queue.bfd.fd);
- bsc_close_connection(bsc);
- return;
- }
-
- rate_ctr_inc(&conf->stats.ctrg->ctr[BCFG_CTR_NET_RECONN]);
- bsc->authenticated = 1;
- bsc->cfg = conf;
- osmo_timer_del(&bsc->id_timeout);
- LOGP(DNAT, LOGL_NOTICE, "Authenticated bsc nr: %d on fd %d\n",
- conf->nr, bsc->write_queue.bfd.fd);
- start_ping_pong(bsc);
-}
-
-static void handle_con_stats(struct nat_sccp_connection *con)
-{
- struct rate_ctr_group *ctrg;
- int id = bsc_conn_type_to_ctr(con);
-
- if (id == -1)
- return;
-
- if (!con->bsc || !con->bsc->cfg)
- return;
-
- ctrg = con->bsc->cfg->stats.ctrg;
- rate_ctr_inc(&ctrg->ctr[id]);
-}
-
-static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
-{
- int con_filter = 0;
- char *imsi = NULL;
- struct bsc_msc_connection *con_msc = NULL;
- struct bsc_connection *con_bsc = NULL;
- int con_type;
- struct bsc_nat_parsed *parsed;
- struct bsc_filter_reject_cause cause;
-
- /* Parse and filter messages */
- parsed = bsc_nat_parse(msg);
- if (!parsed) {
- LOGP(DNAT, LOGL_ERROR, "Can not parse msg from BSC.\n");
- msgb_free(msg);
- return -1;
- }
-
- if (bsc_nat_filter_ipa(DIR_MSC, msg, parsed))
- goto exit;
-
- /*
- * check authentication after filtering to not reject auth
- * responses coming from the BSC. We have to make sure that
- * nothing from the exit path will forward things to the MSC
- */
- if (!bsc->authenticated) {
- LOGP(DNAT, LOGL_ERROR, "BSC is not authenticated.\n");
- msgb_free(msg);
- return -1;
- }
-
-
- /* modify the SCCP entries */
- if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
- int filter;
- struct nat_sccp_connection *con;
- switch (parsed->sccp_type) {
- case SCCP_MSG_TYPE_CR:
- memset(&cause, 0, sizeof(cause));
- filter = bsc_nat_filter_sccp_cr(bsc, msg, parsed,
- &con_type, &imsi, &cause);
- if (filter < 0) {
- if (imsi)
- bsc_nat_inform_reject(bsc, imsi);
- bsc_stat_reject(filter, bsc, 0);
- goto exit3;
- }
-
- if (!create_sccp_src_ref(bsc, parsed))
- goto exit2;
- con = patch_sccp_src_ref_to_msc(msg, parsed, bsc);
- OSMO_ASSERT(con);
- con->msc_con = bsc->nat->msc_con;
- con_msc = con->msc_con;
- con->filter_state.con_type = con_type;
- con->filter_state.imsi_checked = filter;
- bsc_nat_extract_lac(bsc, con, parsed, msg);
- if (imsi)
- con->filter_state.imsi = talloc_steal(con, imsi);
- imsi = NULL;
- con_bsc = con->bsc;
- handle_con_stats(con);
- break;
- case SCCP_MSG_TYPE_RLSD:
- case SCCP_MSG_TYPE_CREF:
- case SCCP_MSG_TYPE_DT1:
- case SCCP_MSG_TYPE_CC:
- case SCCP_MSG_TYPE_IT:
- con = patch_sccp_src_ref_to_msc(msg, parsed, bsc);
- if (con) {
- /* only filter non local connections */
- if (!con->con_local) {
- memset(&cause, 0, sizeof(cause));
- filter = bsc_nat_filter_dt(bsc, msg,
- con, parsed, &cause);
- if (filter < 0) {
- if (con->filter_state.imsi)
- bsc_nat_inform_reject(bsc,
- con->filter_state.imsi);
- bsc_stat_reject(filter, bsc, 1);
- bsc_send_con_release(bsc, con, &cause);
- con = NULL;
- goto exit2;
- }
-
- /* hand data to a side channel */
- if (bsc_ussd_check(con, parsed, msg) == 1)
- con->con_local = NAT_CON_END_USSD;
-
- /*
- * Optionally rewrite setup message. This can
- * replace the msg and the parsed structure becomes
- * invalid.
- */
- msg = bsc_nat_rewrite_msg(bsc->nat, msg, parsed,
- con->filter_state.imsi);
- talloc_free(parsed);
- parsed = NULL;
- } else if (con->con_local == NAT_CON_END_USSD) {
- bsc_ussd_check(con, parsed, msg);
- }
-
- con_bsc = con->bsc;
- con_msc = con->msc_con;
- con_filter = con->con_local;
- }
-
- break;
- case SCCP_MSG_TYPE_RLC:
- 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;
- }
- remove_sccp_src_ref(bsc, msg, parsed);
- bsc_maybe_close(bsc);
- break;
- case SCCP_MSG_TYPE_UDT:
- /* simply forward everything */
- con = NULL;
- break;
- default:
- LOGP(DNAT, LOGL_ERROR, "Not forwarding to msc sccp type: 0x%x\n", parsed->sccp_type);
- con = NULL;
- goto exit2;
- break;
- }
- } else if (parsed->ipa_proto == IPAC_PROTO_MGCP_OLD) {
- bsc_mgcp_forward(bsc, msg);
- goto exit2;
- } else {
- LOGP(DNAT, LOGL_ERROR, "Not forwarding unknown stream id: 0x%x\n", parsed->ipa_proto);
- goto exit2;
- }
-
- if (con_msc && con_bsc != bsc) {
- LOGP(DNAT, LOGL_ERROR, "The connection belongs to a different BTS: input: %d con: %d\n",
- bsc->cfg->nr, con_bsc->cfg->nr);
- 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);
- if (parsed)
- talloc_free(parsed);
- return 0;
-
-exit:
- /* if we filter out the reset send an ack to the BSC */
- if (parsed->bssap == 0 && parsed->gsm_type == BSS_MAP_MSG_RESET) {
- send_reset_ack(bsc);
- send_reset_ack(bsc);
- } else if (parsed->ipa_proto == IPAC_PROTO_IPACCESS) {
- /* do we know who is handling this? */
- if (msg->l2h[0] == IPAC_MSGT_ID_RESP && msgb_l2len(msg) > 2) {
- struct tlv_parsed tvp;
- int ret;
- ret = ipa_ccm_idtag_parse_off(&tvp,
- (unsigned char *) msg->l2h + 2,
- msgb_l2len(msg) - 2, 0);
- if (ret < 0) {
- LOGP(DNAT, LOGL_ERROR, "ignoring IPA response "
- "message with malformed TLVs\n");
- return ret;
- }
- if (TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME))
- ipaccess_auth_bsc(&tvp, bsc);
- }
-
- goto exit2;
- }
-
-exit2:
- if (imsi)
- talloc_free(imsi);
- talloc_free(parsed);
- msgb_free(msg);
- return -1;
-
-exit3:
- /* send a SCCP Connection Refused */
- if (imsi)
- talloc_free(imsi);
- bsc_send_con_refuse(bsc, parsed, con_type, &cause);
- talloc_free(parsed);
- msgb_free(msg);
- return -1;
-}
-
-static int ipaccess_bsc_read_cb(struct osmo_fd *bfd)
-{
- struct bsc_connection *bsc = bfd->data;
- struct msgb *msg = NULL;
- struct ipaccess_head *hh;
- struct ipaccess_head_ext *hh_ext;
- int ret;
-
- ret = ipa_msg_recv_buffered(bfd->fd, &msg, &bsc->pending_msg);
- if (ret <= 0) {
- if (ret == -EAGAIN)
- return 0;
- if (ret == 0)
- LOGP(DNAT, LOGL_ERROR,
- "The connection to the BSC Nr: %d was lost. Cleaning it\n",
- bsc->cfg ? bsc->cfg->nr : -1);
- else
- LOGP(DNAT, LOGL_ERROR,
- "Stream error on BSC Nr: %d. Failed to parse ip access message: %d (%s)\n",
- bsc->cfg ? bsc->cfg->nr : -1, ret, strerror(-ret));
-
- bsc_close_connection(bsc);
- return -1;
- }
-
-
- LOGP(DNAT, LOGL_DEBUG, "MSG from BSC: %s proto: %d\n", osmo_hexdump(msg->data, msg->len), msg->l2h[0]);
-
- /* Handle messages from the BSC */
- hh = (struct ipaccess_head *) msg->data;
-
- /* stop the pong timeout */
- if (hh->proto == IPAC_PROTO_IPACCESS) {
- if (msg->l2h[0] == IPAC_MSGT_PONG) {
- osmo_timer_del(&bsc->pong_timeout);
- msgb_free(msg);
- return 0;
- } else if (msg->l2h[0] == IPAC_MSGT_PING) {
- send_pong(bsc);
- msgb_free(msg);
- return 0;
- }
- /* Message contains the ipaccess_head_ext header, investigate further */
- } else if (hh->proto == IPAC_PROTO_OSMO &&
- msg->len > sizeof(*hh) + sizeof(*hh_ext)) {
-
- hh_ext = (struct ipaccess_head_ext *) hh->data;
- /* l2h is where the actual command data is expected */
- msg->l2h = hh_ext->data;
-
- if (hh_ext->proto == IPAC_PROTO_EXT_CTRL)
- return bsc_nat_handle_ctrlif_msg(bsc, msg);
- }
-
- /* FIXME: Currently no PONG is sent to the BSC */
- /* FIXME: Currently no ID ACK is sent to the BSC */
- forward_sccp_to_msc(bsc, msg);
-
- return 0;
-}
-
-static int ipaccess_listen_bsc_cb(struct osmo_fd *bfd, unsigned int what)
-{
- struct bsc_connection *bsc;
- int fd, rc, on;
- struct sockaddr_in sa;
- socklen_t sa_len = sizeof(sa);
-
- if (!(what & BSC_FD_READ))
- return 0;
-
- fd = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len);
- if (fd < 0) {
- perror("accept");
- return fd;
- }
-
- /* count the reconnect */
- osmo_counter_inc(nat->stats.bsc.reconn);
-
- /*
- * if we are not connected to a msc... just close the socket
- */
- if (!bsc_nat_msc_is_connected(nat)) {
- LOGP(DNAT, LOGL_NOTICE, "Disconnecting BSC due lack of MSC connection.\n");
- close(fd);
- return 0;
- }
-
- if (nat->blocked) {
- LOGP(DNAT, LOGL_NOTICE, "Disconnecting BSC due NAT being blocked.\n");
- close(fd);
- return 0;
- }
-
- on = 1;
- rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
- if (rc != 0)
- LOGP(DNAT, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
-
- rc = setsockopt(fd, IPPROTO_IP, IP_TOS,
- &nat->bsc_ip_dscp, sizeof(nat->bsc_ip_dscp));
- if (rc != 0)
- LOGP(DNAT, LOGL_ERROR, "Failed to set IP_TOS: %s\n", strerror(errno));
-
- /* todo... do something with the connection */
- /* todo... use GNUtls to see if we want to trust this as a BTS */
-
- /*
- *
- */
- bsc = bsc_connection_alloc(nat);
- if (!bsc) {
- LOGP(DNAT, LOGL_ERROR, "Failed to allocate BSC struct.\n");
- close(fd);
- return -1;
- }
-
- bsc->write_queue.bfd.data = bsc;
- bsc->write_queue.bfd.fd = fd;
- bsc->write_queue.read_cb = ipaccess_bsc_read_cb;
- bsc->write_queue.write_cb = bsc_write_cb;
- bsc->write_queue.bfd.when = BSC_FD_READ;
- if (osmo_fd_register(&bsc->write_queue.bfd) < 0) {
- LOGP(DNAT, LOGL_ERROR, "Failed to register BSC fd.\n");
- close(fd);
- talloc_free(bsc);
- return -2;
- }
-
- LOGP(DNAT, LOGL_NOTICE, "BSC connection on %d with IP: %s\n",
- fd, inet_ntoa(sa.sin_addr));
-
- llist_add(&bsc->list_entry, &nat->bsc_connections);
- bsc->last_id = 0;
-
- send_id_ack(bsc);
- send_id_req(nat, bsc);
- send_mgcp_reset(bsc);
-
- /*
- * start the hangup timer
- */
- osmo_timer_setup(&bsc->id_timeout, ipaccess_close_bsc, bsc);
- osmo_timer_schedule(&bsc->id_timeout, nat->auth_timeout, 0);
- return 0;
-}
-
-static void print_usage()
-{
- printf("Usage: bsc_nat\n");
-}
-
-static void print_help()
-{
- printf(" Some useful help...\n");
- printf(" -h --help this text\n");
- printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n");
- printf(" -D --daemonize Fork the process into a background daemon\n");
- printf(" -s --disable-color\n");
- printf(" -c --config-file filename The config file to use.\n");
- printf(" -m --msc=IP. The address of the MSC.\n");
- printf(" -l --local=IP. The local address of this BSC.\n");
-}
-
-static void handle_options(int argc, char **argv)
-{
- while (1) {
- int option_index = 0, c;
- static struct option long_options[] = {
- {"help", 0, 0, 'h'},
- {"debug", 1, 0, 'd'},
- {"daemonize", 0, 0, 'D'},
- {"config-file", 1, 0, 'c'},
- {"disable-color", 0, 0, 's'},
- {"timestamp", 0, 0, 'T'},
- {"msc", 1, 0, 'm'},
- {"local", 1, 0, 'l'},
- {0, 0, 0, 0}
- };
-
- c = getopt_long(argc, argv, "hd:sTPc:m:l:D",
- long_options, &option_index);
- if (c == -1)
- break;
-
- switch (c) {
- case 'h':
- print_usage();
- print_help();
- exit(0);
- case 's':
- log_set_use_color(osmo_stderr_target, 0);
- break;
- case 'd':
- log_parse_category_mask(osmo_stderr_target, optarg);
- break;
- case 'D':
- daemonize = 1;
- break;
- case 'c':
- config_file = optarg;
- break;
- case 'T':
- log_set_print_timestamp(osmo_stderr_target, 1);
- break;
- case 'm':
- msc_ip = optarg;
- break;
- case 'l':
- inet_aton(optarg, &local_addr);
- break;
- default:
- /* ignore */
- break;
- }
- }
-}
-
-static void signal_handler(int signal)
-{
- switch (signal) {
- case SIGABRT:
- /* in case of abort, we want to obtain a talloc report
- * and then return to the caller, who will abort the process */
- case SIGUSR1:
- talloc_report_full(tall_bsc_ctx, stderr);
- break;
- default:
- break;
- }
-}
-
-static void sccp_close_unconfirmed(void *_data)
-{
- int destroyed = 0;
- struct bsc_connection *bsc, *bsc_tmp;
- struct nat_sccp_connection *conn, *tmp1;
- struct timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
-
- llist_for_each_entry_safe(conn, tmp1, &nat->sccp_connections, list_entry) {
- if (conn->has_remote_ref)
- continue;
-
- int diff = (now.tv_sec - conn->creation_time.tv_sec) / 60;
- if (diff < SCCP_CLOSE_TIME_TIMEOUT)
- continue;
-
- LOGP(DNAT, LOGL_ERROR,
- "SCCP connection 0x%x/0x%x was never confirmed on bsc nr. %d\n",
- sccp_src_ref_to_int(&conn->real_ref),
- sccp_src_ref_to_int(&conn->patched_ref),
- conn->bsc->cfg->nr);
- sccp_connection_destroy(conn);
- destroyed = 1;
- }
-
- if (!destroyed)
- goto out;
-
- /* now close out any BSC */
- llist_for_each_entry_safe(bsc, bsc_tmp, &nat->bsc_connections, list_entry)
- bsc_maybe_close(bsc);
-
-out:
- osmo_timer_schedule(&sccp_close, SCCP_CLOSE_TIME, 0);
-}
-
-extern void *tall_ctr_ctx;
-static void talloc_init_ctx()
-{
- tall_bsc_ctx = talloc_named_const(NULL, 0, "nat");
- msgb_talloc_ctx_init(tall_bsc_ctx, 0);
- tall_ctr_ctx = talloc_named_const(tall_bsc_ctx, 0, "counter");
-}
-
-extern int bsc_vty_go_parent(struct vty *vty);
-
-static struct vty_app_info vty_info = {
- .name = "OsmoBSCNAT",
- .version = PACKAGE_VERSION,
- .go_parent_cb = bsc_vty_go_parent,
- .is_config_node = bsc_vty_is_config_node,
-};
-
-
-int main(int argc, char **argv)
-{
- int rc;
-
- talloc_init_ctx();
-
- osmo_init_logging(&log_info);
-
- nat = bsc_nat_alloc();
- if (!nat) {
- fprintf(stderr, "Failed to allocate the BSC nat.\n");
- return -4;
- }
-
- nat->mgcp_cfg = mgcp_config_alloc();
- if (!nat->mgcp_cfg) {
- fprintf(stderr, "Failed to allocate MGCP cfg.\n");
- return -5;
- }
-
- /* We need to add mode-set for amr codecs */
- nat->sdp_ensure_amr_mode_set = 1;
-
- vty_info.copyright = openbsc_copyright;
- vty_init(&vty_info);
- logging_vty_add_cmds(NULL);
- osmo_stats_vty_add_cmds(&log_info);
- bsc_nat_vty_init(nat);
- ctrl_vty_init(tall_bsc_ctx);
-
-
- /* parse options */
- local_addr.s_addr = INADDR_ANY;
- handle_options(argc, argv);
-
- nat->include_base = dirname(talloc_strdup(tall_bsc_ctx, config_file));
-
- rate_ctr_init(tall_bsc_ctx);
- osmo_stats_init(tall_bsc_ctx);
-
- /* Ensure that forced enpoint allocation is turned on by default */
- nat->mgcp_cfg->trunk.force_realloc = 1;
-
- /* init vty and parse */
- if (mgcp_parse_config(config_file, nat->mgcp_cfg, MGCP_BSC_NAT) < 0) {
- fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
- return -3;
- }
-
- /* start telnet after reading config for vty_get_bind_addr() */
- if (telnet_init_dynif(tall_bsc_ctx, NULL, vty_get_bind_addr(),
- OSMO_VTY_PORT_BSC_NAT)) {
- fprintf(stderr, "Creating VTY telnet line failed\n");
- return -5;
- }
-
- /* over rule the VTY config for MSC IP */
- if (msc_ip)
- bsc_nat_set_msc_ip(nat, msc_ip);
-
- /* seed the PRNG */
- srand(time(NULL));
-
- LOGP(DNAT, LOGL_NOTICE, "BSCs configured from %s\n", nat->resolved_path);
-
- /*
- * Setup the MGCP code..
- */
- if (bsc_mgcp_nat_init(nat) != 0)
- return -4;
-
- /* connect to the MSC */
- nat->msc_con = bsc_msc_create(nat, &nat->dests);
- if (!nat->msc_con) {
- fprintf(stderr, "Creating a bsc_msc_connection failed.\n");
- exit(1);
- }
-
- /* start control interface after reading config for
- * ctrl_vty_get_bind_addr() */
- nat->ctrl = bsc_nat_controlif_setup(nat, ctrl_vty_get_bind_addr(),
- OSMO_CTRL_PORT_BSC_NAT);
- if (!nat->ctrl) {
- fprintf(stderr, "Creating the control interface failed.\n");
- exit(1);
- }
-
- nat->msc_con->name = "main MSC";
- nat->msc_con->connection_loss = msc_connection_was_lost;
- nat->msc_con->connected = msc_connection_connected;
- nat->msc_con->write_queue.read_cb = ipaccess_msc_read_cb;
- nat->msc_con->write_queue.write_cb = ipaccess_msc_write_cb;;
- nat->msc_con->write_queue.bfd.data = nat->msc_con;
- bsc_msc_connect(nat->msc_con);
-
- /* wait for the BSC */
- rc = make_sock(&bsc_listen, IPPROTO_TCP, ntohl(local_addr.s_addr),
- 5000, 0, ipaccess_listen_bsc_cb, nat);
- if (rc != 0) {
- fprintf(stderr, "Failed to listen for BSC.\n");
- exit(1);
- }
-
- rc = bsc_ussd_init(nat);
- if (rc != 0) {
- LOGP(DNAT, LOGL_ERROR, "Failed to bind the USSD socket.\n");
- exit(1);
- }
-
- signal(SIGABRT, &signal_handler);
- signal(SIGUSR1, &signal_handler);
- osmo_init_ignore_signals();
-
- if (daemonize) {
- rc = osmo_daemonize();
- if (rc < 0) {
- perror("Error during daemonize");
- exit(1);
- }
- }
-
- /* recycle timer */
- sccp_set_log_area(DSCCP);
- osmo_timer_setup(&sccp_close, sccp_close_unconfirmed, NULL);
- osmo_timer_schedule(&sccp_close, SCCP_CLOSE_TIME, 0);
-
- while (1) {
- osmo_select_main(0);
- }
-
- return 0;
-}
-
-/* Close all connections handed out to the USSD module */
-int bsc_ussd_close_connections(struct bsc_nat *nat)
-{
- struct nat_sccp_connection *con;
- llist_for_each_entry(con, &nat->sccp_connections, list_entry) {
- if (con->con_local != NAT_CON_END_USSD)
- continue;
- if (!con->bsc)
- continue;
-
- nat_send_clrc_bsc(con);
- nat_send_rlsd_bsc(con);
- }
-
- return 0;
-}
diff --git a/src/osmo-bsc_nat/bsc_nat_ctrl.c b/src/osmo-bsc_nat/bsc_nat_ctrl.c
deleted file mode 100644
index ff6a73978..000000000
--- a/src/osmo-bsc_nat/bsc_nat_ctrl.c
+++ /dev/null
@@ -1,525 +0,0 @@
-/*
- * (C) 2011-2012 by Holger Hans Peter Freyther
- * (C) 2011-2012 by On-Waves
- * (C) 2011 by Daniel Willmann
- * 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/talloc.h>
-
-#include <osmocom/ctrl/control_cmd.h>
-#include <osmocom/ctrl/control_if.h>
-#include <osmocom/ctrl/ports.h>
-
-#include <osmocom/vty/misc.h>
-
-#include <openbsc/ctrl.h>
-#include <openbsc/bsc_nat.h>
-#include <openbsc/bsc_msg_filter.h>
-#include <openbsc/vty.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/debug.h>
-
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-
-
-#define NAT_MAX_CTRL_ID 65535
-
-static struct bsc_nat *g_nat;
-
-static int bsc_id_unused(int id, struct bsc_connection *bsc)
-{
- struct bsc_cmd_list *pending;
-
- llist_for_each_entry(pending, &bsc->cmd_pending, list_entry) {
- if (pending->nat_id == id)
- return 0;
- }
- return 1;
-}
-
-static int get_next_free_bsc_id(struct bsc_connection *bsc)
-{
- int new_id, overflow = 0;
-
- new_id = bsc->last_id;
-
- do {
- new_id++;
- if (new_id == NAT_MAX_CTRL_ID) {
- new_id = 1;
- overflow++;
- }
-
- if (bsc_id_unused(new_id, bsc)) {
- bsc->last_id = new_id;
- return new_id;
- }
- } while (overflow != 2);
-
- return -1;
-}
-
-void bsc_nat_ctrl_del_pending(struct bsc_cmd_list *pending)
-{
- llist_del(&pending->list_entry);
- osmo_timer_del(&pending->timeout);
- talloc_free(pending->cmd);
- talloc_free(pending);
-}
-
-static struct bsc_cmd_list *bsc_get_pending(struct bsc_connection *bsc, char *id_str)
-{
- struct bsc_cmd_list *cmd_entry;
- int id = atoi(id_str);
- if (id == 0)
- return NULL;
-
- llist_for_each_entry(cmd_entry, &bsc->cmd_pending, list_entry) {
- if (cmd_entry->nat_id == id) {
- return cmd_entry;
- }
- }
- return NULL;
-}
-
-int bsc_nat_handle_ctrlif_msg(struct bsc_connection *bsc, struct msgb *msg)
-{
- struct ctrl_cmd *cmd;
- struct bsc_cmd_list *pending;
- char *var, *id;
-
- cmd = ctrl_cmd_parse(bsc, msg);
- msgb_free(msg);
-
- if (!cmd) {
- cmd = talloc_zero(bsc, struct ctrl_cmd);
- if (!cmd) {
- LOGP(DNAT, LOGL_ERROR, "OOM!\n");
- return -ENOMEM;
- }
- cmd->type = CTRL_TYPE_ERROR;
- cmd->id = "err";
- cmd->reply = "Failed to parse command.";
- goto err;
- }
-
- if (bsc->cfg && !llist_empty(&bsc->cfg->lac_list)) {
- if (cmd->variable) {
- var = talloc_asprintf(cmd, "net.0.bsc.%i.%s", bsc->cfg->nr,
- cmd->variable);
- if (!var) {
- cmd->type = CTRL_TYPE_ERROR;
- cmd->reply = "OOM";
- goto err;
- }
- talloc_free(cmd->variable);
- cmd->variable = var;
- }
-
- /* We have to handle TRAPs before matching pending */
- if (cmd->type == CTRL_TYPE_TRAP) {
- ctrl_cmd_send_to_all(bsc->nat->ctrl, cmd);
- talloc_free(cmd);
- return 0;
- }
-
- /* Find the pending command */
- pending = bsc_get_pending(bsc, cmd->id);
- if (pending) {
- id = talloc_strdup(cmd, pending->cmd->id);
- if (!id) {
- cmd->type = CTRL_TYPE_ERROR;
- cmd->reply = "OOM";
- goto err;
- }
- cmd->id = id;
- ctrl_cmd_send(&pending->ccon->write_queue, cmd);
- bsc_nat_ctrl_del_pending(pending);
- } else {
- /* We need to handle TRAPS here */
- if ((cmd->type != CTRL_TYPE_ERROR) &&
- (cmd->type != CTRL_TYPE_TRAP)) {
- LOGP(DNAT, LOGL_NOTICE, "Got control message "
- "from BSC without pending entry\n");
- cmd->type = CTRL_TYPE_ERROR;
- cmd->reply = "No request outstanding";
- goto err;
- }
- }
- }
- talloc_free(cmd);
- return 0;
-err:
- ctrl_cmd_send(&bsc->write_queue, cmd);
- talloc_free(cmd);
- return 0;
-}
-
-static void pending_timeout_cb(void *data)
-{
- struct bsc_cmd_list *pending = data;
- LOGP(DNAT, LOGL_ERROR, "Command timed out\n");
- pending->cmd->type = CTRL_TYPE_ERROR;
- pending->cmd->reply = "Command timed out";
- ctrl_cmd_send(&pending->ccon->write_queue, pending->cmd);
-
- bsc_nat_ctrl_del_pending(pending);
-}
-
-static void ctrl_conn_closed_cb(struct ctrl_connection *connection)
-{
- struct bsc_connection *bsc;
- struct bsc_cmd_list *pending, *tmp;
-
- llist_for_each_entry(bsc, &g_nat->bsc_connections, list_entry) {
- llist_for_each_entry_safe(pending, tmp, &bsc->cmd_pending, list_entry) {
- if (pending->ccon == connection)
- bsc_nat_ctrl_del_pending(pending);
- }
- }
-}
-
-static int extract_bsc_nr_variable(char *variable, unsigned int *nr, char **bsc_variable)
-{
- char *nr_str, *tmp, *saveptr = NULL;
-
- tmp = strtok_r(variable, ".", &saveptr);
- tmp = strtok_r(NULL, ".", &saveptr);
- tmp = strtok_r(NULL, ".", &saveptr);
- nr_str = strtok_r(NULL, ".", &saveptr);
- if (!nr_str)
- return 0;
- *nr = atoi(nr_str);
-
- tmp = strtok_r(NULL, "\0", &saveptr);
- if (!tmp)
- return 0;
-
- *bsc_variable = tmp;
- return 1;
-}
-
-static int forward_to_bsc(struct ctrl_cmd *cmd)
-{
- int ret = CTRL_CMD_HANDLED;
- struct ctrl_cmd *bsc_cmd = NULL;
- struct bsc_connection *bsc;
- struct bsc_cmd_list *pending;
- unsigned int nr;
- char *bsc_variable;
-
- /* Skip over the beginning (bsc.) */
- if (!extract_bsc_nr_variable(cmd->variable, &nr, &bsc_variable)) {
- cmd->reply = "command incomplete";
- goto err;
- }
-
-
- llist_for_each_entry(bsc, &g_nat->bsc_connections, list_entry) {
- if (!bsc->cfg)
- continue;
- if (!bsc->authenticated)
- continue;
- if (bsc->cfg->nr == nr) {
- /* Add pending command to list */
- pending = talloc_zero(bsc, struct bsc_cmd_list);
- if (!pending) {
- cmd->reply = "OOM";
- goto err;
- }
-
- pending->nat_id = get_next_free_bsc_id(bsc);
- if (pending->nat_id < 0) {
- cmd->reply = "No free ID found";
- goto err;
- }
-
- bsc_cmd = ctrl_cmd_cpy(bsc, cmd);
- if (!bsc_cmd) {
- cmd->reply = "Could not forward command";
- goto err;
- }
-
- talloc_free(bsc_cmd->id);
- bsc_cmd->id = talloc_asprintf(bsc_cmd, "%i", pending->nat_id);
- if (!bsc_cmd->id) {
- cmd->reply = "OOM";
- goto err;
- }
-
- talloc_free(bsc_cmd->variable);
- bsc_cmd->variable = talloc_strdup(bsc_cmd, bsc_variable);
- if (!bsc_cmd->variable) {
- cmd->reply = "OOM";
- goto err;
- }
-
- if (ctrl_cmd_send(&bsc->write_queue, bsc_cmd)) {
- cmd->reply = "Sending failed";
- goto err;
- }
- pending->ccon = cmd->ccon;
- pending->ccon->closed_cb = ctrl_conn_closed_cb;
- pending->cmd = cmd;
-
- /* Setup the timeout */
- osmo_timer_setup(&pending->timeout, pending_timeout_cb,
- pending);
- /* TODO: Make timeout configurable */
- osmo_timer_schedule(&pending->timeout, 10, 0);
- llist_add_tail(&pending->list_entry, &bsc->cmd_pending);
-
- goto done;
- }
- }
- /* We end up here if there's no bsc to handle our LAC */
- cmd->reply = "no BSC with this nr";
-err:
- ret = CTRL_CMD_ERROR;
-done:
- talloc_free(bsc_cmd);
- return ret;
-
-}
-
-
-CTRL_CMD_DEFINE(fwd_cmd, "net 0 bsc *");
-static int get_fwd_cmd(struct ctrl_cmd *cmd, void *data)
-{
- return forward_to_bsc(cmd);
-}
-
-static int set_fwd_cmd(struct ctrl_cmd *cmd, void *data)
-{
- return forward_to_bsc(cmd);
-}
-
-static int verify_fwd_cmd(struct ctrl_cmd *cmd, const char *value, void *data)
-{
- return 0;
-}
-
-static int extract_bsc_cfg_variable(struct ctrl_cmd *cmd, struct bsc_config **cfg,
- char **bsc_variable)
-{
- unsigned int nr;
-
- if (!extract_bsc_nr_variable(cmd->variable, &nr, bsc_variable)) {
- cmd->reply = "command incomplete";
- return 0;
- }
-
- *cfg = bsc_config_num(g_nat, nr);
- if (!*cfg) {
- cmd->reply = "Unknown BSC";
- return 0;
- }
-
- return 1;
-}
-
-CTRL_CMD_DEFINE(net_cfg_cmd, "net 0 bsc_cfg *");
-static int get_net_cfg_cmd(struct ctrl_cmd *cmd, void *data)
-{
- char *bsc_variable;
- struct bsc_config *bsc_cfg;
-
- if (!extract_bsc_cfg_variable(cmd, &bsc_cfg, &bsc_variable))
- return CTRL_CMD_ERROR;
-
- if (strcmp(bsc_variable, "access-list-name") == 0) {
- cmd->reply = talloc_asprintf(cmd, "%s",
- bsc_cfg->acc_lst_name ? bsc_cfg->acc_lst_name : "");
- return CTRL_CMD_REPLY;
- }
-
- cmd->reply = "unknown command";
- return CTRL_CMD_ERROR;
-}
-
-static int set_net_cfg_cmd(struct ctrl_cmd *cmd, void *data)
-{
- char *bsc_variable;
- struct bsc_config *bsc_cfg;
-
- if (!extract_bsc_cfg_variable(cmd, &bsc_cfg, &bsc_variable))
- return CTRL_CMD_ERROR;
-
- if (strcmp(bsc_variable, "access-list-name") == 0) {
- osmo_talloc_replace_string(bsc_cfg, &bsc_cfg->acc_lst_name, cmd->value);
- cmd->reply = talloc_asprintf(cmd, "%s",
- bsc_cfg->acc_lst_name ? bsc_cfg->acc_lst_name : "");
- return CTRL_CMD_REPLY;
- } else if (strcmp(bsc_variable, "no-access-list-name") == 0) {
- talloc_free(bsc_cfg->acc_lst_name);
- bsc_cfg->acc_lst_name = NULL;
- cmd->reply = "";
- return CTRL_CMD_REPLY;
- }
-
- cmd->reply = "unknown command";
- return CTRL_CMD_ERROR;
-}
-
-static int verify_net_cfg_cmd(struct ctrl_cmd *cmd, const char *value, void *data)
-{
- return 0;
-}
-
-CTRL_CMD_DEFINE(net_cfg_acc_cmd, "net 0 add allow access-list *");
-static const char *extract_acc_name(const char *var)
-{
- char *str;
-
- str = strstr(var, "net.0.add.allow.access-list.");
- if (!str)
- return NULL;
- str += strlen("net.0.add.allow.access-list.");
- if (strlen(str) == 0)
- return NULL;
- return str;
-}
-
-static int get_net_cfg_acc_cmd(struct ctrl_cmd *cmd, void *data)
-{
- cmd->reply = "Append only";
- return CTRL_CMD_ERROR;
-}
-
-static int set_net_cfg_acc_cmd(struct ctrl_cmd *cmd, void *data)
-{
- const char *access_name = extract_acc_name(cmd->variable);
- struct bsc_msg_acc_lst *acc;
- struct bsc_msg_acc_lst_entry *entry;
- const char *value = cmd->value;
- int rc;
-
- /* Should have been caught by verify_net_cfg_acc_cmd */
- acc = bsc_msg_acc_lst_find(&g_nat->access_lists, access_name);
- if (!acc) {
- cmd->reply = "Access list not found";
- return CTRL_CMD_ERROR;
- }
-
- entry = bsc_msg_acc_lst_entry_create(acc);
- if (!entry) {
- cmd->reply = "OOM";
- return CTRL_CMD_ERROR;
- }
-
- rc = gsm_parse_reg(acc, &entry->imsi_allow_re, &entry->imsi_allow, 1, &value);
- if (rc != 0) {
- cmd->reply = "Failed to compile expression";
- return CTRL_CMD_ERROR;
- }
-
- cmd->reply = "IMSI allow added to access list";
- return CTRL_CMD_REPLY;
-}
-
-static int verify_net_cfg_acc_cmd(struct ctrl_cmd *cmd, const char *value, void *data)
-{
- const char *access_name = extract_acc_name(cmd->variable);
- struct bsc_msg_acc_lst *acc = bsc_msg_acc_lst_find(&g_nat->access_lists, access_name);
-
- if (!acc) {
- cmd->reply = "Access list not known";
- return -1;
- }
-
- return 0;
-}
-
-CTRL_CMD_DEFINE_WO_NOVRF(net_save_cmd, "net 0 save-configuration");
-
-static int set_net_save_cmd(struct ctrl_cmd *cmd, void *data)
-{
- int rc = osmo_vty_save_config_file();
- cmd->reply = talloc_asprintf(cmd, "%d", rc);
- if (!cmd->reply) {
- cmd->reply = "OOM";
- return CTRL_CMD_ERROR;
- }
-
- return CTRL_CMD_REPLY;
-}
-
-struct ctrl_handle *bsc_nat_controlif_setup(struct bsc_nat *nat,
- const char *bind_addr, int port)
-{
- struct ctrl_handle *ctrl;
- int rc;
-
-
- ctrl = bsc_controlif_setup(NULL, bind_addr, OSMO_CTRL_PORT_BSC_NAT);
- if (!ctrl) {
- fprintf(stderr, "Failed to initialize the control interface. Exiting.\n");
- return NULL;
- }
-
- rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_fwd_cmd);
- if (rc) {
- fprintf(stderr, "Failed to install the control command. Exiting.\n");
- goto error;
- }
- rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_cfg_cmd);
- if (rc) {
- fprintf(stderr, "Failed to install the net cfg command. Exiting.\n");
- goto error;
- }
- rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_cfg_acc_cmd);
- if (rc) {
- fprintf(stderr, "Failed to install the net acc command. Exiting.\n");
- goto error;
- }
- rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_save_cmd);
- if (rc) {
- fprintf(stderr, "Failed to install the net save command. Exiting.\n");
- goto error;
- }
-
- g_nat = nat;
- return ctrl;
-
-error:
- osmo_fd_unregister(&ctrl->listen_fd);
- close(ctrl->listen_fd.fd);
- talloc_free(ctrl);
- return NULL;
-}
-
-void bsc_nat_inform_reject(struct bsc_connection *conn, const char *imsi)
-{
- struct ctrl_cmd *cmd;
-
- cmd = ctrl_cmd_create(conn, CTRL_TYPE_TRAP);
- if (!cmd) {
- LOGP(DCTRL, LOGL_ERROR, "Failed to create TRAP command.\n");
- return;
- }
-
- cmd->id = "0";
- cmd->variable = talloc_asprintf(cmd, "net.0.bsc.%d.notification-rejection-v1",
- conn->cfg->nr);
- cmd->reply = talloc_asprintf(cmd, "imsi=%s", imsi);
-
- ctrl_cmd_send_to_all(conn->cfg->nat->ctrl, cmd);
- talloc_free(cmd);
-}
diff --git a/src/osmo-bsc_nat/bsc_nat_filter.c b/src/osmo-bsc_nat/bsc_nat_filter.c
deleted file mode 100644
index e73529097..000000000
--- a/src/osmo-bsc_nat/bsc_nat_filter.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * (C) 2010-2015 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010-2012 by On-Waves
- * 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 <openbsc/bsc_nat.h>
-#include <openbsc/bsc_nat_sccp.h>
-#include <openbsc/bsc_msg_filter.h>
-#include <openbsc/debug.h>
-
-#include <osmocom/gsm/gsm0808.h>
-
-#include <osmocom/gsm/protocol/gsm_08_08.h>
-#include <osmocom/gsm/protocol/gsm_04_11.h>
-
-#include <osmocom/sccp/sccp.h>
-
-/* Filter out CR data... */
-int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg,
- struct bsc_nat_parsed *parsed, int *con_type,
- char **imsi, struct bsc_filter_reject_cause *cause)
-{
- struct bsc_filter_request req;
- struct tlv_parsed tp;
- struct gsm48_hdr *hdr48;
- int hdr48_len;
- int len;
-
- *con_type = FLT_CON_TYPE_NONE;
- cause->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED;
- cause->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED;
- *imsi = NULL;
-
- if (parsed->gsm_type != BSS_MAP_MSG_COMPLETE_LAYER_3) {
- LOGP(DNAT, LOGL_ERROR,
- "Rejecting CR message due wrong GSM Type %d\n", parsed->gsm_type);
- return -1;
- }
-
- /* the parsed has had some basic l3 length check */
- len = msg->l3h[1];
- if (msgb_l3len(msg) - 3 < len) {
- LOGP(DNAT, LOGL_ERROR,
- "The CR Data has not enough space...\n");
- return -1;
- }
-
- msg->l4h = &msg->l3h[3];
- len -= 1;
-
- tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h, len, 0, 0);
-
- if (!TLVP_PRESENT(&tp, GSM0808_IE_LAYER_3_INFORMATION)) {
- LOGP(DNAT, LOGL_ERROR, "CR Data does not contain layer3 information.\n");
- return -1;
- }
-
- hdr48_len = TLVP_LEN(&tp, GSM0808_IE_LAYER_3_INFORMATION);
-
- if (hdr48_len < sizeof(*hdr48)) {
- LOGP(DNAT, LOGL_ERROR, "GSM48 header does not fit.\n");
- return -1;
- }
-
- hdr48 = (struct gsm48_hdr *) TLVP_VAL(&tp, GSM0808_IE_LAYER_3_INFORMATION);
- req.ctx = bsc;
- req.black_list = &bsc->nat->imsi_black_list;
- req.access_lists = &bsc->nat->access_lists;
- req.local_lst_name = bsc->cfg->acc_lst_name;
- req.global_lst_name = bsc->nat->acc_lst_name;
- req.bsc_nr = bsc->cfg->nr;
- return bsc_msg_filter_initial(hdr48, hdr48_len, &req, con_type, imsi, cause);
-}
-
-int bsc_nat_filter_dt(struct bsc_connection *bsc, struct msgb *msg,
- struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed,
- struct bsc_filter_reject_cause *cause)
-{
- uint32_t len;
- struct gsm48_hdr *hdr48;
- struct bsc_filter_request req;
-
- cause->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED;
- cause->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED;
-
- if (con->filter_state.imsi_checked)
- return 0;
-
- /* only care about DTAP messages */
- if (parsed->bssap != BSSAP_MSG_DTAP)
- return 0;
-
- hdr48 = bsc_unpack_dtap(parsed, msg, &len);
- if (!hdr48)
- return -1;
-
- req.ctx = con;
- req.black_list = &bsc->nat->imsi_black_list;
- req.access_lists = &bsc->nat->access_lists;
- req.local_lst_name = bsc->cfg->acc_lst_name;
- req.global_lst_name = bsc->nat->acc_lst_name;
- req.bsc_nr = bsc->cfg->nr;
- return bsc_msg_filter_data(hdr48, len, &req, &con->filter_state, cause);
-}
diff --git a/src/osmo-bsc_nat/bsc_nat_rewrite.c b/src/osmo-bsc_nat/bsc_nat_rewrite.c
deleted file mode 100644
index e7c387c22..000000000
--- a/src/osmo-bsc_nat/bsc_nat_rewrite.c
+++ /dev/null
@@ -1,714 +0,0 @@
-/*
- * Message rewriting functionality
- */
-/*
- * (C) 2010-2013 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010-2013 by On-Waves
- * 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 <openbsc/bsc_nat.h>
-#include <openbsc/bsc_nat_sccp.h>
-#include <openbsc/bsc_msc.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/debug.h>
-#include <openbsc/ipaccess.h>
-#include <openbsc/nat_rewrite_trie.h>
-
-#include <osmocom/core/linuxlist.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/utils.h>
-#include <osmocom/gsm/gsm0808.h>
-#include <osmocom/gsm/ipa.h>
-
-#include <osmocom/gsm/protocol/gsm_08_08.h>
-#include <osmocom/gsm/protocol/gsm_04_11.h>
-
-#include <osmocom/sccp/sccp.h>
-
-static char *trie_lookup(struct nat_rewrite *trie, const char *number,
- regoff_t off, void *ctx)
-{
- struct nat_rewrite_rule *rule;
-
- if (!trie) {
- LOGP(DCC, LOGL_ERROR,
- "Asked to do a table lookup but no table.\n");
- return NULL;
- }
-
- rule = nat_rewrite_lookup(trie, number);
- if (!rule) {
- LOGP(DCC, LOGL_DEBUG,
- "Couldn't find a prefix rule for %s\n", number);
- return NULL;
- }
-
- return talloc_asprintf(ctx, "%s%s", rule->rewrite, &number[off]);
-}
-
-static char *match_and_rewrite_number(void *ctx, const char *number,
- const char *imsi, struct llist_head *list,
- struct nat_rewrite *trie)
-{
- struct bsc_nat_num_rewr_entry *entry;
- char *new_number = NULL;
-
- /* need to find a replacement and then fix it */
- llist_for_each_entry(entry, list, list) {
- regmatch_t matches[2];
-
- /* check the IMSI match */
- if (regexec(&entry->msisdn_reg, imsi, 0, NULL, 0) != 0)
- continue;
-
- /* this regexp matches... */
- if (regexec(&entry->num_reg, number, 2, matches, 0) == 0
- && matches[1].rm_eo != -1) {
- if (entry->is_prefix_lookup)
- new_number = trie_lookup(trie, number,
- matches[1].rm_so, ctx);
- else
- new_number = talloc_asprintf(ctx, "%s%s",
- entry->replace,
- &number[matches[1].rm_so]);
- }
-
- if (new_number)
- break;
- }
-
- return new_number;
-}
-
-static char *rewrite_isdn_number(struct bsc_nat *nat, struct llist_head *rewr_list,
- void *ctx, const char *imsi,
- struct gsm_mncc_number *called)
-{
- char int_number[sizeof(called->number) + 2];
- char *number = called->number;
-
- if (llist_empty(&nat->num_rewr)) {
- LOGP(DCC, LOGL_DEBUG, "Rewrite rules empty.\n");
- return NULL;
- }
-
- /* only ISDN plan */
- if (called->plan != 1) {
- LOGP(DCC, LOGL_DEBUG, "Called plan is not 1 it was %d\n",
- called->plan);
- return NULL;
- }
-
- /* international, prepend */
- if (called->type == 1) {
- int_number[0] = '+';
- memcpy(&int_number[1], number, strlen(number) + 1);
- number = int_number;
- }
-
- return match_and_rewrite_number(ctx, number,
- imsi, rewr_list, nat->num_rewr_trie);
-}
-
-static void update_called_number(struct gsm_mncc_number *called,
- const char *chosen_number)
-{
- if (strncmp(chosen_number, "00", 2) == 0) {
- called->type = 1;
- osmo_strlcpy(called->number, chosen_number + 2,
- sizeof(called->number));
- } else {
- /* rewrite international to unknown */
- if (called->type == 1)
- called->type = 0;
- osmo_strlcpy(called->number, chosen_number,
- sizeof(called->number));
- }
-}
-
-/**
- * Rewrite non global numbers... according to rules based on the IMSI
- */
-static struct msgb *rewrite_setup(struct bsc_nat *nat, struct msgb *msg,
- struct bsc_nat_parsed *parsed, const char *imsi,
- struct gsm48_hdr *hdr48, const uint32_t len)
-{
- struct tlv_parsed tp;
- unsigned int payload_len;
- struct gsm_mncc_number called;
- struct msgb *out;
- char *new_number_pre = NULL, *new_number_post = NULL, *chosen_number;
- uint8_t *outptr;
- const uint8_t *msgptr;
- int sec_len;
-
- /* decode and rewrite the message */
- payload_len = len - sizeof(*hdr48);
- tlv_parse(&tp, &gsm48_att_tlvdef, hdr48->data, payload_len, 0, 0);
-
- /* no number, well let us ignore it */
- if (!TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD))
- return NULL;
-
- memset(&called, 0, sizeof(called));
- gsm48_decode_called(&called,
- TLVP_VAL(&tp, GSM48_IE_CALLED_BCD) - 1);
-
- /* check if it looks international and stop */
- LOGP(DCC, LOGL_DEBUG,
- "Pre-Rewrite for IMSI(%s) Plan(%d) Type(%d) Number(%s)\n",
- imsi, called.plan, called.type, called.number);
- new_number_pre = rewrite_isdn_number(nat, &nat->num_rewr, msg, imsi, &called);
-
- if (!new_number_pre) {
- LOGP(DCC, LOGL_DEBUG, "No IMSI(%s) match found, returning message.\n",
- imsi);
- return NULL;
- }
-
- if (strlen(new_number_pre) > sizeof(called.number)) {
- LOGP(DCC, LOGL_ERROR, "Number %s is too long for structure.\n",
- new_number_pre);
- talloc_free(new_number_pre);
- return NULL;
- }
- update_called_number(&called, new_number_pre);
-
- /* another run through the re-write engine with other rules */
- LOGP(DCC, LOGL_DEBUG,
- "Post-Rewrite for IMSI(%s) Plan(%d) Type(%d) Number(%s)\n",
- imsi, called.plan, called.type, called.number);
- new_number_post = rewrite_isdn_number(nat, &nat->num_rewr_post, msg,
- imsi, &called);
- chosen_number = new_number_post ? new_number_post : new_number_pre;
-
-
- if (strlen(chosen_number) > sizeof(called.number)) {
- LOGP(DCC, LOGL_ERROR, "Number %s is too long for structure.\n",
- chosen_number);
- talloc_free(new_number_pre);
- talloc_free(new_number_post);
- return NULL;
- }
-
- /*
- * Need to create a new message now based on the old onew
- * with a new number. We can sadly not patch this in place
- * so we will need to regenerate it.
- */
-
- out = msgb_alloc_headroom(4096, 128, "changed-setup");
- if (!out) {
- LOGP(DCC, LOGL_ERROR, "Failed to allocate.\n");
- talloc_free(new_number_pre);
- talloc_free(new_number_post);
- return NULL;
- }
-
- /* copy the header */
- outptr = msgb_put(out, sizeof(*hdr48));
- memcpy(outptr, hdr48, sizeof(*hdr48));
-
- /* copy everything up to the number */
- sec_len = TLVP_VAL(&tp, GSM48_IE_CALLED_BCD) - 2 - &hdr48->data[0];
- outptr = msgb_put(out, sec_len);
- memcpy(outptr, &hdr48->data[0], sec_len);
-
- /* create the new number */
- update_called_number(&called, chosen_number);
- LOGP(DCC, LOGL_DEBUG,
- "Chosen number for IMSI(%s) is Plan(%d) Type(%d) Number(%s)\n",
- imsi, called.plan, called.type, called.number);
- gsm48_encode_called(out, &called);
-
- /* copy thre rest */
- msgptr = TLVP_VAL(&tp, GSM48_IE_CALLED_BCD) +
- TLVP_LEN(&tp, GSM48_IE_CALLED_BCD);
- sec_len = payload_len - (msgptr - &hdr48->data[0]);
- outptr = msgb_put(out, sec_len);
- memcpy(outptr, msgptr, sec_len);
-
- talloc_free(new_number_pre);
- talloc_free(new_number_post);
- return out;
-}
-
-/**
- * Find a new SMSC address, returns an allocated string that needs to be
- * freed or is NULL.
- */
-static char *find_new_smsc(struct bsc_nat *nat, void *ctx, const char *imsi,
- const char *smsc_addr, const char *dest_nr)
-{
- struct bsc_nat_num_rewr_entry *entry;
- char *new_number = NULL;
- uint8_t dest_match = llist_empty(&nat->tpdest_match);
-
- /* We will find a new number now */
- llist_for_each_entry(entry, &nat->smsc_rewr, list) {
- regmatch_t matches[2];
-
- /* check the IMSI match */
- if (regexec(&entry->msisdn_reg, imsi, 0, NULL, 0) != 0)
- continue;
-
- /* this regexp matches... */
- if (regexec(&entry->num_reg, smsc_addr, 2, matches, 0) == 0 &&
- matches[1].rm_eo != -1)
- new_number = talloc_asprintf(ctx, "%s%s",
- entry->replace,
- &smsc_addr[matches[1].rm_so]);
- if (new_number)
- break;
- }
-
- if (!new_number)
- return NULL;
-
- /*
- * now match the number against another list
- */
- llist_for_each_entry(entry, &nat->tpdest_match, list) {
- /* check the IMSI match */
- if (regexec(&entry->msisdn_reg, imsi, 0, NULL, 0) != 0)
- continue;
-
- if (regexec(&entry->num_reg, dest_nr, 0, NULL, 0) == 0) {
- dest_match = 1;
- break;
- }
- }
-
- if (!dest_match) {
- talloc_free(new_number);
- return NULL;
- }
-
- return new_number;
-}
-
-/**
- * Clear the TP-SRR from the TPDU header
- */
-static uint8_t sms_new_tpdu_hdr(struct bsc_nat *nat, const char *imsi,
- const char *dest_nr, uint8_t hdr)
-{
- struct bsc_nat_num_rewr_entry *entry;
-
- /* We will find a new number now */
- llist_for_each_entry(entry, &nat->sms_clear_tp_srr, list) {
- /* check the IMSI match */
- if (regexec(&entry->msisdn_reg, imsi, 0, NULL, 0) != 0)
- continue;
- if (regexec(&entry->num_reg, dest_nr, 0, NULL, 0) != 0)
- continue;
-
- /* matched phone number and imsi */
- return hdr & ~0x20;
- }
-
- return hdr;
-}
-
-/**
- * Check if we need to rewrite the number. For this SMS.
- */
-static char *sms_new_dest_nr(struct bsc_nat *nat, void *ctx,
- const char *imsi, const char *dest_nr)
-{
- return match_and_rewrite_number(ctx, dest_nr, imsi,
- &nat->sms_num_rewr, NULL);
-}
-
-/**
- * This is a helper for GSM 04.11 8.2.5.2 Destination address element
- */
-void sms_encode_addr_element(struct msgb *out, const char *new_number,
- int format, int tp_data)
-{
- uint8_t new_addr_len;
- uint8_t new_addr[26];
-
- /*
- * Copy the new number. We let libosmocore encode it, then set
- * the extension followed after the length. Depending on if
- * we want to write RP we will let the TLV code add the
- * length for us or we need to use strlen... This is not very clear
- * as of 03.40 and 04.11.
- */
- new_addr_len = gsm48_encode_bcd_number(new_addr, ARRAY_SIZE(new_addr),
- 1, new_number);
- new_addr[1] = format;
- if (tp_data) {
- uint8_t *data = msgb_put(out, new_addr_len);
- memcpy(data, new_addr, new_addr_len);
- data[0] = strlen(new_number);
- } else {
- msgb_lv_put(out, new_addr_len - 1, new_addr + 1);
- }
-}
-
-static struct msgb *sms_create_new(uint8_t type, uint8_t ref,
- struct gsm48_hdr *old_hdr48,
- const uint8_t *orig_addr_ptr,
- int orig_addr_len, const char *new_number,
- const uint8_t *data_ptr, int data_len,
- uint8_t tpdu_first_byte,
- const int old_dest_len, const char *new_dest_nr)
-{
- struct gsm48_hdr *new_hdr48;
- struct msgb *out;
-
- /*
- * We need to re-create the patched structure. This is why we have
- * saved the above pointers.
- */
- out = msgb_alloc_headroom(4096, 128, "changed-smsc");
- if (!out) {
- LOGP(DNAT, LOGL_ERROR, "Failed to allocate.\n");
- return NULL;
- }
-
- out->l2h = out->data;
- msgb_v_put(out, GSM411_MT_RP_DATA_MO);
- msgb_v_put(out, ref);
- msgb_lv_put(out, orig_addr_len, orig_addr_ptr);
-
- sms_encode_addr_element(out, new_number, 0x91, 0);
-
-
- /* Patch the TPDU from here on */
-
- /**
- * Do we need to put a new TP-Destination-Address (TP-DA) here or
- * can we copy the old thing? For the TP-DA we need to find out the
- * new size.
- */
- if (new_dest_nr) {
- uint8_t *data, *new_size;
-
- /* reserve the size and write the header */
- new_size = msgb_put(out, 1);
- out->l3h = new_size + 1;
- msgb_v_put(out, tpdu_first_byte);
- msgb_v_put(out, data_ptr[1]);
-
- /* encode the new number and put it */
- if (strncmp(new_dest_nr, "00", 2) == 0)
- sms_encode_addr_element(out, new_dest_nr + 2, 0x91, 1);
- else
- sms_encode_addr_element(out, new_dest_nr, 0x81, 1);
-
- /* Copy the rest after the TP-DS */
- data = msgb_put(out, data_len - 2 - 1 - old_dest_len);
- memcpy(data, &data_ptr[2 + 1 + old_dest_len], data_len - 2 - 1 - old_dest_len);
-
- /* fill in the new size */
- new_size[0] = msgb_l3len(out);
- } else {
- msgb_v_put(out, data_len);
- msgb_tv_fixed_put(out, tpdu_first_byte, data_len - 1, &data_ptr[1]);
- }
-
- /* prepend GSM 04.08 header */
- new_hdr48 = (struct gsm48_hdr *) msgb_push(out, sizeof(*new_hdr48) + 1);
- memcpy(new_hdr48, old_hdr48, sizeof(*old_hdr48));
- new_hdr48->data[0] = msgb_l2len(out);
-
- return out;
-}
-
-/**
- * Parse the SMS and check if it needs to be rewritten
- */
-static struct msgb *rewrite_sms(struct bsc_nat *nat, struct msgb *msg,
- struct bsc_nat_parsed *parsed, const char *imsi,
- struct gsm48_hdr *hdr48, const uint32_t len)
-{
- unsigned int payload_len;
- unsigned int cp_len;
-
- uint8_t ref;
- uint8_t orig_addr_len, *orig_addr_ptr;
- uint8_t dest_addr_len, *dest_addr_ptr;
- uint8_t data_len, *data_ptr;
- char smsc_addr[30];
-
-
- uint8_t dest_len, orig_dest_len;
- char _dest_nr[30];
- char *dest_nr;
- char *new_dest_nr;
-
- char *new_number = NULL;
- uint8_t tpdu_hdr;
- struct msgb *out;
-
- payload_len = len - sizeof(*hdr48);
- if (payload_len < 1) {
- LOGP(DNAT, LOGL_ERROR, "SMS too short for things. %d\n", payload_len);
- return NULL;
- }
-
- cp_len = hdr48->data[0];
- if (payload_len + 1 < cp_len) {
- LOGP(DNAT, LOGL_ERROR, "SMS RPDU can not fit in: %d %d\n", cp_len, payload_len);
- return NULL;
- }
-
- if (hdr48->data[1] != GSM411_MT_RP_DATA_MO)
- return NULL;
-
- if (cp_len < 5) {
- LOGP(DNAT, LOGL_ERROR, "RD-DATA can not fit in the CP len: %d\n", cp_len);
- return NULL;
- }
-
- /* RP */
- ref = hdr48->data[2];
- orig_addr_len = hdr48->data[3];
- orig_addr_ptr = &hdr48->data[4];
-
- /* the +1 is for checking if the following element has some space */
- if (cp_len < 3 + orig_addr_len + 1) {
- LOGP(DNAT, LOGL_ERROR, "RP-Originator addr does not fit: %d\n", orig_addr_len);
- return NULL;
- }
-
- dest_addr_len = hdr48->data[3 + orig_addr_len + 1];
- dest_addr_ptr = &hdr48->data[3 + orig_addr_len + 2];
-
- if (cp_len < 3 + orig_addr_len + 1 + dest_addr_len + 1) {
- LOGP(DNAT, LOGL_ERROR, "RP-Destination addr does not fit: %d\n", dest_addr_len);
- return NULL;
- }
- gsm48_decode_bcd_number(smsc_addr, ARRAY_SIZE(smsc_addr), dest_addr_ptr - 1, 1);
-
- data_len = hdr48->data[3 + orig_addr_len + 1 + dest_addr_len + 1];
- data_ptr = &hdr48->data[3 + orig_addr_len + 1 + dest_addr_len + 2];
-
- if (cp_len < 3 + orig_addr_len + 1 + dest_addr_len + 1 + data_len) {
- LOGP(DNAT, LOGL_ERROR, "RP-Data does not fit: %d\n", data_len);
- return NULL;
- }
-
- if (data_len < 3) {
- LOGP(DNAT, LOGL_ERROR, "SMS-SUBMIT is too short.\n");
- return NULL;
- }
-
- /* TP-PDU starts here */
- if ((data_ptr[0] & 0x03) != GSM340_SMS_SUBMIT_MS2SC)
- return NULL;
-
- /*
- * look into the phone number. The length is in semi-octets, we will
- * need to add the byte for the number type as well.
- */
- orig_dest_len = data_ptr[2];
- dest_len = ((orig_dest_len + 1) / 2) + 1;
- if (data_len < dest_len + 3 || dest_len < 2) {
- LOGP(DNAT, LOGL_ERROR, "SMS-SUBMIT can not have TP-DestAddr.\n");
- return NULL;
- }
-
- if ((data_ptr[3] & 0x80) == 0) {
- LOGP(DNAT, LOGL_ERROR, "TP-DestAddr has extension. Not handled.\n");
- return NULL;
- }
-
- if ((data_ptr[3] & 0x0F) == 0) {
- LOGP(DNAT, LOGL_ERROR, "TP-DestAddr is of unknown type.\n");
- return NULL;
- }
-
- /**
- * Besides of what I think I read in GSM 03.40 and 04.11 the TP-DA
- * contains the semi-octets as length (strlen), change it to the
- * the number of bytes, but then change it back.
- */
- data_ptr[2] = dest_len;
- gsm48_decode_bcd_number(_dest_nr + 2, ARRAY_SIZE(_dest_nr) - 2,
- &data_ptr[2], 1);
- data_ptr[2] = orig_dest_len;
- if ((data_ptr[3] & 0x70) == 0x10) {
- _dest_nr[0] = _dest_nr[1] = '0';
- dest_nr = &_dest_nr[0];
- } else {
- dest_nr = &_dest_nr[2];
- }
-
- /**
- * Call functions to rewrite the data
- */
- tpdu_hdr = sms_new_tpdu_hdr(nat, imsi, dest_nr, data_ptr[0]);
- new_number = find_new_smsc(nat, msg, imsi, smsc_addr, dest_nr);
- new_dest_nr = sms_new_dest_nr(nat, msg, imsi, dest_nr);
-
- if (tpdu_hdr == data_ptr[0] && !new_number && !new_dest_nr)
- return NULL;
-
- out = sms_create_new(GSM411_MT_RP_DATA_MO, ref, hdr48,
- orig_addr_ptr, orig_addr_len,
- new_number ? new_number : smsc_addr,
- data_ptr, data_len, tpdu_hdr,
- dest_len, new_dest_nr);
- talloc_free(new_number);
- talloc_free(new_dest_nr);
- return out;
-}
-
-struct msgb *bsc_nat_rewrite_msg(struct bsc_nat *nat, struct msgb *msg, struct bsc_nat_parsed *parsed, const char *imsi)
-{
- struct gsm48_hdr *hdr48;
- uint32_t len;
- uint8_t msg_type, proto;
- struct msgb *new_msg = NULL, *sccp;
- uint8_t link_id;
-
- if (!imsi || strlen(imsi) < 5)
- return msg;
-
- /* only care about DTAP messages */
- if (parsed->bssap != BSSAP_MSG_DTAP)
- return msg;
- if (!parsed->dest_local_ref)
- return msg;
-
- hdr48 = bsc_unpack_dtap(parsed, msg, &len);
- if (!hdr48)
- return msg;
-
- link_id = msg->l3h[1];
- proto = gsm48_hdr_pdisc(hdr48);
- msg_type = gsm48_hdr_msg_type(hdr48);
-
- if (proto == GSM48_PDISC_CC && msg_type == GSM48_MT_CC_SETUP)
- new_msg = rewrite_setup(nat, msg, parsed, imsi, hdr48, len);
- else if (proto == GSM48_PDISC_SMS && msg_type == GSM411_MT_CP_DATA)
- new_msg = rewrite_sms(nat, msg, parsed, imsi, hdr48, len);
-
- if (!new_msg)
- return msg;
-
- /* wrap with DTAP, SCCP, then IPA. TODO: Stop copying */
- gsm0808_prepend_dtap_header(new_msg, link_id);
- sccp = sccp_create_dt1(parsed->dest_local_ref, new_msg->data, new_msg->len);
- talloc_free(new_msg);
-
- if (!sccp) {
- LOGP(DNAT, LOGL_ERROR, "Failed to allocate.\n");
- return msg;
- }
-
- ipa_prepend_header(sccp, IPAC_PROTO_SCCP);
-
- /* the parsed hangs off from msg but it needs to survive */
- talloc_steal(sccp, parsed);
- msgb_free(msg);
- return sccp;
-}
-
-static void num_rewr_free_data(struct bsc_nat_num_rewr_entry *entry)
-{
- regfree(&entry->msisdn_reg);
- regfree(&entry->num_reg);
- talloc_free(entry->replace);
-}
-
-void bsc_nat_num_rewr_entry_adapt(void *ctx, struct llist_head *head,
- const struct osmo_config_list *list)
-{
- struct bsc_nat_num_rewr_entry *entry, *tmp;
- struct osmo_config_entry *cfg_entry;
-
- /* free the old data */
- llist_for_each_entry_safe(entry, tmp, head, list) {
- num_rewr_free_data(entry);
- llist_del(&entry->list);
- talloc_free(entry);
- }
-
-
- if (!list)
- return;
-
- llist_for_each_entry(cfg_entry, &list->entry, list) {
- char *regexp;
- if (cfg_entry->text[0] == '+') {
- LOGP(DNAT, LOGL_ERROR,
- "Plus is not allowed in the number\n");
- continue;
- }
-
- entry = talloc_zero(ctx, struct bsc_nat_num_rewr_entry);
- if (!entry) {
- LOGP(DNAT, LOGL_ERROR,
- "Allocation of the num_rewr entry failed.\n");
- continue;
- }
-
- entry->replace = talloc_strdup(entry, cfg_entry->text);
- if (!entry->replace) {
- LOGP(DNAT, LOGL_ERROR,
- "Failed to copy the replacement text.\n");
- talloc_free(entry);
- continue;
- }
-
- if (strcmp("prefix_lookup", entry->replace) == 0)
- entry->is_prefix_lookup = 1;
-
- /* we will now build a regexp string */
- if (cfg_entry->mcc[0] == '^') {
- regexp = talloc_strdup(entry, cfg_entry->mcc);
- } else {
- regexp = talloc_asprintf(entry, "^%s%s",
- cfg_entry->mcc[0] == '*' ?
- "[0-9][0-9][0-9]" : cfg_entry->mcc,
- cfg_entry->mnc[0] == '*' ?
- "[0-9][0-9]" : cfg_entry->mnc);
- }
-
- if (!regexp) {
- LOGP(DNAT, LOGL_ERROR, "Failed to create a regexp string.\n");
- talloc_free(entry);
- continue;
- }
-
- if (regcomp(&entry->msisdn_reg, regexp, 0) != 0) {
- LOGP(DNAT, LOGL_ERROR,
- "Failed to compile regexp '%s'\n", regexp);
- talloc_free(regexp);
- talloc_free(entry);
- continue;
- }
-
- talloc_free(regexp);
- if (regcomp(&entry->num_reg, cfg_entry->option, REG_EXTENDED) != 0) {
- LOGP(DNAT, LOGL_ERROR,
- "Failed to compile regexp '%s'\n", cfg_entry->option);
- regfree(&entry->msisdn_reg);
- talloc_free(entry);
- continue;
- }
-
- /* we have copied the number */
- llist_add_tail(&entry->list, head);
- }
-}
diff --git a/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c b/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c
deleted file mode 100644
index 633fa87d0..000000000
--- a/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/* Handling for loading a re-write file/database */
-/*
- * (C) 2013 by On-Waves
- * (C) 2013 by Holger Hans Peter Freyther <zecke@selfish.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 <openbsc/nat_rewrite_trie.h>
-#include <openbsc/debug.h>
-#include <openbsc/vty.h>
-
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/utils.h>
-
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-
-#define CHECK_IS_DIGIT_OR_FAIL(prefix, pos) \
- if (!isdigit(prefix[pos]) && prefix[pos] != '+') { \
- LOGP(DNAT, LOGL_ERROR, \
- "Prefix(%s) contains non ascii text at(%d=%c)\n", \
- prefix, pos, prefix[pos]); \
- goto fail; \
- }
-#define TO_INT(c) \
- ((c) == '+' ? 10 : ((c - '0') % 10))
-
-static void insert_rewrite_node(struct nat_rewrite_rule *rule, struct nat_rewrite *root)
-{
- struct nat_rewrite_rule *new = &root->rule;
-
- const int len = strlen(rule->prefix);
- int i;
-
- if (len <= 0) {
- LOGP(DNAT, LOGL_ERROR, "An empty prefix does not make sense.\n");
- goto fail;
- }
-
- for (i = 0; i < len - 1; ++i) {
- int pos;
-
- /* check if the input is valid */
- CHECK_IS_DIGIT_OR_FAIL(rule->prefix, i);
-
- /* check if the next node is already valid */
- pos = TO_INT(rule->prefix[i]);
- if (!new->rules[pos]) {
- new->rules[pos] = talloc_zero(root, struct nat_rewrite_rule);
- if (!new->rules[pos]) {
- LOGP(DNAT, LOGL_ERROR,
- "Failed to allocate memory.\n");
- goto fail;
- }
-
- new->rules[pos]->empty = 1;
- }
-
- /* we continue here */
- new = new->rules[pos];
- }
-
- /* new now points to the place where we want to add it */
- int pos;
-
- /* check if the input is valid */
- CHECK_IS_DIGIT_OR_FAIL(rule->prefix, (len - 1));
-
- /* check if the next node is already valid */
- pos = TO_INT(rule->prefix[len - 1]);
- if (!new->rules[pos])
- new->rules[pos] = rule;
- else if (new->rules[pos]->empty) {
- /* copy over entries */
- new->rules[pos]->empty = 0;
- memcpy(new->rules[pos]->prefix, rule->prefix, sizeof(rule->prefix));
- memcpy(new->rules[pos]->rewrite, rule->rewrite, sizeof(rule->rewrite));
- talloc_free(rule);
- } else {
- LOGP(DNAT, LOGL_ERROR,
- "Prefix(%s) is already installed\n", rule->prefix);
- goto fail;
- }
-
- root->prefixes += 1;
- return;
-
-fail:
- talloc_free(rule);
- return;
-}
-
-static void handle_line(struct nat_rewrite *rewrite, char *line)
-{
- char *split;
- struct nat_rewrite_rule *rule;
- size_t size_prefix, size_end, len;
-
-
- /* Find the ',' in the line */
- len = strlen(line);
- split = strstr(line, ",");
- if (!split) {
- LOGP(DNAT, LOGL_ERROR, "Line doesn't contain ','\n");
- return;
- }
-
- /* Check if there is space for the rewrite rule */
- size_prefix = split - line;
- if (len - size_prefix <= 2) {
- LOGP(DNAT, LOGL_ERROR, "No rewrite available.\n");
- return;
- }
-
- /* Continue after the ',' to the end */
- split = &line[size_prefix + 1];
- size_end = strlen(split) - 1;
-
- /* Check if both strings can fit into the static array */
- if (size_prefix > sizeof(rule->prefix) - 1) {
- LOGP(DNAT, LOGL_ERROR,
- "Prefix is too long with %zu\n", size_prefix);
- return;
- }
-
- if (size_end > sizeof(rule->rewrite) - 1) {
- LOGP(DNAT, LOGL_ERROR,
- "Rewrite is too long with %zu on %s\n",
- size_end, &line[size_prefix + 1]);
- return;
- }
-
- /* Now create the entry and insert it into the trie */
- rule = talloc_zero(rewrite, struct nat_rewrite_rule);
- if (!rule) {
- LOGP(DNAT, LOGL_ERROR, "Can not allocate memory\n");
- return;
- }
-
- memcpy(rule->prefix, line, size_prefix);
- assert(size_prefix < sizeof(rule->prefix));
- rule->prefix[size_prefix] = '\0';
-
- memcpy(rule->rewrite, split, size_end);
- assert(size_end < sizeof(rule->rewrite));
- rule->rewrite[size_end] = '\0';
-
- /* now insert and balance the tree */
- insert_rewrite_node(rule, rewrite);
-}
-
-struct nat_rewrite *nat_rewrite_parse(void *ctx, const char *filename)
-{
- FILE *file;
- char *line = NULL;
- size_t n = 0;
- struct nat_rewrite *res;
-
- file = fopen(filename, "r");
- if (!file)
- return NULL;
-
- res = talloc_zero(ctx, struct nat_rewrite);
- if (!res) {
- fclose(file);
- return NULL;
- }
-
- /* mark the root as empty */
- res->rule.empty = 1;
-
- while (getline(&line, &n, file) != -1) {
- handle_line(res, line);
- }
-
- free(line);
- fclose(file);
- return res;
-}
-
-/**
- * Simple find that tries to do a longest match...
- */
-struct nat_rewrite_rule *nat_rewrite_lookup(struct nat_rewrite *rewrite,
- const char *prefix)
-{
- struct nat_rewrite_rule *rule = &rewrite->rule;
- struct nat_rewrite_rule *last = NULL;
- const int len = OSMO_MIN(strlen(prefix), (sizeof(rule->prefix) - 1));
- int i;
-
- for (i = 0; rule && i < len; ++i) {
- int pos;
-
- CHECK_IS_DIGIT_OR_FAIL(prefix, i);
- pos = TO_INT(prefix[i]);
-
- rule = rule->rules[pos];
- if (rule && !rule->empty)
- last = rule;
- }
-
- return last;
-
-fail:
- return NULL;
-}
-
-static void nat_rewrite_dump_rec(struct nat_rewrite_rule *rule)
-{
- int i;
- if (!rule->empty)
- printf("%s,%s\n", rule->prefix, rule->rewrite);
-
- for (i = 0; i < ARRAY_SIZE(rule->rules); ++i) {
- if (!rule->rules[i])
- continue;
- nat_rewrite_dump_rec(rule->rules[i]);
- }
-}
-
-void nat_rewrite_dump(struct nat_rewrite *rewrite)
-{
- nat_rewrite_dump_rec(&rewrite->rule);
-}
-
-static void nat_rewrite_dump_rec_vty(struct vty *vty, struct nat_rewrite_rule *rule)
-{
- int i;
- if (!rule->empty)
- vty_out(vty, "%s,%s%s", rule->prefix, rule->rewrite, VTY_NEWLINE);
-
- for (i = 0; i < ARRAY_SIZE(rule->rules); ++i) {
- if (!rule->rules[i])
- continue;
- nat_rewrite_dump_rec_vty(vty, rule->rules[i]);
- }
-}
-
-void nat_rewrite_dump_vty(struct vty *vty, struct nat_rewrite *rewrite)
-{
- nat_rewrite_dump_rec_vty(vty, &rewrite->rule);
-}
diff --git a/src/osmo-bsc_nat/bsc_nat_utils.c b/src/osmo-bsc_nat/bsc_nat_utils.c
deleted file mode 100644
index c12b29f1f..000000000
--- a/src/osmo-bsc_nat/bsc_nat_utils.c
+++ /dev/null
@@ -1,535 +0,0 @@
-
-/* BSC Multiplexer/NAT Utilities */
-
-/*
- * (C) 2010-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010-2011 by On-Waves
- * 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 <openbsc/bsc_nat.h>
-#include <openbsc/bsc_nat_sccp.h>
-#include <openbsc/bsc_msg_filter.h>
-#include <openbsc/bsc_msc.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/debug.h>
-#include <openbsc/ipaccess.h>
-#include <openbsc/vty.h>
-
-#include <osmocom/core/linuxlist.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/stats.h>
-#include <osmocom/gsm/gsm0808.h>
-#include <osmocom/gsm/ipa.h>
-
-#include <osmocom/gsm/protocol/gsm_08_08.h>
-#include <osmocom/gsm/protocol/gsm_04_11.h>
-
-#include <osmocom/sccp/sccp.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-
-static const struct rate_ctr_desc bsc_cfg_ctr_description[] = {
- [BCFG_CTR_SCCP_CONN] = { "sccp.conn", "SCCP Connections "},
- [BCFG_CTR_SCCP_CALLS] = { "sccp.calls", "SCCP Assignment Commands "},
- [BCFG_CTR_NET_RECONN] = { "net.reconnects", "Network reconnects "},
- [BCFG_CTR_DROPPED_SCCP] = { "dropped.sccp", "Dropped SCCP connections."},
- [BCFG_CTR_DROPPED_CALLS] = { "dropped.calls", "Dropped active calls. "},
- [BCFG_CTR_REJECTED_CR] = { "rejected.cr", "Rejected CR due filter "},
- [BCFG_CTR_REJECTED_MSG] = { "rejected.msg", "Rejected MSG due filter "},
- [BCFG_CTR_ILL_PACKET] = { "rejected.ill", "Rejected due parse error "},
- [BCFG_CTR_CON_TYPE_LU] = { "conn.lu", "Conn Location Update "},
- [BCFG_CTR_CON_CMSERV_RQ] = { "conn.rq", "Conn CM Service Req "},
- [BCFG_CTR_CON_PAG_RESP] = { "conn.pag", "Conn Paging Response "},
- [BCFG_CTR_CON_SSA] = { "conn.ssa", "Conn USSD "},
- [BCFG_CTR_CON_OTHER] = { "conn.other", "Conn Other "},
-};
-
-static const struct rate_ctr_group_desc bsc_cfg_ctrg_desc = {
- .group_name_prefix = "nat.bsc",
- .group_description = "NAT BSC Statistics",
- .num_ctr = ARRAY_SIZE(bsc_cfg_ctr_description),
- .ctr_desc = bsc_cfg_ctr_description,
- .class_id = OSMO_STATS_CLASS_PEER,
-};
-
-struct bsc_nat *bsc_nat_alloc(void)
-{
- struct bsc_nat *nat = talloc_zero(tall_bsc_ctx, struct bsc_nat);
- if (!nat)
- return NULL;
-
- nat->main_dest = talloc_zero(nat, struct bsc_msc_dest);
- if (!nat->main_dest) {
- talloc_free(nat);
- return NULL;
- }
-
- INIT_LLIST_HEAD(&nat->sccp_connections);
- INIT_LLIST_HEAD(&nat->bsc_connections);
- INIT_LLIST_HEAD(&nat->paging_groups);
- INIT_LLIST_HEAD(&nat->bsc_configs);
- INIT_LLIST_HEAD(&nat->access_lists);
- INIT_LLIST_HEAD(&nat->dests);
- INIT_LLIST_HEAD(&nat->num_rewr);
- INIT_LLIST_HEAD(&nat->num_rewr_post);
- INIT_LLIST_HEAD(&nat->smsc_rewr);
- INIT_LLIST_HEAD(&nat->tpdest_match);
- INIT_LLIST_HEAD(&nat->sms_clear_tp_srr);
- INIT_LLIST_HEAD(&nat->sms_num_rewr);
-
- nat->stats.sccp.conn = osmo_counter_alloc("nat.sccp.conn");
- nat->stats.sccp.calls = osmo_counter_alloc("nat.sccp.calls");
- nat->stats.bsc.reconn = osmo_counter_alloc("nat.bsc.conn");
- nat->stats.bsc.auth_fail = osmo_counter_alloc("nat.bsc.auth_fail");
- nat->stats.msc.reconn = osmo_counter_alloc("nat.msc.conn");
- nat->stats.ussd.reconn = osmo_counter_alloc("nat.ussd.conn");
- nat->auth_timeout = 2;
- nat->ping_timeout = 20;
- nat->pong_timeout = 5;
-
- llist_add(&nat->main_dest->list, &nat->dests);
- nat->main_dest->ip = talloc_strdup(nat, "127.0.0.1");
- nat->main_dest->port = 5000;
-
- return nat;
-}
-
-void bsc_nat_free(struct bsc_nat *nat)
-{
- struct bsc_config *cfg, *tmp;
- struct bsc_msg_acc_lst *lst, *tmp_lst;
-
- llist_for_each_entry_safe(cfg, tmp, &nat->bsc_configs, entry)
- bsc_config_free(cfg);
- llist_for_each_entry_safe(lst, tmp_lst, &nat->access_lists, list)
- bsc_msg_acc_lst_delete(lst);
-
- bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, NULL);
- bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr_post, NULL);
- bsc_nat_num_rewr_entry_adapt(nat, &nat->sms_clear_tp_srr, NULL);
- bsc_nat_num_rewr_entry_adapt(nat, &nat->sms_num_rewr, NULL);
- bsc_nat_num_rewr_entry_adapt(nat, &nat->tpdest_match, NULL);
-
- osmo_counter_free(nat->stats.sccp.conn);
- osmo_counter_free(nat->stats.sccp.calls);
- osmo_counter_free(nat->stats.bsc.reconn);
- osmo_counter_free(nat->stats.bsc.auth_fail);
- osmo_counter_free(nat->stats.msc.reconn);
- osmo_counter_free(nat->stats.ussd.reconn);
- talloc_free(nat->mgcp_cfg);
- talloc_free(nat);
-}
-
-void bsc_nat_set_msc_ip(struct bsc_nat *nat, const char *ip)
-{
- osmo_talloc_replace_string(nat, &nat->main_dest->ip, ip);
-}
-
-struct bsc_connection *bsc_connection_alloc(struct bsc_nat *nat)
-{
- struct bsc_connection *con = talloc_zero(nat, struct bsc_connection);
- if (!con)
- return NULL;
-
- con->nat = nat;
- osmo_wqueue_init(&con->write_queue, 100);
- INIT_LLIST_HEAD(&con->cmd_pending);
- INIT_LLIST_HEAD(&con->pending_dlcx);
- return con;
-}
-
-struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token,
- unsigned int number)
-{
- struct bsc_config *conf = talloc_zero(nat, struct bsc_config);
- if (!conf)
- return NULL;
-
- conf->token = talloc_strdup(conf, token);
- conf->nr = number;
- conf->nat = nat;
- conf->max_endpoints = 32;
- conf->paging_group = PAGIN_GROUP_UNASSIGNED;
-
- INIT_LLIST_HEAD(&conf->lac_list);
-
- llist_add_tail(&conf->entry, &nat->bsc_configs);
- ++nat->num_bsc;
-
- conf->stats.ctrg = rate_ctr_group_alloc(conf, &bsc_cfg_ctrg_desc, conf->nr);
- if (!conf->stats.ctrg) {
- llist_del(&conf->entry);
- talloc_free(conf);
- return NULL;
- }
-
- return conf;
-}
-
-struct bsc_config *bsc_config_by_token(struct bsc_nat *nat, const char *token, int len)
-{
- struct bsc_config *conf;
-
- llist_for_each_entry(conf, &nat->bsc_configs, entry) {
- /*
- * Add the '\0' of the token for the memcmp, the IPA messages
- * for some reason added null termination.
- */
- const int token_len = strlen(conf->token) + 1;
-
- if (token_len == len && memcmp(conf->token, token, token_len) == 0)
- return conf;
- }
-
- return NULL;
-}
-
-void bsc_config_free(struct bsc_config *cfg)
-{
- llist_del(&cfg->entry);
- rate_ctr_group_free(cfg->stats.ctrg);
- cfg->nat->num_bsc--;
- OSMO_ASSERT(cfg->nat->num_bsc >= 0)
- talloc_free(cfg);
-}
-
-static void _add_lac(void *ctx, struct llist_head *list, int _lac)
-{
- struct bsc_lac_entry *lac;
-
- llist_for_each_entry(lac, list, entry)
- if (lac->lac == _lac)
- return;
-
- lac = talloc_zero(ctx, struct bsc_lac_entry);
- if (!lac) {
- LOGP(DNAT, LOGL_ERROR, "Failed to allocate.\n");
- return;
- }
-
- lac->lac = _lac;
- llist_add_tail(&lac->entry, list);
-}
-
-static void _del_lac(struct llist_head *list, int _lac)
-{
- struct bsc_lac_entry *lac;
-
- llist_for_each_entry(lac, list, entry)
- if (lac->lac == _lac) {
- llist_del(&lac->entry);
- talloc_free(lac);
- return;
- }
-}
-
-void bsc_config_add_lac(struct bsc_config *cfg, int _lac)
-{
- _add_lac(cfg, &cfg->lac_list, _lac);
-}
-
-void bsc_config_del_lac(struct bsc_config *cfg, int _lac)
-{
- _del_lac(&cfg->lac_list, _lac);
-}
-
-struct bsc_nat_paging_group *bsc_nat_paging_group_create(struct bsc_nat *nat, int group)
-{
- struct bsc_nat_paging_group *pgroup;
-
- pgroup = talloc_zero(nat, struct bsc_nat_paging_group);
- if (!pgroup) {
- LOGP(DNAT, LOGL_ERROR, "Failed to allocate a paging group.\n");
- return NULL;
- }
-
- pgroup->nr = group;
- INIT_LLIST_HEAD(&pgroup->lists);
- llist_add_tail(&pgroup->entry, &nat->paging_groups);
- return pgroup;
-}
-
-void bsc_nat_paging_group_delete(struct bsc_nat_paging_group *pgroup)
-{
- llist_del(&pgroup->entry);
- talloc_free(pgroup);
-}
-
-struct bsc_nat_paging_group *bsc_nat_paging_group_num(struct bsc_nat *nat, int group)
-{
- struct bsc_nat_paging_group *pgroup;
-
- llist_for_each_entry(pgroup, &nat->paging_groups, entry)
- if (pgroup->nr == group)
- return pgroup;
-
- return NULL;
-}
-
-void bsc_nat_paging_group_add_lac(struct bsc_nat_paging_group *pgroup, int lac)
-{
- _add_lac(pgroup, &pgroup->lists, lac);
-}
-
-void bsc_nat_paging_group_del_lac(struct bsc_nat_paging_group *pgroup, int lac)
-{
- _del_lac(&pgroup->lists, lac);
-}
-
-int bsc_config_handles_lac(struct bsc_config *cfg, int lac_nr)
-{
- struct bsc_nat_paging_group *pgroup;
- struct bsc_lac_entry *entry;
-
- llist_for_each_entry(entry, &cfg->lac_list, entry)
- if (entry->lac == lac_nr)
- return 1;
-
- /* now lookup the paging group */
- pgroup = bsc_nat_paging_group_num(cfg->nat, cfg->paging_group);
- if (!pgroup)
- return 0;
-
- llist_for_each_entry(entry, &pgroup->lists, entry)
- if (entry->lac == lac_nr)
- return 1;
-
- return 0;
-}
-
-void sccp_connection_destroy(struct nat_sccp_connection *conn)
-{
- LOGP(DNAT, LOGL_DEBUG, "Destroy 0x%x <-> 0x%x mapping for con %p\n",
- sccp_src_ref_to_int(&conn->real_ref),
- sccp_src_ref_to_int(&conn->patched_ref), conn->bsc);
- bsc_mgcp_dlcx(conn);
- llist_del(&conn->list_entry);
- talloc_free(conn);
-}
-
-
-int bsc_nat_find_paging(struct msgb *msg,
- const uint8_t **out_data, int *out_leng)
-{
- int data_length;
- const uint8_t *data;
- struct tlv_parsed tp;
-
- if (!msg->l3h || msgb_l3len(msg) < 3) {
- LOGP(DNAT, LOGL_ERROR, "Paging message is too short.\n");
- return -1;
- }
-
- tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0);
- if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST)) {
- LOGP(DNAT, LOGL_ERROR, "No CellIdentifier List inside paging msg.\n");
- return -2;
- }
-
- data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST);
- data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST);
-
- /* No need to try a different BSS */
- if (data[0] == CELL_IDENT_BSS) {
- return -3;
- } else if (data[0] != CELL_IDENT_LAC) {
- LOGP(DNAT, LOGL_ERROR, "Unhandled cell ident discrminator: %d\n", data[0]);
- return -4;
- }
-
- *out_data = &data[1];
- *out_leng = data_length - 1;
- return 0;
-}
-
-int bsc_write_mgcp(struct bsc_connection *bsc, const uint8_t *data, unsigned int length)
-{
- struct msgb *msg;
-
- if (length > 4096 - 128) {
- LOGP(DLINP, LOGL_ERROR, "Can not send message of that size.\n");
- return -1;
- }
-
- msg = msgb_alloc_headroom(4096, 128, "to-bsc");
- if (!msg) {
- LOGP(DLINP, LOGL_ERROR, "Failed to allocate memory for BSC msg.\n");
- return -1;
- }
-
- /* copy the data */
- msg->l3h = msgb_put(msg, length);
- memcpy(msg->l3h, data, length);
-
- return bsc_write(bsc, msg, IPAC_PROTO_MGCP_OLD);
-}
-
-int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int proto)
-{
- return bsc_do_write(&bsc->write_queue, msg, proto);
-}
-
-int bsc_do_write(struct osmo_wqueue *queue, struct msgb *msg, int proto)
-{
- /* prepend the header */
- ipa_prepend_header(msg, proto);
- return bsc_write_msg(queue, msg);
-}
-
-int bsc_write_msg(struct osmo_wqueue *queue, struct msgb *msg)
-{
- if (osmo_wqueue_enqueue(queue, msg) != 0) {
- LOGP(DLINP, LOGL_ERROR, "Failed to enqueue the write.\n");
- msgb_free(msg);
- return -1;
- }
-
- return 0;
-}
-
-struct gsm48_hdr *bsc_unpack_dtap(struct bsc_nat_parsed *parsed,
- struct msgb *msg, uint32_t *len)
-{
- /* gsm_type is actually the size of the dtap */
- *len = parsed->gsm_type;
- if (*len < msgb_l3len(msg) - 3) {
- LOGP(DNAT, LOGL_ERROR, "Not enough space for DTAP.\n");
- return NULL;
- }
-
- if (msgb_l3len(msg) - 3 < msg->l3h[2]) {
- LOGP(DNAT, LOGL_ERROR,
- "GSM48 payload does not fit: %d %d\n",
- msg->l3h[2], msgb_l3len(msg) - 3);
- return NULL;
- }
-
- msg->l4h = &msg->l3h[3];
- return (struct gsm48_hdr *) msg->l4h;
-}
-
-static const char *con_types [] = {
- [FLT_CON_TYPE_NONE] = "n/a",
- [FLT_CON_TYPE_LU] = "Location Update",
- [FLT_CON_TYPE_CM_SERV_REQ] = "CM Serv Req",
- [FLT_CON_TYPE_PAG_RESP] = "Paging Response",
- [FLT_CON_TYPE_SSA] = "Supplementar Service Activation",
- [FLT_CON_TYPE_LOCAL_REJECT] = "Local Reject",
- [FLT_CON_TYPE_OTHER] = "Other",
-};
-
-const char *bsc_con_type_to_string(int type)
-{
- return con_types[type];
-}
-
-int bsc_nat_msc_is_connected(struct bsc_nat *nat)
-{
- return nat->msc_con->is_connected;
-}
-
-static const int con_to_ctr[] = {
- [FLT_CON_TYPE_NONE] = -1,
- [FLT_CON_TYPE_LU] = BCFG_CTR_CON_TYPE_LU,
- [FLT_CON_TYPE_CM_SERV_REQ] = BCFG_CTR_CON_CMSERV_RQ,
- [FLT_CON_TYPE_PAG_RESP] = BCFG_CTR_CON_PAG_RESP,
- [FLT_CON_TYPE_SSA] = BCFG_CTR_CON_SSA,
- [FLT_CON_TYPE_LOCAL_REJECT] = -1,
- [FLT_CON_TYPE_OTHER] = BCFG_CTR_CON_OTHER,
-};
-
-int bsc_conn_type_to_ctr(struct nat_sccp_connection *conn)
-{
- return con_to_ctr[conn->filter_state.con_type];
-}
-
-int bsc_write_cb(struct osmo_fd *bfd, struct msgb *msg)
-{
- int rc;
-
- rc = write(bfd->fd, msg->data, msg->len);
- if (rc != msg->len)
- LOGP(DNAT, LOGL_ERROR, "Failed to write message to the BSC.\n");
-
- return rc;
-}
-
-static void extract_lac(const uint8_t *data, uint16_t *lac, uint16_t *ci)
-{
- memcpy(lac, &data[0], sizeof(*lac));
- memcpy(ci, &data[2], sizeof(*ci));
-
- *lac = ntohs(*lac);
- *ci = ntohs(*ci);
-}
-
-int bsc_nat_extract_lac(struct bsc_connection *bsc,
- struct nat_sccp_connection *con,
- struct bsc_nat_parsed *parsed, struct msgb *msg)
-{
- int data_length;
- const uint8_t *data;
- struct tlv_parsed tp;
- uint16_t lac, ci;
-
- if (parsed->gsm_type != BSS_MAP_MSG_COMPLETE_LAYER_3) {
- LOGP(DNAT, LOGL_ERROR, "Can only extract LAC from Complete Layer3\n");
- return -1;
- }
-
- if (!msg->l3h || msgb_l3len(msg) < 3) {
- LOGP(DNAT, LOGL_ERROR, "Complete Layer3 mssage is too short.\n");
- return -1;
- }
-
- tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0);
- if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER)) {
- LOGP(DNAT, LOGL_ERROR, "No CellIdentifier List inside paging msg.\n");
- return -2;
- }
-
- data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER);
- data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER);
-
- /* Attemt to get the LAC/CI from it */
- if (data[0] == CELL_IDENT_WHOLE_GLOBAL) {
- if (data_length != 8) {
- LOGP(DNAT, LOGL_ERROR,
- "Ident too short: %d\n", data_length);
- return -3;
- }
- extract_lac(&data[1 + 3], &lac, &ci);
- } else if (data[0] == CELL_IDENT_LAC_AND_CI) {
- if (data_length != 5) {
- LOGP(DNAT, LOGL_ERROR,
- "Ident too short: %d\n", data_length);
- return -3;
- }
- extract_lac(&data[1], &lac, &ci);
- } else {
- LOGP(DNAT, LOGL_ERROR,
- "Unhandled cell identifier: %d\n", data[0]);
- return -1;
- }
-
- con->lac = lac;
- con->ci = ci;
- return 0;
-}
diff --git a/src/osmo-bsc_nat/bsc_nat_vty.c b/src/osmo-bsc_nat/bsc_nat_vty.c
deleted file mode 100644
index fed530676..000000000
--- a/src/osmo-bsc_nat/bsc_nat_vty.c
+++ /dev/null
@@ -1,1336 +0,0 @@
-/* OpenBSC NAT interface to quagga VTY */
-/* (C) 2010-2015 by Holger Hans Peter Freyther
- * (C) 2010-2015 by On-Waves
- * 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 <openbsc/vty.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/bsc_nat.h>
-#include <openbsc/bsc_nat_sccp.h>
-#include <openbsc/bsc_msg_filter.h>
-#include <openbsc/bsc_msc.h>
-#include <openbsc/gsm_04_08.h>
-#include <osmocom/legacy_mgcp/mgcp.h>
-#include <openbsc/vty.h>
-#include <openbsc/nat_rewrite_trie.h>
-
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/rate_ctr.h>
-#include <osmocom/core/utils.h>
-#include <osmocom/vty/logging.h>
-#include <osmocom/vty/misc.h>
-#include <openbsc/osmux.h>
-
-#include <osmocom/sccp/sccp.h>
-
-#include <stdlib.h>
-#include <stdbool.h>
-
-static struct bsc_nat *_nat;
-
-
-#define BSC_STR "Information about BSCs\n"
-#define MGCP_STR "MGCP related status\n"
-#define PAGING_STR "Paging\n"
-#define SMSC_REWRITE "SMSC Rewriting\n"
-
-static struct cmd_node nat_node = {
- NAT_NODE,
- "%s(config-nat)# ",
- 1,
-};
-
-static struct cmd_node bsc_node = {
- NAT_BSC_NODE,
- "%s(config-nat-bsc)# ",
- 1,
-};
-
-static struct cmd_node pgroup_node = {
- PGROUP_NODE,
- "%s(config-nat-paging-group)# ",
- 1,
-};
-
-static int config_write_pgroup(struct vty *vty)
-{
- return CMD_SUCCESS;
-}
-
-static void dump_lac(struct vty *vty, struct llist_head *head)
-{
- struct bsc_lac_entry *lac;
- llist_for_each_entry(lac, head, entry)
- vty_out(vty, " location_area_code %u%s", lac->lac, VTY_NEWLINE);
-}
-
-
-static void write_pgroup_lst(struct vty *vty, struct bsc_nat_paging_group *pgroup)
-{
- vty_out(vty, " paging-group %d%s", pgroup->nr, VTY_NEWLINE);
- dump_lac(vty, &pgroup->lists);
-}
-
-static int config_write_nat(struct vty *vty)
-{
- struct bsc_msg_acc_lst *lst;
- struct bsc_nat_paging_group *pgroup;
-
- vty_out(vty, "nat%s", VTY_NEWLINE);
- vty_out(vty, " msc ip %s%s", _nat->main_dest->ip, VTY_NEWLINE);
- vty_out(vty, " msc port %d%s", _nat->main_dest->port, VTY_NEWLINE);
- vty_out(vty, " timeout auth %d%s", _nat->auth_timeout, VTY_NEWLINE);
- vty_out(vty, " timeout ping %d%s", _nat->ping_timeout, VTY_NEWLINE);
- vty_out(vty, " timeout pong %d%s", _nat->pong_timeout, VTY_NEWLINE);
- if (_nat->include_file)
- vty_out(vty, " bscs-config-file %s%s", _nat->include_file, VTY_NEWLINE);
- if (_nat->token)
- vty_out(vty, " token %s%s", _nat->token, VTY_NEWLINE);
- vty_out(vty, " ip-dscp %d%s", _nat->bsc_ip_dscp, VTY_NEWLINE);
- if (_nat->acc_lst_name)
- vty_out(vty, " access-list-name %s%s", _nat->acc_lst_name, VTY_NEWLINE);
- if (_nat->imsi_black_list_fn)
- vty_out(vty, " imsi-black-list-file-name %s%s",
- _nat->imsi_black_list_fn, VTY_NEWLINE);
- if (_nat->ussd_lst_name)
- vty_out(vty, " ussd-list-name %s%s", _nat->ussd_lst_name, VTY_NEWLINE);
- if (_nat->ussd_query)
- vty_out(vty, " ussd-query %s%s", _nat->ussd_query, VTY_NEWLINE);
- if (_nat->ussd_token)
- vty_out(vty, " ussd-token %s%s", _nat->ussd_token, VTY_NEWLINE);
- if (_nat->ussd_local)
- vty_out(vty, " ussd-local-ip %s%s", _nat->ussd_local, VTY_NEWLINE);
-
- if (_nat->num_rewr_name)
- vty_out(vty, " number-rewrite %s%s", _nat->num_rewr_name, VTY_NEWLINE);
- if (_nat->num_rewr_post_name)
- vty_out(vty, " number-rewrite-post %s%s",
- _nat->num_rewr_post_name, VTY_NEWLINE);
-
- if (_nat->smsc_rewr_name)
- vty_out(vty, " rewrite-smsc addr %s%s",
- _nat->smsc_rewr_name, VTY_NEWLINE);
- if (_nat->tpdest_match_name)
- vty_out(vty, " rewrite-smsc tp-dest-match %s%s",
- _nat->tpdest_match_name, VTY_NEWLINE);
- if (_nat->sms_clear_tp_srr_name)
- vty_out(vty, " sms-clear-tp-srr %s%s",
- _nat->sms_clear_tp_srr_name, VTY_NEWLINE);
- if (_nat->sms_num_rewr_name)
- vty_out(vty, " sms-number-rewrite %s%s",
- _nat->sms_num_rewr_name, VTY_NEWLINE);
- if (_nat->num_rewr_trie_name)
- vty_out(vty, " prefix-tree %s%s",
- _nat->num_rewr_trie_name, VTY_NEWLINE);
-
- llist_for_each_entry(lst, &_nat->access_lists, list)
- bsc_msg_acc_lst_write(vty, lst);
- llist_for_each_entry(pgroup, &_nat->paging_groups, entry)
- write_pgroup_lst(vty, pgroup);
- if (_nat->mgcp_ipa)
- vty_out(vty, " use-msc-ipa-for-mgcp%s", VTY_NEWLINE);
- vty_out(vty, " %ssdp-ensure-amr-mode-set%s",
- _nat->sdp_ensure_amr_mode_set ? "" : "no ", VTY_NEWLINE);
-
- return CMD_SUCCESS;
-}
-
-static void config_write_bsc_single(struct vty *vty, struct bsc_config *bsc)
-{
- vty_out(vty, " bsc %u%s", bsc->nr, VTY_NEWLINE);
- vty_out(vty, " token %s%s", bsc->token, VTY_NEWLINE);
- if (bsc->key_present)
- vty_out(vty, " auth-key %s%s", osmo_hexdump(bsc->key, 16), VTY_NEWLINE);
- dump_lac(vty, &bsc->lac_list);
- if (bsc->description)
- vty_out(vty, " description %s%s", bsc->description, VTY_NEWLINE);
- if (bsc->acc_lst_name)
- vty_out(vty, " access-list-name %s%s", bsc->acc_lst_name, VTY_NEWLINE);
- vty_out(vty, " max-endpoints %d%s", bsc->max_endpoints, VTY_NEWLINE);
- if (bsc->paging_group != -1)
- vty_out(vty, " paging group %d%s", bsc->paging_group, VTY_NEWLINE);
- vty_out(vty, " paging forbidden %d%s", bsc->forbid_paging, VTY_NEWLINE);
- switch (bsc->osmux) {
- case OSMUX_USAGE_ON:
- vty_out(vty, " osmux on%s", VTY_NEWLINE);
- break;
- case OSMUX_USAGE_ONLY:
- vty_out(vty, " osmux only%s", VTY_NEWLINE);
- break;
- }
-}
-
-static int config_write_bsc(struct vty *vty)
-{
- struct bsc_config *bsc;
-
- llist_for_each_entry(bsc, &_nat->bsc_configs, entry)
- config_write_bsc_single(vty, bsc);
- return CMD_SUCCESS;
-}
-
-DEFUN(show_bscs, show_bscs_cmd, "show bscs-config",
- SHOW_STR "Show configured BSCs\n"
- "Both from included file and vty\n")
-{
- vty_out(vty, "BSCs configuration loaded from %s:%s", _nat->resolved_path,
- VTY_NEWLINE);
- return config_write_bsc(vty);
-}
-
-DEFUN(show_sccp, show_sccp_cmd, "show sccp connections",
- SHOW_STR "Display information about SCCP\n"
- "All active connections\n")
-{
- struct nat_sccp_connection *con;
- vty_out(vty, "Listing all open SCCP connections%s", VTY_NEWLINE);
-
- llist_for_each_entry(con, &_nat->sccp_connections, list_entry) {
- vty_out(vty, "For BSC Nr: %d BSC ref: 0x%x; MUX ref: 0x%x; Network has ref: %d ref: 0x%x MSC/BSC mux: 0x%x/0x%x type: %s%s",
- con->bsc->cfg ? con->bsc->cfg->nr : -1,
- sccp_src_ref_to_int(&con->real_ref),
- sccp_src_ref_to_int(&con->patched_ref),
- con->has_remote_ref,
- sccp_src_ref_to_int(&con->remote_ref),
- con->msc_endp, con->bsc_endp,
- bsc_con_type_to_string(con->filter_state.con_type),
- VTY_NEWLINE);
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(show_nat_bsc, show_nat_bsc_cmd, "show nat num-bscs-configured",
- SHOW_STR "Display NAT configuration details\n"
- "BSCs-related\n")
-{
- vty_out(vty, "%d BSCs configured%s", _nat->num_bsc, VTY_NEWLINE);
- return CMD_SUCCESS;
-}
-
-DEFUN(show_bsc, show_bsc_cmd, "show bsc connections",
- SHOW_STR BSC_STR
- "All active connections\n")
-{
- struct bsc_connection *con;
- struct sockaddr_in sock;
- socklen_t len = sizeof(sock);
-
- llist_for_each_entry(con, &_nat->bsc_connections, list_entry) {
- getpeername(con->write_queue.bfd.fd, (struct sockaddr *) &sock, &len);
- vty_out(vty, "BSC nr: %d auth: %d fd: %d peername: %s pending-stats: %u%s",
- con->cfg ? con->cfg->nr : -1,
- con->authenticated, con->write_queue.bfd.fd,
- inet_ntoa(sock.sin_addr), con->pending_dlcx_count,
- VTY_NEWLINE);
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(show_bsc_mgcp, show_bsc_mgcp_cmd, "show bsc mgcp NR",
- SHOW_STR BSC_STR MGCP_STR "Identifier of the BSC\n")
-{
- struct bsc_connection *con;
- int nr = atoi(argv[0]);
- int i, j, endp;
-
- llist_for_each_entry(con, &_nat->bsc_connections, list_entry) {
- int max;
- if (!con->cfg)
- continue;
- if (con->cfg->nr != nr)
- continue;
-
- /* this bsc has no audio endpoints yet */
- if (!con->_endpoint_status)
- continue;
-
- vty_out(vty, "MGCP Status for %d%s", con->cfg->nr, VTY_NEWLINE);
- max = bsc_mgcp_nr_multiplexes(con->max_endpoints);
- for (i = 0; i < max; ++i) {
- for (j = 1; j < 32; ++j) {
- endp = mgcp_timeslot_to_endpoint(i, j);
- vty_out(vty, " Endpoint 0x%x %s%s", endp,
- con->_endpoint_status[endp] == 0
- ? "free" : "allocated",
- VTY_NEWLINE);
- }
- }
- break;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(show_bsc_cfg, show_bsc_cfg_cmd, "show bsc config",
- SHOW_STR BSC_STR "Configuration of BSCs\n")
-{
- struct bsc_config *conf;
- llist_for_each_entry(conf, &_nat->bsc_configs, entry) {
- vty_out(vty, "BSC token: '%s' nr: %u%s",
- conf->token, conf->nr, VTY_NEWLINE);
- if (conf->acc_lst_name)
- vty_out(vty, " access-list: %s%s",
- conf->acc_lst_name, VTY_NEWLINE);
- vty_out(vty, " paging forbidden: %d%s",
- conf->forbid_paging, VTY_NEWLINE);
- if (conf->description)
- vty_out(vty, " description: %s%s", conf->description, VTY_NEWLINE);
- else
- vty_out(vty, " No description.%s", VTY_NEWLINE);
-
- }
-
- return CMD_SUCCESS;
-}
-
-static void dump_stat_total(struct vty *vty, struct bsc_nat *nat)
-{
- vty_out(vty, "NAT statistics%s", VTY_NEWLINE);
- vty_out(vty, " SCCP Connections %lu total, %lu calls%s",
- osmo_counter_get(nat->stats.sccp.conn),
- osmo_counter_get(nat->stats.sccp.calls), VTY_NEWLINE);
- vty_out(vty, " MSC Connections %lu%s",
- osmo_counter_get(nat->stats.msc.reconn), VTY_NEWLINE);
- vty_out(vty, " MSC Connected: %d%s",
- bsc_nat_msc_is_connected(nat), VTY_NEWLINE);
- vty_out(vty, " BSC Connections %lu total, %lu auth failed.%s",
- osmo_counter_get(nat->stats.bsc.reconn),
- osmo_counter_get(nat->stats.bsc.auth_fail), VTY_NEWLINE);
-}
-
-static void dump_stat_bsc(struct vty *vty, struct bsc_config *conf)
-{
- int connected = 0;
- struct bsc_connection *con;
-
- vty_out(vty, " BSC nr: %d%s",
- conf->nr, VTY_NEWLINE);
- vty_out_rate_ctr_group(vty, " ", conf->stats.ctrg);
-
- llist_for_each_entry(con, &conf->nat->bsc_connections, list_entry) {
- if (con->cfg != conf)
- continue;
- connected = 1;
- break;
- }
-
- vty_out(vty, " Connected: %d%s", connected, VTY_NEWLINE);
-}
-
-DEFUN(show_stats,
- show_stats_cmd,
- "show statistics [NR]",
- SHOW_STR "Display network statistics\n"
- "Number of the BSC\n")
-{
- struct bsc_config *conf;
-
- int nr = -1;
-
- if (argc == 1)
- nr = atoi(argv[0]);
-
- dump_stat_total(vty, _nat);
- llist_for_each_entry(conf, &_nat->bsc_configs, entry) {
- if (argc == 1 && nr != conf->nr)
- continue;
- dump_stat_bsc(vty, conf);
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(show_stats_lac,
- show_stats_lac_cmd,
- "show statistics-by-lac <0-65535>",
- SHOW_STR "Display network statistics by lac\n"
- "The lac of the BSC\n")
-{
- int lac;
- struct bsc_config *conf;
-
- lac = atoi(argv[0]);
-
- dump_stat_total(vty, _nat);
- llist_for_each_entry(conf, &_nat->bsc_configs, entry) {
- if (!bsc_config_handles_lac(conf, lac))
- continue;
- dump_stat_bsc(vty, conf);
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(show_msc,
- show_msc_cmd,
- "show msc connection",
- SHOW_STR "MSC related information\n"
- "Status of the A-link connection\n")
-{
- if (!_nat->msc_con) {
- vty_out(vty, "The MSC is not yet configured.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- vty_out(vty, "MSC is connected: %d%s",
- bsc_nat_msc_is_connected(_nat), VTY_NEWLINE);
- return CMD_SUCCESS;
-}
-
-DEFUN(close_bsc,
- close_bsc_cmd,
- "close bsc connection BSC_NR",
- "Close\n" "A-link\n" "Connection\n" "Identifier of the BSC\n")
-{
- struct bsc_connection *bsc;
- int bsc_nr = atoi(argv[0]);
-
- llist_for_each_entry(bsc, &_nat->bsc_connections, list_entry) {
- if (!bsc->cfg || bsc->cfg->nr != bsc_nr)
- continue;
- bsc_close_connection(bsc);
- break;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat, cfg_nat_cmd, "nat", "Configure the NAT")
-{
- vty->index = _nat;
- vty->node = NAT_NODE;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_msc_ip,
- cfg_nat_msc_ip_cmd,
- "msc ip A.B.C.D",
- "MSC related configuration\n"
- "Configure the IP address\n" IP_STR)
-{
- bsc_nat_set_msc_ip(_nat, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_msc_port,
- cfg_nat_msc_port_cmd,
- "msc port <1-65500>",
- "MSC related configuration\n"
- "Configure the port\n"
- "Port number\n")
-{
- _nat->main_dest->port = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_auth_time,
- cfg_nat_auth_time_cmd,
- "timeout auth <1-256>",
- "Timeout configuration\n"
- "Authentication timeout\n"
- "Timeout in seconds\n")
-{
- _nat->auth_timeout = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_ping_time,
- cfg_nat_ping_time_cmd,
- "timeout ping NR",
- "Timeout configuration\n"
- "Time between two pings\n"
- "Timeout in seconds\n")
-{
- _nat->ping_timeout = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_pong_time,
- cfg_nat_pong_time_cmd,
- "timeout pong NR",
- "Timeout configuration\n"
- "Waiting for pong timeout\n"
- "Timeout in seconds\n")
-{
- _nat->pong_timeout = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_token, cfg_nat_token_cmd,
- "token TOKEN",
- "Authentication token configuration\n"
- "Token of the BSC, currently transferred in cleartext\n")
-{
- osmo_talloc_replace_string(_nat, &_nat->token, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_bsc_ip_dscp, cfg_nat_bsc_ip_dscp_cmd,
- "ip-dscp <0-255>",
- "Set the IP DSCP for the BSCs to use\n" "Set the IP_TOS attribute")
-{
- _nat->bsc_ip_dscp = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-ALIAS_DEPRECATED(cfg_nat_bsc_ip_dscp, cfg_nat_bsc_ip_tos_cmd,
- "ip-tos <0-255>",
- "Use ip-dscp in the future.\n" "Set the DSCP\n")
-
-
-DEFUN(cfg_nat_acc_lst_name,
- cfg_nat_acc_lst_name_cmd,
- "access-list-name NAME",
- "Set the name of the access list to use.\n"
- "The name of the to be used access list.")
-{
- osmo_talloc_replace_string(_nat, &_nat->acc_lst_name, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_include,
- cfg_nat_include_cmd,
- "bscs-config-file NAME",
- "Set the filename of the BSC configuration to include.\n"
- "The filename to be included.")
-{
- char *path;
- int rc;
- struct bsc_config *cf1, *cf2;
- struct bsc_connection *con1, *con2;
-
- if ('/' == argv[0][0])
- osmo_talloc_replace_string(_nat, &_nat->resolved_path, argv[0]);
- else {
- path = talloc_asprintf(_nat, "%s/%s", _nat->include_base,
- argv[0]);
- osmo_talloc_replace_string(_nat, &_nat->resolved_path, path);
- talloc_free(path);
- }
-
- llist_for_each_entry_safe(cf1, cf2, &_nat->bsc_configs, entry) {
- cf1->remove = true;
- cf1->token_updated = false;
- }
-
- rc = vty_read_config_file(_nat->resolved_path, NULL);
- if (rc < 0) {
- vty_out(vty, "Failed to parse the config file %s: %s%s",
- _nat->resolved_path, strerror(-rc), VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- osmo_talloc_replace_string(_nat, &_nat->include_file, argv[0]);
-
- llist_for_each_entry_safe(con1, con2, &_nat->bsc_connections,
- list_entry) {
- if (con1->cfg)
- if (con1->cfg->token_updated || con1->cfg->remove)
- bsc_close_connection(con1);
- }
-
- llist_for_each_entry_safe(cf1, cf2, &_nat->bsc_configs, entry) {
- if (cf1->remove)
- bsc_config_free(cf1);
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_no_acc_lst_name,
- cfg_nat_no_acc_lst_name_cmd,
- "no access-list-name",
- NO_STR "Remove the access list from the NAT.\n")
-{
- if (_nat->acc_lst_name) {
- talloc_free(_nat->acc_lst_name);
- _nat->acc_lst_name = NULL;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_imsi_black_list_fn,
- cfg_nat_imsi_black_list_fn_cmd,
- "imsi-black-list-file-name NAME",
- "IMSI black listing\n" "Filename IMSI and reject-cause\n")
-{
-
- osmo_talloc_replace_string(_nat, &_nat->imsi_black_list_fn, argv[0]);
- if (_nat->imsi_black_list_fn) {
- int rc;
- struct osmo_config_list *rewr = NULL;
- rewr = osmo_config_list_parse(_nat, _nat->imsi_black_list_fn);
- rc = bsc_filter_barr_adapt(_nat, &_nat->imsi_black_list, rewr);
- if (rc != 0) {
- vty_out(vty, "%%There was an error parsing the list."
- " Please see the error log.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- return CMD_SUCCESS;
- }
-
- bsc_filter_barr_adapt(_nat, &_nat->imsi_black_list, NULL);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_no_imsi_black_list_fn,
- cfg_nat_no_imsi_black_list_fn_cmd,
- "no imsi-black-list-file-name",
- NO_STR "Remove the imsi-black-list\n")
-{
- talloc_free(_nat->imsi_black_list_fn);
- _nat->imsi_black_list_fn = NULL;
- bsc_filter_barr_adapt(_nat, &_nat->imsi_black_list, NULL);
- return CMD_SUCCESS;
-}
-
-static int replace_rules(struct bsc_nat *nat, char **name,
- struct llist_head *head, const char *file)
-{
- struct osmo_config_list *rewr = NULL;
-
- osmo_talloc_replace_string(nat, name, file);
- if (*name) {
- rewr = osmo_config_list_parse(nat, *name);
- bsc_nat_num_rewr_entry_adapt(nat, head, rewr);
- talloc_free(rewr);
- return CMD_SUCCESS;
- } else {
- bsc_nat_num_rewr_entry_adapt(nat, head, NULL);
- return CMD_SUCCESS;
- }
-}
-
-DEFUN(cfg_nat_number_rewrite,
- cfg_nat_number_rewrite_cmd,
- "number-rewrite FILENAME",
- "Set the file with rewriting rules.\n" "Filename")
-{
- return replace_rules(_nat, &_nat->num_rewr_name,
- &_nat->num_rewr, argv[0]);
-}
-
-DEFUN(cfg_nat_no_number_rewrite,
- cfg_nat_no_number_rewrite_cmd,
- "no number-rewrite",
- NO_STR "Set the file with rewriting rules.\n")
-{
- talloc_free(_nat->num_rewr_name);
- _nat->num_rewr_name = NULL;
-
- bsc_nat_num_rewr_entry_adapt(NULL, &_nat->num_rewr, NULL);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_number_rewrite_post,
- cfg_nat_number_rewrite_post_cmd,
- "number-rewrite-post FILENAME",
- "Set the file with post-routing rewriting rules.\n" "Filename")
-{
- return replace_rules(_nat, &_nat->num_rewr_post_name,
- &_nat->num_rewr_post, argv[0]);
-}
-
-DEFUN(cfg_nat_no_number_rewrite_post,
- cfg_nat_no_number_rewrite_post_cmd,
- "no number-rewrite-post",
- NO_STR "Set the file with post-routing rewriting rules.\n")
-{
- talloc_free(_nat->num_rewr_post_name);
- _nat->num_rewr_post_name = NULL;
-
- bsc_nat_num_rewr_entry_adapt(NULL, &_nat->num_rewr_post, NULL);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_smsc_addr,
- cfg_nat_smsc_addr_cmd,
- "rewrite-smsc addr FILENAME",
- SMSC_REWRITE
- "The SMSC Address to match and replace in RP-DATA\n"
- "File with rules for the SMSC Address replacing\n")
-{
- return replace_rules(_nat, &_nat->smsc_rewr_name,
- &_nat->smsc_rewr, argv[0]);
-}
-
-DEFUN(cfg_nat_smsc_tpdest,
- cfg_nat_smsc_tpdest_cmd,
- "rewrite-smsc tp-dest-match FILENAME",
- SMSC_REWRITE
- "Match TP-Destination of a SMS.\n"
- "File with rules for matching MSISDN and TP-DEST\n")
-{
- return replace_rules(_nat, &_nat->tpdest_match_name,
- &_nat->tpdest_match, argv[0]);
-}
-
-DEFUN(cfg_nat_sms_clear_tpsrr,
- cfg_nat_sms_clear_tpsrr_cmd,
- "sms-clear-tp-srr FILENAME",
- "SMS TPDU Sender Report Request clearing\n"
- "Files with rules for matching MSISDN\n")
-{
- return replace_rules(_nat, &_nat->sms_clear_tp_srr_name,
- &_nat->sms_clear_tp_srr, argv[0]);
-}
-
-DEFUN(cfg_nat_no_sms_clear_tpsrr,
- cfg_nat_no_sms_clear_tpsrr_cmd,
- "no sms-clear-tp-srr",
- NO_STR
- "SMS TPDU Sender Report Request clearing\n")
-{
- talloc_free(_nat->sms_clear_tp_srr_name);
- _nat->sms_clear_tp_srr_name = NULL;
-
- bsc_nat_num_rewr_entry_adapt(NULL, &_nat->sms_clear_tp_srr, NULL);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_sms_number_rewrite,
- cfg_nat_sms_number_rewrite_cmd,
- "sms-number-rewrite FILENAME",
- "SMS TP-DA Number rewriting\n"
- "Files with rules for matching MSISDN\n")
-{
- return replace_rules(_nat, &_nat->sms_num_rewr_name,
- &_nat->sms_num_rewr, argv[0]);
-}
-
-DEFUN(cfg_nat_no_sms_number_rewrite,
- cfg_nat_no_sms_number_rewrite_cmd,
- "no sms-number-rewrite",
- NO_STR "Disable SMS TP-DA rewriting\n")
-{
- talloc_free(_nat->sms_num_rewr_name);
- _nat->sms_num_rewr_name = NULL;
-
- bsc_nat_num_rewr_entry_adapt(NULL, &_nat->sms_num_rewr, NULL);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_prefix_trie,
- cfg_nat_prefix_trie_cmd,
- "prefix-tree FILENAME",
- "Prefix tree for number rewriting\n" "File to load\n")
-{
- /* give up the old data */
- talloc_free(_nat->num_rewr_trie);
- _nat->num_rewr_trie = NULL;
-
- /* replace the file name */
- osmo_talloc_replace_string(_nat, &_nat->num_rewr_trie_name, argv[0]);
- if (!_nat->num_rewr_trie_name) {
- vty_out(vty, "%% prefix-tree no filename is present.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- _nat->num_rewr_trie = nat_rewrite_parse(_nat, _nat->num_rewr_trie_name);
- if (!_nat->num_rewr_trie) {
- vty_out(vty, "%% prefix-tree parsing has failed.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- vty_out(vty, "%% prefix-tree loaded %zu rules.%s",
- _nat->num_rewr_trie->prefixes, VTY_NEWLINE);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_no_prefix_trie, cfg_nat_no_prefix_trie_cmd,
- "no prefix-tree",
- NO_STR "Prefix tree for number rewriting\n")
-{
- talloc_free(_nat->num_rewr_trie);
- _nat->num_rewr_trie = NULL;
- talloc_free(_nat->num_rewr_trie_name);
- _nat->num_rewr_trie_name = NULL;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(show_prefix_tree, show_prefix_tree_cmd,
- "show prefix-tree",
- SHOW_STR "Prefix tree for number rewriting\n")
-{
- if (!_nat->num_rewr_trie) {
- vty_out(vty, "%% there is now prefix tree loaded.%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- nat_rewrite_dump_vty(vty, _nat->num_rewr_trie);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_ussd_lst_name,
- cfg_nat_ussd_lst_name_cmd,
- "ussd-list-name NAME",
- "Set the name of the access list to check for IMSIs for USSD message\n"
- "The name of the access list for HLR USSD handling")
-{
- osmo_talloc_replace_string(_nat, &_nat->ussd_lst_name, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_ussd_query,
- cfg_nat_ussd_query_cmd,
- "ussd-query REGEXP",
- "Set the USSD query to match with the ussd-list-name\n"
- "The query to match")
-{
- if (gsm_parse_reg(_nat, &_nat->ussd_query_re, &_nat->ussd_query, argc, argv) != 0)
- return CMD_WARNING;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_ussd_token,
- cfg_nat_ussd_token_cmd,
- "ussd-token TOKEN",
- "Set the token used to identify the USSD module\n" "Secret key\n")
-{
- osmo_talloc_replace_string(_nat, &_nat->ussd_token, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_ussd_local,
- cfg_nat_ussd_local_cmd,
- "ussd-local-ip A.B.C.D",
- "Set the IP to listen for the USSD Provider\n" "IP Address\n")
-{
- osmo_talloc_replace_string(_nat, &_nat->ussd_local, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_use_ipa_for_mgcp,
- cfg_nat_use_ipa_for_mgcp_cmd,
- "use-msc-ipa-for-mgcp",
- "This needs to be set at start. Handle MGCP messages through "
- "the IPA protocol and not through the UDP socket.\n")
-{
- if (_nat->mgcp_cfg->data)
- vty_out(vty,
- "%%the setting will not be applied right now.%s",
- VTY_NEWLINE);
- _nat->mgcp_ipa = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_sdp_amr_mode_set,
- cfg_nat_sdp_amr_mode_set_cmd,
- "sdp-ensure-amr-mode-set",
- "Ensure that SDP records include a mode-set\n")
-{
- _nat->sdp_ensure_amr_mode_set = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_no_sdp_amr_mode_set,
- cfg_nat_no_sdp_amr_mode_set_cmd,
- "no sdp-ensure-amr-mode-set",
- NO_STR "Ensure that SDP records include a mode-set\n")
-{
- _nat->sdp_ensure_amr_mode_set = 0;
- return CMD_SUCCESS;
-}
-
-/* per BSC configuration */
-DEFUN(cfg_bsc, cfg_bsc_cmd, "bsc BSC_NR",
- "BSC configuration\n" "Identifier of the BSC\n")
-{
- int bsc_nr = atoi(argv[0]);
- struct bsc_config *bsc = bsc_config_num(_nat, bsc_nr);
-
- /* allocate a new one */
- if (!bsc)
- bsc = bsc_config_alloc(_nat, "unknown", bsc_nr);
-
- if (!bsc)
- return CMD_WARNING;
-
- bsc->remove = false;
- vty->index = bsc;
- vty->node = NAT_BSC_NODE;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bsc_token, cfg_bsc_token_cmd, "token TOKEN",
- "Authentication token configuration\n"
- "Token of the BSC, currently transferred in cleartext\n")
-{
- struct bsc_config *conf = vty->index;
-
- if (strncmp(conf->token, argv[0], 128) != 0)
- conf->token_updated = true;
-
- osmo_talloc_replace_string(conf, &conf->token, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bsc_auth_key, cfg_bsc_auth_key_cmd,
- "auth-key KEY",
- "Authentication (secret) key configuration\n"
- "Non null security key\n")
-{
- struct bsc_config *conf = vty->index;
-
- memset(conf->key, 0, sizeof(conf->key));
- osmo_hexparse(argv[0], conf->key, sizeof(conf->key));
- conf->key_present = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bsc_no_auth_key, cfg_bsc_no_auth_key_cmd,
- "no auth-key",
- NO_STR "Authentication (secret) key configuration\n")
-{
- struct bsc_config *conf = vty->index;
-
- memset(conf->key, 0, sizeof(conf->key));
- conf->key_present = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bsc_lac, cfg_bsc_lac_cmd, "location_area_code <0-65535>",
- "Add the Location Area Code (LAC) of this BSC\n" "LAC\n")
-{
- struct bsc_config *tmp;
- struct bsc_config *conf = vty->index;
-
- int lac = atoi(argv[0]);
-
- if (lac == GSM_LAC_RESERVED_DETACHED || lac == GSM_LAC_RESERVED_ALL_BTS) {
- vty_out(vty, "%% LAC %d is reserved by GSM 04.08%s",
- lac, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- /* verify that the LACs are unique */
- llist_for_each_entry(tmp, &_nat->bsc_configs, entry) {
- if (bsc_config_handles_lac(tmp, lac)) {
- if (tmp->nr != conf->nr) {
- vty_out(vty, "%% LAC %d is already used.%s", lac,
- VTY_NEWLINE);
- return CMD_ERR_INCOMPLETE;
- }
- }
- }
-
- bsc_config_add_lac(conf, lac);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bsc_no_lac, cfg_bsc_no_lac_cmd,
- "no location_area_code <0-65535>",
- NO_STR "Remove the Location Area Code (LAC) of this BSC\n" "LAC\n")
-{
- int lac = atoi(argv[0]);
- struct bsc_config *conf = vty->index;
-
- bsc_config_del_lac(conf, lac);
- return CMD_SUCCESS;
-}
-
-DEFUN(show_bar_lst,
- show_bar_lst_cmd,
- "show imsi-black-list",
- SHOW_STR "IMSIs barred from the network\n")
-{
- struct rb_node *node;
-
- vty_out(vty, "IMSIs barred from the network:%s", VTY_NEWLINE);
-
- for (node = rb_first(&_nat->imsi_black_list); node; node = rb_next(node)) {
- struct bsc_filter_barr_entry *entry;
- entry = rb_entry(node, struct bsc_filter_barr_entry, node);
-
- vty_out(vty, " IMSI(%s) CM-Reject-Cause(%d) LU-Reject-Cause(%d)%s",
- entry->imsi, entry->cm_reject_cause, entry->lu_reject_cause,
- VTY_NEWLINE);
- }
-
- return CMD_SUCCESS;
-}
-
-
-DEFUN(cfg_bsc_acc_lst_name,
- cfg_bsc_acc_lst_name_cmd,
- "access-list-name NAME",
- "Set the name of the access list to use.\n"
- "The name of the to be used access list.")
-{
- struct bsc_config *conf = vty->index;
-
- osmo_talloc_replace_string(conf, &conf->acc_lst_name, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bsc_no_acc_lst_name,
- cfg_bsc_no_acc_lst_name_cmd,
- "no access-list-name",
- NO_STR "Do not use an access-list for the BSC.\n")
-{
- struct bsc_config *conf = vty->index;
-
- if (conf->acc_lst_name) {
- talloc_free(conf->acc_lst_name);
- conf->acc_lst_name = NULL;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bsc_max_endps, cfg_bsc_max_endps_cmd,
- "max-endpoints <1-1024>",
- "Highest endpoint to use (exclusively)\n" "Number of ports\n")
-{
- struct bsc_config *conf = vty->index;
-
- conf->max_endpoints = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bsc_paging,
- cfg_bsc_paging_cmd,
- "paging forbidden (0|1)",
- PAGING_STR "Forbid sending PAGING REQUESTS to the BSC.\n"
- "Do not forbid\n" "Forbid\n")
-{
- struct bsc_config *conf = vty->index;
-
- if (strcmp("1", argv[0]) == 0)
- conf->forbid_paging = 1;
- else
- conf->forbid_paging = 0;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bsc_desc,
- cfg_bsc_desc_cmd,
- "description DESC",
- "Provide a description for the given BSC.\n" "Description\n")
-{
- struct bsc_config *conf = vty->index;
-
- osmo_talloc_replace_string(conf, &conf->description, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bsc_paging_grp,
- cfg_bsc_paging_grp_cmd,
- "paging group <0-1000>",
- PAGING_STR "Use a paging group\n" "Paging Group to use\n")
-{
- struct bsc_config *conf = vty->index;
- conf->paging_group = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-ALIAS_DEPRECATED(cfg_bsc_paging_grp, cfg_bsc_old_grp_cmd,
- "paging-group <0-1000>",
- "Use a paging group\n" "Paging Group to use\n")
-
-DEFUN(cfg_bsc_no_paging_grp,
- cfg_bsc_no_paging_grp_cmd,
- "no paging group",
- NO_STR PAGING_STR "Disable the usage of a paging group.\n")
-{
- struct bsc_config *conf = vty->index;
- conf->paging_group = PAGIN_GROUP_UNASSIGNED;
- return CMD_SUCCESS;
-}
-
-DEFUN(test_regex, test_regex_cmd,
- "test regex PATTERN STRING",
- "Test utilities\n"
- "Regexp testing\n" "The regexp pattern\n"
- "The string to match\n")
-{
- regex_t reg;
- char *str = NULL;
-
- memset(&reg, 0, sizeof(reg));
- if (gsm_parse_reg(_nat, &reg, &str, 1, argv) != 0)
- return CMD_WARNING;
-
- vty_out(vty, "String matches allow pattern: %d%s",
- regexec(&reg, argv[1], 0, NULL, 0) == 0, VTY_NEWLINE);
-
- talloc_free(str);
- regfree(&reg);
- return CMD_SUCCESS;
-}
-
-DEFUN(set_last_endp, set_last_endp_cmd,
- "set bsc last-used-endpoint <0-9999999999> <0-1024>",
- "Set a value\n" "Operate on a BSC\n"
- "Last used endpoint for an assignment\n" "BSC configuration number\n"
- "Endpoint number used\n")
-{
- struct bsc_connection *con;
- int nr = atoi(argv[0]);
- int endp = atoi(argv[1]);
-
-
- llist_for_each_entry(con, &_nat->bsc_connections, list_entry) {
- if (!con->cfg)
- continue;
- if (con->cfg->nr != nr)
- continue;
-
- con->last_endpoint = endp;
- vty_out(vty, "Updated the last endpoint for %d to %d.%s",
- con->cfg->nr, con->last_endpoint, VTY_NEWLINE);
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(block_new_conn, block_new_conn_cmd,
- "nat-block (block|unblock)",
- "Block the NAT for new connections\n"
- "Block\n" "Unblock\n")
-{
- _nat->blocked = argv[0][0] == 'b';
- vty_out(vty, "%%Going to %s the NAT.%s",
- _nat->blocked ? "block" : "unblock", VTY_NEWLINE);
- return CMD_SUCCESS;
-}
-
-/* paging group */
-DEFUN(cfg_nat_pgroup, cfg_nat_pgroup_cmd,
- "paging-group <0-1000>",
- "Create a Paging Group\n" "Number of the Group\n")
-{
- int group = atoi(argv[0]);
- struct bsc_nat_paging_group *pgroup;
- pgroup = bsc_nat_paging_group_num(_nat, group);
- if (!pgroup)
- pgroup = bsc_nat_paging_group_create(_nat, group);
- if (!pgroup) {
- vty_out(vty, "Failed to create the group.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- vty->index = pgroup;
- vty->node = PGROUP_NODE;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_nat_no_pgroup, cfg_nat_no_pgroup_cmd,
- "no paging-group <0-1000>",
- NO_STR "Delete paging-group\n" "Paging-group number\n")
-{
- int group = atoi(argv[0]);
- struct bsc_nat_paging_group *pgroup;
- pgroup = bsc_nat_paging_group_num(_nat, group);
- if (!pgroup) {
- vty_out(vty, "No such paging group %d.%s", group, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bsc_nat_paging_group_delete(pgroup);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_pgroup_lac, cfg_pgroup_lac_cmd,
- "location_area_code <0-65535>",
- "Add the Location Area Code (LAC)\n" "LAC\n")
-{
- struct bsc_nat_paging_group *pgroup = vty->index;
-
- int lac = atoi(argv[0]);
- if (lac == GSM_LAC_RESERVED_DETACHED || lac == GSM_LAC_RESERVED_ALL_BTS) {
- vty_out(vty, "%% LAC %d is reserved by GSM 04.08%s",
- lac, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bsc_nat_paging_group_add_lac(pgroup, lac);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_pgroup_no_lac, cfg_pgroup_no_lac_cmd,
- "no location_area_code <0-65535>",
- NO_STR "Remove the Location Area Code (LAC)\n" "LAC\n")
-{
- int lac = atoi(argv[0]);
- struct bsc_nat_paging_group *pgroup = vty->index;
-
- bsc_nat_paging_group_del_lac(pgroup, lac);
- return CMD_SUCCESS;
-}
-
-DEFUN(show_ussd_connection,
- show_ussd_connection_cmd,
- "show ussd-connection",
- SHOW_STR "USSD connection related information\n")
-{
- vty_out(vty, "The USSD side channel provider is %sconnected and %sauthorized.%s",
- _nat->ussd_con ? "" : "not ",
- _nat->ussd_con && _nat->ussd_con->authorized? "" : "not ",
- VTY_NEWLINE);
- return CMD_SUCCESS;
-}
-
-#define OSMUX_STR "RTP multiplexing\n"
-DEFUN(cfg_bsc_osmux,
- cfg_bsc_osmux_cmd,
- "osmux (on|off|only)",
- OSMUX_STR "Enable OSMUX\n" "Disable OSMUX\n" "Only OSMUX\n")
-{
- struct bsc_config *conf = vty->index;
- int old = conf->osmux;
-
- if (strcmp(argv[0], "on") == 0)
- conf->osmux = OSMUX_USAGE_ON;
- else if (strcmp(argv[0], "off") == 0)
- conf->osmux = OSMUX_USAGE_OFF;
- else if (strcmp(argv[0], "only") == 0)
- conf->osmux = OSMUX_USAGE_ONLY;
-
- if (old == 0 && conf->osmux > 0 && !conf->nat->mgcp_cfg->osmux_init) {
- LOGP(DLMGCP, LOGL_NOTICE, "Setting up OSMUX socket\n");
- if (osmux_init(OSMUX_ROLE_BSC_NAT, conf->nat->mgcp_cfg) < 0) {
- LOGP(DLMGCP, LOGL_ERROR, "Cannot init OSMUX\n");
- vty_out(vty, "%% failed to create Osmux socket%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- } else if (old > 0 && conf->osmux == 0) {
- LOGP(DLMGCP, LOGL_NOTICE, "Disabling OSMUX socket\n");
- /* Don't stop the socket, we may already have ongoing voice
- * flows already using Osmux. This just switch indicates that
- * new upcoming flows should use RTP.
- */
- }
-
- return CMD_SUCCESS;
-}
-
-int bsc_nat_vty_init(struct bsc_nat *nat)
-{
- _nat = nat;
-
- /* show commands */
- install_element_ve(&show_sccp_cmd);
- install_element_ve(&show_bsc_cmd);
- install_element_ve(&show_nat_bsc_cmd);
- install_element_ve(&show_bsc_cfg_cmd);
- install_element_ve(&show_stats_cmd);
- install_element_ve(&show_stats_lac_cmd);
- install_element_ve(&close_bsc_cmd);
- install_element_ve(&show_msc_cmd);
- install_element_ve(&test_regex_cmd);
- install_element_ve(&show_bsc_mgcp_cmd);
- install_element_ve(&show_bscs_cmd);
- install_element_ve(&show_bar_lst_cmd);
- install_element_ve(&show_prefix_tree_cmd);
- install_element_ve(&show_ussd_connection_cmd);
-
- install_element(ENABLE_NODE, &set_last_endp_cmd);
- install_element(ENABLE_NODE, &block_new_conn_cmd);
-
- /* nat group */
- install_element(CONFIG_NODE, &cfg_nat_cmd);
- install_node(&nat_node, config_write_nat);
- vty_install_default(NAT_NODE);
- install_element(NAT_NODE, &cfg_nat_msc_ip_cmd);
- install_element(NAT_NODE, &cfg_nat_msc_port_cmd);
- install_element(NAT_NODE, &cfg_nat_auth_time_cmd);
- install_element(NAT_NODE, &cfg_nat_ping_time_cmd);
- install_element(NAT_NODE, &cfg_nat_pong_time_cmd);
- install_element(NAT_NODE, &cfg_nat_token_cmd);
- install_element(NAT_NODE, &cfg_nat_bsc_ip_dscp_cmd);
- install_element(NAT_NODE, &cfg_nat_bsc_ip_tos_cmd);
- install_element(NAT_NODE, &cfg_nat_acc_lst_name_cmd);
- install_element(NAT_NODE, &cfg_nat_no_acc_lst_name_cmd);
- install_element(NAT_NODE, &cfg_nat_include_cmd);
- install_element(NAT_NODE, &cfg_nat_imsi_black_list_fn_cmd);
- install_element(NAT_NODE, &cfg_nat_no_imsi_black_list_fn_cmd);
- install_element(NAT_NODE, &cfg_nat_ussd_lst_name_cmd);
- install_element(NAT_NODE, &cfg_nat_ussd_query_cmd);
- install_element(NAT_NODE, &cfg_nat_ussd_token_cmd);
- install_element(NAT_NODE, &cfg_nat_ussd_local_cmd);
- install_element(NAT_NODE, &cfg_nat_use_ipa_for_mgcp_cmd);
-
- bsc_msg_lst_vty_init(nat, &nat->access_lists, NAT_NODE);
-
- /* number rewriting */
- install_element(NAT_NODE, &cfg_nat_number_rewrite_cmd);
- install_element(NAT_NODE, &cfg_nat_no_number_rewrite_cmd);
- install_element(NAT_NODE, &cfg_nat_number_rewrite_post_cmd);
- install_element(NAT_NODE, &cfg_nat_no_number_rewrite_post_cmd);
- install_element(NAT_NODE, &cfg_nat_smsc_addr_cmd);
- install_element(NAT_NODE, &cfg_nat_smsc_tpdest_cmd);
- install_element(NAT_NODE, &cfg_nat_sms_clear_tpsrr_cmd);
- install_element(NAT_NODE, &cfg_nat_no_sms_clear_tpsrr_cmd);
- install_element(NAT_NODE, &cfg_nat_sms_number_rewrite_cmd);
- install_element(NAT_NODE, &cfg_nat_no_sms_number_rewrite_cmd);
- install_element(NAT_NODE, &cfg_nat_prefix_trie_cmd);
- install_element(NAT_NODE, &cfg_nat_no_prefix_trie_cmd);
-
- install_element(NAT_NODE, &cfg_nat_sdp_amr_mode_set_cmd);
- install_element(NAT_NODE, &cfg_nat_no_sdp_amr_mode_set_cmd);
-
- install_element(NAT_NODE, &cfg_nat_pgroup_cmd);
- install_element(NAT_NODE, &cfg_nat_no_pgroup_cmd);
- install_node(&pgroup_node, config_write_pgroup);
- vty_install_default(PGROUP_NODE);
- install_element(PGROUP_NODE, &cfg_pgroup_lac_cmd);
- install_element(PGROUP_NODE, &cfg_pgroup_no_lac_cmd);
-
- /* BSC subgroups */
- install_element(NAT_NODE, &cfg_bsc_cmd);
- install_node(&bsc_node, NULL);
- vty_install_default(NAT_BSC_NODE);
- install_element(NAT_BSC_NODE, &cfg_bsc_token_cmd);
- install_element(NAT_BSC_NODE, &cfg_bsc_auth_key_cmd);
- install_element(NAT_BSC_NODE, &cfg_bsc_no_auth_key_cmd);
- install_element(NAT_BSC_NODE, &cfg_bsc_lac_cmd);
- install_element(NAT_BSC_NODE, &cfg_bsc_no_lac_cmd);
- install_element(NAT_BSC_NODE, &cfg_bsc_paging_cmd);
- install_element(NAT_BSC_NODE, &cfg_bsc_desc_cmd);
- install_element(NAT_BSC_NODE, &cfg_bsc_acc_lst_name_cmd);
- install_element(NAT_BSC_NODE, &cfg_bsc_no_acc_lst_name_cmd);
- install_element(NAT_BSC_NODE, &cfg_bsc_max_endps_cmd);
- install_element(NAT_BSC_NODE, &cfg_bsc_old_grp_cmd);
- install_element(NAT_BSC_NODE, &cfg_bsc_paging_grp_cmd);
- install_element(NAT_BSC_NODE, &cfg_bsc_no_paging_grp_cmd);
- install_element(NAT_BSC_NODE, &cfg_bsc_osmux_cmd);
-
- mgcp_vty_init();
-
- return 0;
-}
-
-
-/* called by the telnet interface... we have our own init above */
-int bsc_vty_init(struct gsm_network *network)
-{
- logging_vty_add_cmds(NULL);
- return 0;
-}
diff --git a/src/osmo-bsc_nat/bsc_sccp.c b/src/osmo-bsc_nat/bsc_sccp.c
deleted file mode 100644
index c6c265f7a..000000000
--- a/src/osmo-bsc_nat/bsc_sccp.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/* SCCP patching and handling routines */
-/*
- * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010 by On-Waves
- * 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 <openbsc/debug.h>
-#include <openbsc/bsc_nat.h>
-#include <openbsc/bsc_nat_sccp.h>
-
-#include <osmocom/sccp/sccp.h>
-
-#include <osmocom/core/talloc.h>
-
-#include <string.h>
-#include <time.h>
-
-static int equal(struct sccp_source_reference *ref1, struct sccp_source_reference *ref2)
-{
- return memcmp(ref1, ref2, sizeof(*ref1)) == 0;
-}
-
-/*
- * SCCP patching below
- */
-
-/* check if we are using this ref for patched already */
-static int sccp_ref_is_free(struct sccp_source_reference *ref, struct bsc_nat *nat)
-{
- struct nat_sccp_connection *conn;
-
- llist_for_each_entry(conn, &nat->sccp_connections, list_entry) {
- if (equal(ref, &conn->patched_ref))
- return -1;
- }
-
- return 0;
-}
-
-/* copied from sccp.c */
-static int assign_src_local_reference(struct sccp_source_reference *ref, struct bsc_nat *nat)
-{
- static uint32_t last_ref = 0x50000;
- int wrapped = 0;
-
- do {
- struct sccp_source_reference reference;
- reference.octet1 = (last_ref >> 0) & 0xff;
- reference.octet2 = (last_ref >> 8) & 0xff;
- reference.octet3 = (last_ref >> 16) & 0xff;
-
- ++last_ref;
- /* do not use the reversed word and wrap around */
- if ((last_ref & 0x00FFFFFF) == 0x00FFFFFF) {
- LOGP(DNAT, LOGL_NOTICE, "Wrapped searching for a free code\n");
- last_ref = 0;
- ++wrapped;
- }
-
- if (sccp_ref_is_free(&reference, nat) == 0) {
- *ref = reference;
- return 0;
- }
- } while (wrapped != 2);
-
- LOGP(DNAT, LOGL_ERROR, "Finding a free reference failed\n");
- return -1;
-}
-
-struct nat_sccp_connection *create_sccp_src_ref(struct bsc_connection *bsc,
- struct bsc_nat_parsed *parsed)
-{
- struct nat_sccp_connection *conn;
-
- /* Some commercial BSCs like to reassign there SRC ref */
- llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) {
- if (conn->bsc != bsc)
- continue;
- if (!equal(parsed->src_local_ref, &conn->real_ref))
- continue;
-
- /* the BSC has reassigned the SRC ref and we failed to keep track */
- memset(&conn->remote_ref, 0, sizeof(conn->remote_ref));
- if (assign_src_local_reference(&conn->patched_ref, bsc->nat) != 0) {
- LOGP(DNAT, LOGL_ERROR, "BSC %d reused src ref: %d and we failed to generate a new id.\n",
- bsc->cfg->nr, sccp_src_ref_to_int(parsed->src_local_ref));
- bsc_mgcp_dlcx(conn);
- llist_del(&conn->list_entry);
- talloc_free(conn);
- return NULL;
- } else {
- clock_gettime(CLOCK_MONOTONIC, &conn->creation_time);
- bsc_mgcp_dlcx(conn);
- return conn;
- }
- }
-
-
- conn = talloc_zero(bsc->nat, struct nat_sccp_connection);
- if (!conn) {
- LOGP(DNAT, LOGL_ERROR, "Memory allocation failure.\n");
- return NULL;
- }
-
- conn->bsc = bsc;
- clock_gettime(CLOCK_MONOTONIC, &conn->creation_time);
- conn->real_ref = *parsed->src_local_ref;
- if (assign_src_local_reference(&conn->patched_ref, bsc->nat) != 0) {
- LOGP(DNAT, LOGL_ERROR, "Failed to assign a ref.\n");
- talloc_free(conn);
- return NULL;
- }
-
- bsc_mgcp_init(conn);
- llist_add_tail(&conn->list_entry, &bsc->nat->sccp_connections);
- rate_ctr_inc(&bsc->cfg->stats.ctrg->ctr[BCFG_CTR_SCCP_CONN]);
- osmo_counter_inc(bsc->cfg->nat->stats.sccp.conn);
-
- LOGP(DNAT, LOGL_DEBUG, "Created 0x%x <-> 0x%x mapping for con %p\n",
- sccp_src_ref_to_int(&conn->real_ref),
- sccp_src_ref_to_int(&conn->patched_ref), bsc);
-
- return conn;
-}
-
-int update_sccp_src_ref(struct nat_sccp_connection *sccp, struct bsc_nat_parsed *parsed)
-{
- if (!parsed->dest_local_ref || !parsed->src_local_ref) {
- LOGP(DNAT, LOGL_ERROR, "CC MSG should contain both local and dest address.\n");
- return -1;
- }
-
- sccp->remote_ref = *parsed->src_local_ref;
- sccp->has_remote_ref = 1;
- LOGP(DNAT, LOGL_DEBUG, "Updating 0x%x to remote 0x%x on %p\n",
- sccp_src_ref_to_int(&sccp->patched_ref),
- sccp_src_ref_to_int(&sccp->remote_ref), sccp->bsc);
-
- return 0;
-}
-
-void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed)
-{
- struct nat_sccp_connection *conn;
-
- llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) {
- if (equal(parsed->src_local_ref, &conn->patched_ref)) {
- sccp_connection_destroy(conn);
- return;
- }
- }
-
- LOGP(DNAT, LOGL_ERROR, "Can not remove connection: 0x%x\n",
- sccp_src_ref_to_int(parsed->src_local_ref));
-}
-
-/*
- * We have a message from the MSC to the BSC. The MSC is using
- * an address that was assigned by the MUX, we need to update the
- * dest reference to the real network.
- */
-struct nat_sccp_connection *patch_sccp_src_ref_to_bsc(struct msgb *msg,
- struct bsc_nat_parsed *parsed,
- struct bsc_nat *nat)
-{
- struct nat_sccp_connection *conn;
-
- if (!parsed->dest_local_ref) {
- LOGP(DNAT, LOGL_ERROR, "MSG should contain dest_local_ref.\n");
- return NULL;
- }
-
-
- llist_for_each_entry(conn, &nat->sccp_connections, list_entry) {
- if (!equal(parsed->dest_local_ref, &conn->patched_ref))
- continue;
-
- /* Change the dest address to the real one */
- *parsed->dest_local_ref = conn->real_ref;
- return conn;
- }
-
- return NULL;
-}
-
-/*
- * These are message to the MSC. We will need to find the BSC
- * Connection by either the SRC or the DST local reference.
- *
- * In case of a CR we need to work by the SRC local reference
- * in all other cases we need to work by the destination local
- * reference..
- */
-struct nat_sccp_connection *patch_sccp_src_ref_to_msc(struct msgb *msg,
- struct bsc_nat_parsed *parsed,
- struct bsc_connection *bsc)
-{
- struct nat_sccp_connection *conn;
-
- llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) {
- if (conn->bsc != bsc)
- continue;
-
- if (parsed->src_local_ref) {
- if (equal(parsed->src_local_ref, &conn->real_ref)) {
- *parsed->src_local_ref = conn->patched_ref;
- return conn;
- }
- } else if (parsed->dest_local_ref) {
- if (equal(parsed->dest_local_ref, &conn->remote_ref))
- return conn;
- } else {
- LOGP(DNAT, LOGL_ERROR, "Header has neither loc/dst ref.\n");
- return NULL;
- }
- }
-
- return NULL;
-}
-
-struct nat_sccp_connection *bsc_nat_find_con_by_bsc(struct bsc_nat *nat,
- struct sccp_source_reference *ref)
-{
- struct nat_sccp_connection *conn;
-
- llist_for_each_entry(conn, &nat->sccp_connections, list_entry) {
- if (equal(ref, &conn->real_ref))
- return conn;
- }
-
- return NULL;
-}
diff --git a/src/osmo-bsc_nat/bsc_ussd.c b/src/osmo-bsc_nat/bsc_ussd.c
deleted file mode 100644
index 9769bbd39..000000000
--- a/src/osmo-bsc_nat/bsc_ussd.c
+++ /dev/null
@@ -1,454 +0,0 @@
-/* USSD Filter Code */
-
-/*
- * (C) 2010-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010-2011 by On-Waves
- * 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 <openbsc/bsc_nat.h>
-#include <openbsc/bsc_nat_sccp.h>
-#include <openbsc/bsc_msg_filter.h>
-#include <openbsc/ipaccess.h>
-#include <openbsc/socket.h>
-#include <openbsc/debug.h>
-
-#include <osmocom/gsm/protocol/gsm_08_08.h>
-#include <osmocom/gsm/gsm0480.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/gsm/tlv.h>
-#include <osmocom/gsm/ipa.h>
-
-#include <osmocom/sccp/sccp.h>
-
-#include <osmocom/abis/ipa.h>
-
-#include <sys/socket.h>
-#include <string.h>
-#include <unistd.h>
-
-#define USSD_LAC_IE 0
-#define USSD_CI_IE 1
-
-static void ussd_auth_con(struct tlv_parsed *, struct bsc_nat_ussd_con *);
-
-static struct bsc_nat_ussd_con *bsc_nat_ussd_alloc(struct bsc_nat *nat)
-{
- struct bsc_nat_ussd_con *con;
-
- con = talloc_zero(nat, struct bsc_nat_ussd_con);
- if (!con)
- return NULL;
-
- con->nat = nat;
- return con;
-}
-
-static void bsc_nat_ussd_destroy(struct bsc_nat_ussd_con *con)
-{
- if (con->nat->ussd_con == con) {
- bsc_ussd_close_connections(con->nat);
- con->nat->ussd_con = NULL;
- }
-
- close(con->queue.bfd.fd);
- osmo_fd_unregister(&con->queue.bfd);
- osmo_timer_del(&con->auth_timeout);
- osmo_wqueue_clear(&con->queue);
-
- msgb_free(con->pending_msg);
- talloc_free(con);
-}
-
-static void ussd_pong(struct bsc_nat_ussd_con *conn)
-{
- struct msgb *msg;
-
- msg = msgb_alloc_headroom(4096, 128, "pong message");
- if (!msg) {
- LOGP(DNAT, LOGL_ERROR, "Failed to allocate pong msg\n");
- return;
- }
-
- msgb_v_put(msg, IPAC_MSGT_PONG);
- bsc_do_write(&conn->queue, msg, IPAC_PROTO_IPACCESS);
-}
-
-static int forward_sccp(struct bsc_nat *nat, struct msgb *msg)
-{
- struct nat_sccp_connection *con;
- struct bsc_nat_parsed *parsed;
-
-
- parsed = bsc_nat_parse(msg);
- if (!parsed) {
- LOGP(DNAT, LOGL_ERROR, "Can not parse msg from USSD.\n");
- msgb_free(msg);
- return -1;
- }
-
- if (!parsed->dest_local_ref) {
- LOGP(DNAT, LOGL_ERROR, "No destination local reference.\n");
- msgb_free(msg);
- return -1;
- }
-
- con = bsc_nat_find_con_by_bsc(nat, parsed->dest_local_ref);
- if (!con || !con->bsc) {
- LOGP(DNAT, LOGL_ERROR, "No active connection found.\n");
- msgb_free(msg);
- return -1;
- }
-
- talloc_free(parsed);
- bsc_write_msg(&con->bsc->write_queue, msg);
- return 0;
-}
-
-static int ussd_read_cb(struct osmo_fd *bfd)
-{
- struct bsc_nat_ussd_con *conn = bfd->data;
- struct msgb *msg = NULL;
- struct ipaccess_head *hh;
- int ret;
-
- ret = ipa_msg_recv_buffered(bfd->fd, &msg, &conn->pending_msg);
- if (ret <= 0) {
- if (ret == -EAGAIN)
- return 0;
- LOGP(DNAT, LOGL_ERROR, "USSD Connection was lost.\n");
- bsc_nat_ussd_destroy(conn);
- return -1;
- }
-
- LOGP(DNAT, LOGL_NOTICE, "MSG from USSD: %s proto: %d\n",
- osmo_hexdump(msg->data, msg->len), msg->l2h[0]);
- hh = (struct ipaccess_head *) msg->data;
-
- if (hh->proto == IPAC_PROTO_IPACCESS) {
- if (msg->l2h[0] == IPAC_MSGT_ID_RESP) {
- struct tlv_parsed tvp;
- int ret;
- ret = ipa_ccm_idtag_parse(&tvp,
- (unsigned char *) msg->l2h + 2,
- msgb_l2len(msg) - 2);
- if (ret < 0) {
- LOGP(DNAT, LOGL_ERROR, "ignoring IPA response "
- "message with malformed TLVs\n");
- msgb_free(msg);
- return ret;
- }
- if (TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME))
- ussd_auth_con(&tvp, conn);
- } else if (msg->l2h[0] == IPAC_MSGT_PING) {
- LOGP(DNAT, LOGL_DEBUG, "Got USSD ping request.\n");
- ussd_pong(conn);
- } else {
- LOGP(DNAT, LOGL_NOTICE, "Got unknown IPACCESS message 0x%02x.\n", msg->l2h[0]);
- }
-
- msgb_free(msg);
- } else if (hh->proto == IPAC_PROTO_SCCP) {
- forward_sccp(conn->nat, msg);
- } else {
- msgb_free(msg);
- }
-
- return 0;
-}
-
-static void ussd_auth_cb(void *_data)
-{
- LOGP(DNAT, LOGL_ERROR, "USSD module didn't authenticate\n");
- bsc_nat_ussd_destroy((struct bsc_nat_ussd_con *) _data);
-}
-
-static void ussd_auth_con(struct tlv_parsed *tvp, struct bsc_nat_ussd_con *conn)
-{
- const char *token;
- int len;
- if (!conn->nat->ussd_token) {
- LOGP(DNAT, LOGL_ERROR, "No USSD token set. Closing\n");
- bsc_nat_ussd_destroy(conn);
- return;
- }
-
- token = (const char *) TLVP_VAL(tvp, IPAC_IDTAG_UNITNAME);
- len = TLVP_LEN(tvp, IPAC_IDTAG_UNITNAME);
-
- /* last byte should be a NULL */
- if (strlen(conn->nat->ussd_token) != len - 1)
- goto disconnect;
- /* compare everything including the null byte */
- if (memcmp(conn->nat->ussd_token, token, len) != 0)
- goto disconnect;
-
- /* it is authenticated now */
- if (conn->nat->ussd_con && conn->nat->ussd_con != conn)
- bsc_nat_ussd_destroy(conn->nat->ussd_con);
-
- LOGP(DNAT, LOGL_ERROR, "USSD token specified. USSD provider is connected.\n");
- osmo_timer_del(&conn->auth_timeout);
- conn->authorized = 1;
- conn->nat->ussd_con = conn;
- return;
-
-disconnect:
- LOGP(DNAT, LOGL_ERROR, "Wrong USSD token by client: %d\n",
- conn->queue.bfd.fd);
- bsc_nat_ussd_destroy(conn);
-}
-
-static void ussd_start_auth(struct bsc_nat_ussd_con *conn)
-{
- struct msgb *msg;
-
- osmo_timer_setup(&conn->auth_timeout, ussd_auth_cb, conn);
- osmo_timer_schedule(&conn->auth_timeout, conn->nat->auth_timeout, 0);
-
- msg = msgb_alloc_headroom(4096, 128, "auth message");
- if (!msg) {
- LOGP(DNAT, LOGL_ERROR, "Failed to allocate auth msg\n");
- return;
- }
-
- msgb_v_put(msg, IPAC_MSGT_ID_GET);
- bsc_do_write(&conn->queue, msg, IPAC_PROTO_IPACCESS);
-}
-
-static int ussd_listen_cb(struct osmo_fd *bfd, unsigned int what)
-{
- struct bsc_nat_ussd_con *conn;
- struct bsc_nat *nat;
- struct sockaddr_in sa;
- socklen_t sa_len = sizeof(sa);
- int fd;
-
- if (!(what & BSC_FD_READ))
- return 0;
-
- fd = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len);
- if (fd < 0) {
- perror("accept");
- return fd;
- }
-
- nat = (struct bsc_nat *) bfd->data;
- osmo_counter_inc(nat->stats.ussd.reconn);
-
- conn = bsc_nat_ussd_alloc(nat);
- if (!conn) {
- LOGP(DNAT, LOGL_ERROR, "Failed to allocate USSD con struct.\n");
- close(fd);
- return -1;
- }
-
- osmo_wqueue_init(&conn->queue, 10);
- conn->queue.bfd.data = conn;
- conn->queue.bfd.fd = fd;
- conn->queue.bfd.when = BSC_FD_READ;
- conn->queue.read_cb = ussd_read_cb;
- conn->queue.write_cb = bsc_write_cb;
-
- if (osmo_fd_register(&conn->queue.bfd) < 0) {
- LOGP(DNAT, LOGL_ERROR, "Failed to register USSD fd.\n");
- bsc_nat_ussd_destroy(conn);
- return -1;
- }
-
- LOGP(DNAT, LOGL_NOTICE, "USSD Connection on %d with IP: %s\n",
- fd, inet_ntoa(sa.sin_addr));
-
- /* do authentication */
- ussd_start_auth(conn);
- return 0;
-}
-
-int bsc_ussd_init(struct bsc_nat *nat)
-{
- struct in_addr addr;
-
- addr.s_addr = INADDR_ANY;
- if (nat->ussd_local)
- inet_aton(nat->ussd_local, &addr);
-
- nat->ussd_listen.data = nat;
- return make_sock(&nat->ussd_listen, IPPROTO_TCP,
- ntohl(addr.s_addr), 5001, 0, ussd_listen_cb, nat);
-}
-
-static int forward_ussd_simple(struct nat_sccp_connection *con, struct msgb *input)
-{
- struct msgb *copy;
- struct bsc_nat_ussd_con *ussd;
-
- if (!con->bsc->nat->ussd_con)
- return -1;
-
- copy = msgb_alloc_headroom(4096, 128, "forward bts");
- if (!copy) {
- LOGP(DNAT, LOGL_ERROR, "Allocation failed, not forwarding.\n");
- return -1;
- }
-
- /* copy the data into the copy */
- copy->l2h = msgb_put(copy, msgb_l2len(input));
- memcpy(copy->l2h, input->l2h, msgb_l2len(input));
-
- /* send it out */
- ussd = con->bsc->nat->ussd_con;
- bsc_do_write(&ussd->queue, copy, IPAC_PROTO_SCCP);
- return 0;
-}
-
-static int forward_ussd(struct nat_sccp_connection *con, const struct ussd_request *req,
- struct msgb *input)
-{
- struct msgb *msg, *copy;
- struct ipac_msgt_sccp_state *state;
- struct bsc_nat_ussd_con *ussd;
- uint16_t lac, ci;
-
- if (!con->bsc->nat->ussd_con)
- return -1;
-
- msg = msgb_alloc_headroom(4096, 128, "forward ussd");
- if (!msg) {
- LOGP(DNAT, LOGL_ERROR, "Allocation failed, not forwarding.\n");
- return -1;
- }
-
- copy = msgb_alloc_headroom(4096, 128, "forward bts");
- if (!copy) {
- LOGP(DNAT, LOGL_ERROR, "Allocation failed, not forwarding.\n");
- msgb_free(msg);
- return -1;
- }
-
- copy->l2h = msgb_put(copy, msgb_l2len(input));
- memcpy(copy->l2h, input->l2h, msgb_l2len(input));
-
- msg->l2h = msgb_put(msg, 1);
- msg->l2h[0] = IPAC_MSGT_SCCP_OLD;
-
- /* fill out the data */
- state = (struct ipac_msgt_sccp_state *) msgb_put(msg, sizeof(*state));
- state->trans_id = req->transaction_id;
- state->invoke_id = req->invoke_id;
- memcpy(&state->src_ref, &con->remote_ref, sizeof(con->remote_ref));
- memcpy(&state->dst_ref, &con->real_ref, sizeof(con->real_ref));
- memcpy(state->imsi, con->filter_state.imsi, strlen(con->filter_state.imsi));
-
- /* add additional tag/values */
- lac = htons(con->lac);
- ci = htons(con->ci);
- msgb_tv_fixed_put(msg, USSD_LAC_IE, sizeof(lac), (const uint8_t *) &lac);
- msgb_tv_fixed_put(msg, USSD_CI_IE, sizeof(ci), (const uint8_t *) &ci);
-
- ussd = con->bsc->nat->ussd_con;
- bsc_do_write(&ussd->queue, msg, IPAC_PROTO_IPACCESS);
- bsc_do_write(&ussd->queue, copy, IPAC_PROTO_SCCP);
-
- return 0;
-}
-
-int bsc_ussd_check(struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed,
- struct msgb *msg)
-{
- uint32_t len;
- uint8_t msg_type;
- uint8_t proto;
- uint8_t ti;
- struct gsm48_hdr *hdr48;
- struct bsc_msg_acc_lst *lst;
- struct ussd_request req;
-
- /*
- * various checks to avoid the decoding work. Right now we only want to
- * decode if the connection was created for USSD, we do have a USSD access
- * list, a query, a IMSI and such...
- */
- if (con->filter_state.con_type != FLT_CON_TYPE_SSA)
- return 0;
-
- if (!con->filter_state.imsi)
- return 0;
-
- /* We have not verified the IMSI yet */
- if (!con->authorized)
- return 0;
-
- if (!con->bsc->nat->ussd_lst_name)
- return 0;
- if (!con->bsc->nat->ussd_query)
- return 0;
-
- if (parsed->bssap != BSSAP_MSG_DTAP)
- return 0;
-
- if (strlen(con->filter_state.imsi) > GSM23003_IMSI_MAX_DIGITS)
- return 0;
-
- hdr48 = bsc_unpack_dtap(parsed, msg, &len);
- if (!hdr48)
- return 0;
-
- proto = gsm48_hdr_pdisc(hdr48);
- msg_type = gsm48_hdr_msg_type(hdr48);
- ti = gsm48_hdr_trans_id_no_ti(hdr48);
- if (proto != GSM48_PDISC_NC_SS)
- return 0;
-
- if (msg_type == GSM0480_MTYPE_REGISTER) {
-
- /* now check if it is a IMSI we care about */
- lst = bsc_msg_acc_lst_find(&con->bsc->nat->access_lists,
- con->bsc->nat->ussd_lst_name);
- if (!lst)
- return 0;
-
- if (bsc_msg_acc_lst_check_allow(lst, con->filter_state.imsi) != 0)
- return 0;
-
- /* now decode the message and see if we really want to handle it */
- memset(&req, 0, sizeof(req));
- if (gsm0480_decode_ussd_request(hdr48, len, &req) != 1)
- return 0;
- if (req.text[0] == 0xff)
- return 0;
-
- if (regexec(&con->bsc->nat->ussd_query_re,
- req.text, 0, NULL, 0) == REG_NOMATCH)
- return 0;
-
- /* found a USSD query for our subscriber */
- LOGP(DNAT, LOGL_NOTICE, "Found USSD query for %s\n",
- con->filter_state.imsi);
- con->ussd_ti[ti] = 1;
- if (forward_ussd(con, &req, msg) != 0)
- return 0;
- return 1;
- } else if (msg_type == GSM0480_MTYPE_FACILITY && con->ussd_ti[ti]) {
- LOGP(DNAT, LOGL_NOTICE, "Forwarding message part of TI: %d %s\n",
- ti, con->filter_state.imsi);
- if (forward_ussd_simple(con, msg) != 0)
- return 0;
- return 1;
- }
-
- return 0;
-}