patching: Add a VTY option to hardcode the assignment complete message

For some equipment it is the easiest to patch the assignment
complete message transported to the MSC. Add a VTY config to
enable this patching, create a testcase that tests that the
original message is truncated. The setting of the VTY option
has been manually tested. The entire system has not been end
to end tested.
diff --git a/include/ss7_application.h b/include/ss7_application.h
index 3d25165..b762cac 100644
--- a/include/ss7_application.h
+++ b/include/ss7_application.h
@@ -81,6 +81,13 @@
 	/* mgcp handling for the cellmgr and stp */
 	char *mgcp_domain_name;
 	char *trunk_name;
+
+	/* various hacks/quirks to deal with broken equipment */
+	/*
+	 * Some equipments do not look into the codec list but only the
+	 * size of it.
+	 */
+	unsigned fixed_ass_cmpl_reply : 1;
 };
 
 
diff --git a/src/bss_patch.c b/src/bss_patch.c
index cc897b6..e0a6362 100644
--- a/src/bss_patch.c
+++ b/src/bss_patch.c
@@ -1,7 +1,7 @@
 /* Patch GSM 08.08 messages for the network and BS */
 /*
- * (C) 2010-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010-2011 by On-Waves
+ * (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
@@ -21,6 +21,7 @@
 
 #include <bss_patch.h>
 #include <cellmgr_debug.h>
+#include <ss7_application.h>
 
 #include <string.h>
 
@@ -71,7 +72,14 @@
 	struct tlv_parsed tp;
 	uint8_t *data;
 
-	if (length == 1) {
+	if (length == 1 || app->fixed_ass_cmpl_reply) {
+		/* We need to truncate the message to only include the codec */
+		if (length > 1 && app->fixed_ass_cmpl_reply) {
+			uint8_t *old = msg->tail;
+			msg->tail = &msg->l3h[1];
+			msg->len = old - msg->tail;
+		}
+
 		LOGP(DMSC, LOGL_ERROR, "Hacking the Assignment Complete.\n");
 		msgb_v_put(msg, 0x21);
 		msgb_v_put(msg, 0x09);
