aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2010-04-01 10:16:28 +0200
committerHolger Hans Peter Freyther <zecke@selfish.org>2010-04-01 10:16:28 +0200
commit8aaec620da62e27fb9c1e5c1768e2b5d8574e707 (patch)
treea6006886812dff382fdc646fd19118bbfccd87cb
parenta5a4014d67a5eae045541681b94359eb4bf0bd18 (diff)
nat: Return MGCP messages to the call agent
Attempt to find the message by transaction id, then patch the response and use the IP/PORT of the local network, update the ci with the one from the BSC. This is currently not tracking any state of the MGCP and will not handle two bsc's... this will need to happen later. With this in we should be feature complete and now enter the mode of making all of this work reliable and fixing thinko's and other bugs.
-rw-r--r--openbsc/include/openbsc/bsc_nat.h4
-rw-r--r--openbsc/src/nat/bsc_mgcp_utils.c79
-rw-r--r--openbsc/src/nat/bsc_nat.c3
-rw-r--r--openbsc/tests/bsc-nat/bsc_nat_test.c30
4 files changed, 116 insertions, 0 deletions
diff --git a/openbsc/include/openbsc/bsc_nat.h b/openbsc/include/openbsc/bsc_nat.h
index e41849652..cb85ce0e4 100644
--- a/openbsc/include/openbsc/bsc_nat.h
+++ b/openbsc/include/openbsc/bsc_nat.h
@@ -200,5 +200,9 @@ int bsc_mgcp_init(struct bsc_nat *nat);
struct bsc_connection *bsc_mgcp_find_con(struct bsc_nat *, int endpoint_number);
struct msgb *bsc_mgcp_rewrite(struct msgb *msg, const char *ip, int port);
+void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg);
+
+int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60]);
+int bsc_mgcp_extract_ci(const char *resp);
#endif
diff --git a/openbsc/src/nat/bsc_mgcp_utils.c b/openbsc/src/nat/bsc_mgcp_utils.c
index 24f66a14f..0899cec8e 100644
--- a/openbsc/src/nat/bsc_mgcp_utils.c
+++ b/openbsc/src/nat/bsc_mgcp_utils.c
@@ -173,6 +173,85 @@ int bsc_mgcp_policy_cb(struct mgcp_config *cfg, int endpoint, int state, const c
return MGCP_POLICY_DEFER;
}
+/*
+ * 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.
+ */
+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->number_endpoints; ++i) {
+ if (bsc->nat->bsc_endpoints[i].bsc != bsc)
+ continue;
+ if (strcmp(transaction_id, bsc->nat->bsc_endpoints[i].transaction_id) != 0)
+ continue;
+
+ endp = &bsc->nat->mgcp_cfg->endpoints[i];
+ bsc_endp = &bsc->nat->bsc_endpoints[i];
+ break;
+ }
+
+ if (!bsc_endp) {
+ LOGP(DMGCP, LOGL_ERROR, "Could not find active endpoint: %s\n", transaction_id);
+ return;
+ }
+
+ /* free some stuff */
+ talloc_free(bsc_endp->transaction_id);
+ bsc_endp->transaction_id = NULL;
+
+ /* make it point to our endpoint */
+ endp->ci = bsc_mgcp_extract_ci((const char *) msg->l2h);
+ output = bsc_mgcp_rewrite(msg, bsc->nat->mgcp_cfg->source_addr, endp->rtp_port);
+ if (!output) {
+ LOGP(DMGCP, LOGL_ERROR, "Failed to rewrite MGCP msg.\n");
+ return;
+ }
+
+ if (write_queue_enqueue(&bsc->nat->mgcp_queue, output) != 0) {
+ LOGP(DMGCP, LOGL_ERROR, "Failed to queue MGCP msg.\n");
+ msgb_free(output);
+ }
+}
+
+int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60])
+{
+ /* we want to parse two strings */
+ return sscanf(str, "%3d %59s\n", code, transaction) != 2;
+}
+
+int bsc_mgcp_extract_ci(const char *str)
+{
+ int ci;
+ char *res = strstr(str, "I: ");
+ if (!res)
+ return CI_UNUSED;
+
+ if (sscanf(res, "I: %d\r\n", &ci) != 1)
+ return CI_UNUSED;
+ return ci;
+}
+
/* we need to replace some strings... */
struct msgb *bsc_mgcp_rewrite(struct msgb *input, const char *ip, int port)
{
diff --git a/openbsc/src/nat/bsc_nat.c b/openbsc/src/nat/bsc_nat.c
index a0115df69..b135bfec6 100644
--- a/openbsc/src/nat/bsc_nat.c
+++ b/openbsc/src/nat/bsc_nat.c
@@ -430,6 +430,9 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
goto exit2;
break;
}
+ } else if (parsed->ipa_proto == NAT_IPAC_PROTO_MGCP) {
+ 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;
diff --git a/openbsc/tests/bsc-nat/bsc_nat_test.c b/openbsc/tests/bsc-nat/bsc_nat_test.c
index c3b86c060..10b876b37 100644
--- a/openbsc/tests/bsc-nat/bsc_nat_test.c
+++ b/openbsc/tests/bsc-nat/bsc_nat_test.c
@@ -456,6 +456,35 @@ static void test_mgcp_rewrite(void)
msgb_free(input);
}
+static void test_mgcp_parse(void)
+{
+ int code, ci;
+ char transaction[60];
+
+ fprintf(stderr, "Test MGCP response parsing.\n");
+
+ if (bsc_mgcp_parse_response(crcx_resp, &code, transaction) != 0) {
+ fprintf(stderr, "Failed to parse CRCX resp.\n");
+ abort();
+ }
+
+ if (code != 200) {
+ fprintf(stderr, "Failed to parse the CODE properly. Got: %d\n", code);
+ abort();
+ }
+
+ if (strcmp(transaction, "23265295") != 0) {
+ fprintf(stderr, "Failed to parse transaction id: '%s'\n", transaction);
+ abort();
+ }
+
+ ci = bsc_mgcp_extract_ci(crcx_resp);
+ if (ci != 1) {
+ fprintf(stderr, "Failed to parse the CI. Got: %d\n", ci);
+ abort();
+ }
+}
+
int main(int argc, char **argv)
{
struct debug_target *stderr_target;
@@ -470,6 +499,7 @@ int main(int argc, char **argv)
test_mgcp_ass_tracking();
test_mgcp_find();
test_mgcp_rewrite();
+ test_mgcp_parse();
return 0;
}