aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 353cf0809..6ef1f5971 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 70f7509c3..7bba41342 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 20ddec27e..b047c3b05 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 d9fceaf8f..1e51737f1 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 4ef2d551b..90c8499bf 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 4666c3b23..8623123f7 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 */