aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2010-04-22 12:08:17 +0800
committerHolger Hans Peter Freyther <zecke@selfish.org>2010-04-22 12:13:44 +0800
commitbbc2c6e76548047c7eaa7f5fbb22fd9fe1edde5f (patch)
treed71facf1a759a1ce4656b1ae49501bca38c9b3b3
parent7e3724ad18119967cd0fbaaee601d3e0d06e5ad4 (diff)
nat: Change MGCP DLCX handling and send dummy MDCX to the BTS.
When setting a new MSC timeslot to a SCCP connection check if any of the existing connections have this timeslot, if so we will send a DLCX down the stream to make sure it is closed there, when we will CRCX this new timeslot we will happily reallocate it. When the SCCP connection goes away, or we get a DLCX from the network, or the BSC is gone we will send a DLCX message down the stream as well. When we receive a CRCX from the network we will forward the CRCX as usual and send a dummy MDCX after it. For the DLCX and the dummy MDCX we send a custom MGCP message that will not provoke an answer. Even if the downstream MGCP GW will answer we will ignore it due the dummy transaction id that is not used anywhere else. This change should make sure that we close the dowstream endpoint all the time, even when the DLCX arrives after the SCCP connection is torndown.
-rw-r--r--openbsc/include/openbsc/bsc_nat.h8
-rw-r--r--openbsc/src/nat/bsc_mgcp_utils.c125
-rw-r--r--openbsc/src/nat/bsc_nat.c2
-rw-r--r--openbsc/src/nat/bsc_nat_utils.c2
-rw-r--r--openbsc/src/nat/bsc_sccp.c4
-rw-r--r--openbsc/tests/bsc-nat/bsc_nat_test.c14
6 files changed, 114 insertions, 41 deletions
diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h
index 353cf080..6ef1f597 100644
--- a/openbsc/include/openbsc/bsc_nat.h
+++ b/openbsc/include/openbsc/bsc_nat.h
@@ -162,8 +162,6 @@ struct bsc_endpoint {
char *transaction_id;
/* the bsc we are talking to */
struct bsc_connection *bsc;
- /* pending delete */
- int pending_delete;
};
/**
@@ -257,10 +255,10 @@ struct sccp_connections *patch_sccp_src_ref_to_msc(struct msgb *, struct bsc_nat
*/
int bsc_write_mgcp(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length);
int bsc_mgcp_assign(struct sccp_connections *, struct msgb *msg);
-void bsc_mgcp_clear(struct sccp_connections *);
-void bsc_mgcp_free_endpoint(struct bsc_nat *nat, int);
+void bsc_mgcp_init(struct sccp_connections *);
+void bsc_mgcp_dlcx(struct sccp_connections *);
void bsc_mgcp_free_endpoints(struct bsc_nat *nat);
-int bsc_mgcp_init(struct bsc_nat *nat);
+int bsc_mgcp_nat_init(struct bsc_nat *nat);
struct sccp_connections *bsc_mgcp_find_con(struct bsc_nat *, int endpoint_number);
struct msgb *bsc_mgcp_rewrite(char *input, int length, const char *ip, int port);
diff --git a/openbsc/src/nat/bsc_mgcp_utils.c b/openbsc/src/nat/bsc_mgcp_utils.c
index 70f7509c..7bba4134 100644
--- a/openbsc/src/nat/bsc_mgcp_utils.c
+++ b/openbsc/src/nat/bsc_mgcp_utils.c
@@ -26,6 +26,8 @@
#include <openbsc/mgcp.h>
#include <openbsc/mgcp_internal.h>
+#include <sccp/sccp.h>
+
#include <osmocore/talloc.h>
#include <osmocore/gsm0808.h>
@@ -37,10 +39,12 @@
int bsc_mgcp_assign(struct sccp_connections *con, struct msgb *msg)
{
+ struct sccp_connections *mcon;
struct tlv_parsed tp;
u_int16_t cic;
u_int8_t timeslot;
u_int8_t multiplex;
+ int combined;
if (!msg->l3h) {
LOGP(DNAT, LOGL_ERROR, "Assignment message should have l3h pointer.\n");
@@ -62,18 +66,27 @@ int bsc_mgcp_assign(struct sccp_connections *con, struct msgb *msg)
timeslot = cic & 0x1f;
multiplex = (cic & ~0x1f) >> 5;
- con->msc_timeslot = (32 * multiplex) + timeslot;
+
+ combined = (32 * multiplex) + timeslot;
+
+ /* find stale connections using that endpoint */
+ llist_for_each_entry(mcon, &con->bsc->nat->sccp_connections, list_entry) {
+ if (mcon->msc_timeslot == combined) {
+ LOGP(DNAT, LOGL_ERROR,
+ "Timeslot %d was assigned to 0x%x and now 0x%x\n",
+ combined,
+ sccp_src_ref_to_int(&mcon->patched_ref),
+ sccp_src_ref_to_int(&con->patched_ref));
+ bsc_mgcp_dlcx(mcon);
+ }
+ }
+
+ con->msc_timeslot = combined;
con->bsc_timeslot = con->msc_timeslot;
return 0;
}
-void bsc_mgcp_clear(struct sccp_connections *con)
-{
- con->msc_timeslot = -1;
- con->bsc_timeslot = -1;
-}
-
-void bsc_mgcp_free_endpoint(struct bsc_nat *nat, int i)
+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);
@@ -81,17 +94,74 @@ void bsc_mgcp_free_endpoint(struct bsc_nat *nat, int i)
}
nat->bsc_endpoints[i].bsc = NULL;
- mgcp_free_endp(&nat->mgcp_cfg->endpoints[i]);
}
void bsc_mgcp_free_endpoints(struct bsc_nat *nat)
{
int i;
- for (i = 1; i < nat->mgcp_cfg->number_endpoints; ++i)
+ for (i = 1; i < nat->mgcp_cfg->number_endpoints; ++i){
bsc_mgcp_free_endpoint(nat, i);
+ mgcp_free_endp(&nat->mgcp_cfg->endpoints[i]);
+ }
+}
+
+/* send a MDCX where we do not want a response */
+static void bsc_mgcp_send_mdcx(struct bsc_connection *bsc, struct mgcp_endpoint *endp)
+{
+ char buf[2096];
+ int len;
+
+ len = snprintf(buf, sizeof(buf),
+ "MDCX 23 %d@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",
+ ENDPOINT_NUMBER(endp),
+ bsc->nat->mgcp_cfg->source_addr,
+ endp->rtp_port);
+ if (len < 0) {
+ LOGP(DMGCP, LOGL_ERROR, "snprintf for DLCX failed.\n");
+ return;
+ }
+}
+
+static void bsc_mgcp_send_dlcx(struct bsc_connection *bsc, int endpoint)
+{
+ char buf[2096];
+ int len;
+
+ len = snprintf(buf, sizeof(buf),
+ "DLCX 23 %d@mgw MGCP 1.0\r\n"
+ "Z: noanswer\r\n", endpoint);
+ if (len < 0) {
+ LOGP(DMGCP, LOGL_ERROR, "snprintf for DLCX failed.\n");
+ return;
+ }
+
+ bsc_write_mgcp(bsc, (u_int8_t *) buf, len);
+}
+
+void bsc_mgcp_init(struct sccp_connections *con)
+{
+ con->msc_timeslot = -1;
+ con->bsc_timeslot = -1;
+}
+
+void bsc_mgcp_dlcx(struct sccp_connections *con)
+{
+ /* send a DLCX down the stream */
+ if (con->bsc_timeslot != -1) {
+ int endp = mgcp_timeslot_to_endpoint(0, con->msc_timeslot);
+ bsc_mgcp_send_dlcx(con->bsc, endp);
+ bsc_mgcp_free_endpoint(con->bsc->nat, endp);
+ }
+
+ bsc_mgcp_init(con);
}
+
struct sccp_connections *bsc_mgcp_find_con(struct bsc_nat *nat, int endpoint)
{
struct sccp_connections *con = NULL;
@@ -164,7 +234,6 @@ int bsc_mgcp_policy_cb(struct mgcp_config *cfg, int endpoint, int state, const c
bsc_endp->transaction_id = talloc_strdup(nat, transaction_id);
bsc_endp->bsc = sccp->bsc;
- bsc_endp->pending_delete = 0;
/* we need to update some bits */
if (state == MGCP_ENDP_CRCX) {
@@ -176,15 +245,19 @@ int bsc_mgcp_policy_cb(struct mgcp_config *cfg, int endpoint, int state, const c
} else {
mgcp_endp->bts = sock.sin_addr;
}
+
+ /* send the message and a fake MDCX for force sending of a dummy packet */
+ bsc_write(sccp->bsc, bsc_msg, NAT_IPAC_PROTO_MGCP);
+ bsc_mgcp_send_mdcx(sccp->bsc, mgcp_endp);
+ return MGCP_POLICY_DEFER;
} else if (state == MGCP_ENDP_DLCX) {
- /* we will free the endpoint now in case the BSS does not respond */
- bsc_mgcp_clear(sccp);
- bsc_endp->pending_delete = 1;
- mgcp_free_endp(mgcp_endp);
+ /* we will free the endpoint now and send a DLCX to the BSC */
+ bsc_mgcp_dlcx(sccp);
+ return MGCP_POLICY_CONT;
+ } else {
+ bsc_write(sccp->bsc, bsc_msg, NAT_IPAC_PROTO_MGCP);
+ return MGCP_POLICY_DEFER;
}
-
- bsc_write(sccp->bsc, bsc_msg, NAT_IPAC_PROTO_MGCP);
- return MGCP_POLICY_DEFER;
}
/*
@@ -234,13 +307,7 @@ void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg)
return;
}
- /* make it point to our endpoint if it was not deleted */
- if (bsc_endp->pending_delete) {
- bsc_endp->bsc = NULL;
- bsc_endp->pending_delete = 0;
- } else {
- endp->ci = bsc_mgcp_extract_ci((const char *) msg->l2h);
- }
+ endp->ci = bsc_mgcp_extract_ci((const char *) msg->l2h);
/* free some stuff */
talloc_free(bsc_endp->transaction_id);
@@ -401,7 +468,7 @@ static int mgcp_do_write(struct bsc_fd *bfd, struct msgb *msg)
return rc;
}
-int bsc_mgcp_init(struct bsc_nat *nat)
+int bsc_mgcp_nat_init(struct bsc_nat *nat)
{
int on;
struct sockaddr_in addr;
@@ -481,11 +548,7 @@ void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc)
if (bsc_endp->bsc != bsc)
continue;
- bsc_endp->bsc = NULL;
- bsc_endp->pending_delete = 0;
- if (bsc_endp->transaction_id)
- talloc_free(bsc_endp->transaction_id);
- bsc_endp->transaction_id = NULL;
+ bsc_mgcp_free_endpoint(bsc->nat, i);
mgcp_free_endp(&bsc->nat->mgcp_cfg->endpoints[i]);
}
}
diff --git a/openbsc/src/nat/bsc_nat.c b/openbsc/src/nat/bsc_nat.c
index 20ddec27..b047c3b0 100644
--- a/openbsc/src/nat/bsc_nat.c
+++ b/openbsc/src/nat/bsc_nat.c
@@ -861,7 +861,7 @@ int main(int argc, char** argv)
/*
* Setup the MGCP code..
*/
- if (bsc_mgcp_init(nat) != 0)
+ if (bsc_mgcp_nat_init(nat) != 0)
return -4;
/* connect to the MSC */
diff --git a/openbsc/src/nat/bsc_nat_utils.c b/openbsc/src/nat/bsc_nat_utils.c
index d9fceaf8..1e51737f 100644
--- a/openbsc/src/nat/bsc_nat_utils.c
+++ b/openbsc/src/nat/bsc_nat_utils.c
@@ -100,7 +100,7 @@ void sccp_connection_destroy(struct sccp_connections *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_clear(conn);
+ bsc_mgcp_dlcx(conn);
llist_del(&conn->list_entry);
talloc_free(conn);
}
diff --git a/openbsc/src/nat/bsc_sccp.c b/openbsc/src/nat/bsc_sccp.c
index 4ef2d551..90c8499b 100644
--- a/openbsc/src/nat/bsc_sccp.c
+++ b/openbsc/src/nat/bsc_sccp.c
@@ -101,7 +101,7 @@ int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc
talloc_free(conn);
return -1;
} else {
- bsc_mgcp_clear(conn);
+ bsc_mgcp_dlcx(conn);
return 0;
}
}
@@ -121,7 +121,7 @@ int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc
return -1;
}
- bsc_mgcp_clear(conn);
+ bsc_mgcp_init(conn);
llist_add_tail(&conn->list_entry, &bsc->nat->sccp_connections);
counter_inc(bsc->cfg->stats.sccp.conn);
counter_inc(bsc->cfg->nat->stats.sccp.conn);
diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c
index 4666c3b2..8623123f 100644
--- a/openbsc/tests/bsc-nat/bsc_nat_test.c
+++ b/openbsc/tests/bsc-nat/bsc_nat_test.c
@@ -395,6 +395,8 @@ static void test_paging(void)
static void test_mgcp_ass_tracking(void)
{
+ struct bsc_connection *bsc;
+ struct bsc_nat *nat;
struct sccp_connections con;
struct bsc_nat_parsed *parsed;
struct msgb *msg;
@@ -402,6 +404,14 @@ static void test_mgcp_ass_tracking(void)
fprintf(stderr, "Testing MGCP.\n");
memset(&con, 0, sizeof(con));
+ nat = bsc_nat_alloc();
+ nat->bsc_endpoints = talloc_zero_array(nat,
+ struct bsc_endpoint,
+ 33);
+ bsc = bsc_connection_alloc(nat);
+ bsc->cfg = bsc_config_alloc(nat, "foo", 2323);
+ con.bsc = bsc;
+
msg = msgb_alloc(4096, "foo");
copy_to_msg(msg, ass_cmd, sizeof(ass_cmd));
parsed = bsc_nat_parse(msg);
@@ -421,11 +431,13 @@ static void test_mgcp_ass_tracking(void)
}
talloc_free(parsed);
- bsc_mgcp_clear(&con);
+ bsc_mgcp_dlcx(&con);
if (con.bsc_timeslot != -1 || con.msc_timeslot != -1) {
fprintf(stderr, "Clearing should remove the mapping.\n");
abort();
}
+
+ talloc_free(nat);
}
/* test the code to find a given connection */