diff --git a/src/vty_interface.c b/src/vty_interface.c
index 09b796e..93ebc6a 100644
--- a/src/vty_interface.c
+++ b/src/vty_interface.c
@@ -1,7 +1,7 @@
 /* VTY code for the osmo-stp */
 /*
- * (C) 2010-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010-2012 by On-Waves
+ * (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
@@ -298,6 +298,9 @@
 	vty_out(vty, "  description %s%s", name, VTY_NEWLINE);
 	vty_out(vty, "  type %s%s", app_type(app->type), VTY_NEWLINE);
 
+	if (app->fixed_ass_cmpl_reply)
+		vty_out(vty, "  hardcode-assignment-complete%s", VTY_NEWLINE);
+
 	if (app->type == APP_STP) {
 		vty_out(vty, "  isup-pass-through %d%s", app->isup_pass, VTY_NEWLINE);
 		if (app->trunk_name)
@@ -1077,6 +1080,24 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_app_hardcode_ass, cfg_app_hardcode_ass_cmd,
+      "hardcode-assignment-complete",
+      "Hardcode the assignment complete message to HR3\n")
+{
+	struct ss7_application *app = vty->index;
+	app->fixed_ass_cmpl_reply = 1;
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_app_no_hardcode_ass, cfg_app_no_hardcode_ass_cmd,
+      "no hardcode-assignment-complete",
+      "Hardcode the assignment complete message to HR3\n")
+{
+	struct ss7_application *app = vty->index;
+	app->fixed_ass_cmpl_reply = 0;
+	return CMD_SUCCESS;
+}
+
 static void install_defaults(int node)
 {
 	install_default(node);
@@ -1156,6 +1177,8 @@
 	install_element(APP_NODE, &cfg_app_no_trunk_name_cmd);
 	install_element(APP_NODE, &cfg_app_forward_only_cmd);
 	install_element(APP_NODE, &cfg_app_no_forward_only_cmd);
+	install_element(APP_NODE, &cfg_app_hardcode_ass_cmd);
+	install_element(APP_NODE, &cfg_app_no_hardcode_ass_cmd);
 
 	cell_vty_init_cmds();
 }
diff --git a/tests/patching/patching_test.c b/tests/patching/patching_test.c
index e97d568..9208788 100644
--- a/tests/patching/patching_test.c
+++ b/tests/patching/patching_test.c
@@ -170,6 +170,11 @@
 	0x03, 0x02, 0x40, 0x25,
 };
 
+static const uint8_t dt1_ass_compl_hardcoded[] = {
+	0x06, 0x01, 0x02, 0x47, 0x00, 0x01, 0x09, 0x00,
+	0x07, 0x02, 0x21, 0x09, 0x2c, 0x02, 0x40, 0x25,
+};
+
 static struct result rewrite_results_to_msc[] = {
 	{
 		.input = udt_with_poi,
@@ -327,6 +332,58 @@
 	}
 }
 
+static void test_rewrite_msc_fixed_ass_cmpl(void)
+{
+	struct sccp_parse_result result;
+	struct msgb *inp;
+	struct msgb *outp;
+	int rc;
+
+	struct ss7_application app;
+	memset(&app, 0, sizeof(app));
+	app.fixed_ass_cmpl_reply = 1;
+
+	printf("Testing fixed response\n");
+
+	outp = msgb_alloc_headroom(256, 8, "test2");
+	inp = msgb_alloc_headroom(256, 8, "test1");
+	msgb_put(inp, 1);
+	inp->l2h = msgb_put(inp, sizeof(dt1_ass_compl));
+	memcpy(inp->l2h, dt1_ass_compl, msgb_l2len(inp));
+
+	rc = bss_patch_filter_msg(&app, inp, &result, BSS_DIR_MSC);
+	if (rc < 0) {
+		printf("Failed to parse header msg\n");
+		abort();
+	}
+
+	bss_rewrite_header_for_msc(rc, outp, inp, &result);
+
+	memset(&result, 0, sizeof(result));
+	rc = bss_patch_filter_msg(&app, outp, &result, BSS_DIR_MSC);
+	if (rc < 0) {
+		printf("Patched message doesn't work\n");
+		printf("hex: %s\n", osmo_hexdump(outp->l2h, msgb_l2len(outp)));
+		abort();
+	}
+
+	if (msgb_l2len(outp) != sizeof(dt1_ass_compl_hardcoded)) {
+		printf("The length's don't match on %u != %u\n",
+			msgb_l2len(outp), sizeof(dt1_ass_compl_hardcoded));
+		printf("hex: %s\n", osmo_hexdump(outp->l2h, msgb_l2len(outp)));
+		abort();
+	}
+
+	if (memcmp(outp->l2h, dt1_ass_compl_hardcoded, msgb_l2len(outp)) != 0) {
+		printf("Expected results don't match\n");
+		printf("hex: %s\n", osmo_hexdump(outp->l2h, msgb_l2len(outp)));
+		abort();
+	}
+
+	msgb_free(outp);
+	msgb_free(inp);
+}
+
 static void test_rewrite_bsc(void)
 {
 	int i;
@@ -361,6 +418,7 @@
 
 	test_patch_filter();
 	test_rewrite_msc();
+	test_rewrite_msc_fixed_ass_cmpl();
 	test_rewrite_bsc();
 	printf("All tests passed.\n");
 	return 0;
diff --git a/tests/patching/patching_test.ok b/tests/patching/patching_test.ok
index 0e681b2..498d268 100644
--- a/tests/patching/patching_test.ok
+++ b/tests/patching/patching_test.ok
@@ -1,4 +1,5 @@
 Testing patching of GSM messages to the MSC.
 Testing rewriting the SCCP header.
+Testing fixed response
 Testing rewriting the SCCP header for BSC.
 All tests passed.