mgcp: Send RTP keepalive dummy packets to net

So far, a single dummy packet has been sent immediately after the
reception of a MDCX message. There is no dedicated keep alive
mechanism (it just worked because the audio from the MS has always
been forwarded to the NAT until the 'mgcp: Set output_enabled flags
based on the MGCP mode' patch).

This patch adds explicit, timer based keep alive handling that can be
enable per trunk. A VTY command 'rtp keep-alive' command is added for
configuration which can be used to set the interval in seconds, to
send a single packet after the reception of a CRCX/MDCX when RTP data
from the net is expected ('once'), or to disable the feature
completely ('no rtp keep-alive'). In 'send-recv' connections, only
the initial packet is sent if enabled (even when an interval has been
configured). The default is 'once'.

Note that this removes the mgcp_change_cb() from mgcp_main.c.

Sponsored-by: On-Waves ehf
diff --git a/openbsc/src/libmgcp/mgcp_vty.c b/openbsc/src/libmgcp/mgcp_vty.c
index 3f1ebeb..408a059 100644
--- a/openbsc/src/libmgcp/mgcp_vty.c
+++ b/openbsc/src/libmgcp/mgcp_vty.c
@@ -32,6 +32,7 @@
 
 #define RTCP_OMIT_STR "Drop RTCP packets in both directions\n"
 #define RTP_PATCH_STR "Modify RTP packet header in both directions\n"
+#define RTP_KEEPALIVE_STR "Send dummy UDP packet to net RTP destination\n"
 
 static struct mgcp_config *g_cfg = NULL;
 
@@ -85,6 +86,14 @@
 			g_cfg->net_ports.range_start, g_cfg->net_ports.range_end, VTY_NEWLINE);
 
 	vty_out(vty, "  rtp ip-dscp %d%s", g_cfg->endp_dscp, VTY_NEWLINE);
+	if (g_cfg->trunk.keepalive_interval == MGCP_KEEPALIVE_ONCE)
+		vty_out(vty, "  rtp keep-alive once%s", VTY_NEWLINE);
+	else if (g_cfg->trunk.keepalive_interval)
+		vty_out(vty, "  rtp keep-alive %d%s",
+			g_cfg->trunk.keepalive_interval, VTY_NEWLINE);
+	else
+		vty_out(vty, "  no rtp keep-alive%s", VTY_NEWLINE);
+
 	if (g_cfg->trunk.omit_rtcp)
 		vty_out(vty, "  rtcp-omit%s", VTY_NEWLINE);
 	else
@@ -511,6 +520,39 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_mgcp_rtp_keepalive,
+      cfg_mgcp_rtp_keepalive_cmd,
+      "rtp keep-alive <1-120>",
+      RTP_STR RTP_KEEPALIVE_STR
+      "Keep alive interval in secs\n"
+      )
+{
+	mgcp_trunk_set_keepalive(&g_cfg->trunk, atoi(argv[0]));
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_rtp_keepalive_once,
+      cfg_mgcp_rtp_keepalive_once_cmd,
+      "rtp keep-alive once",
+      RTP_STR RTP_KEEPALIVE_STR
+      "Send dummy packet only once after CRCX/MDCX\n"
+      )
+{
+	mgcp_trunk_set_keepalive(&g_cfg->trunk, MGCP_KEEPALIVE_ONCE);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_mgcp_no_rtp_keepalive,
+      cfg_mgcp_no_rtp_keepalive_cmd,
+      "no rtp keep-alive",
+      NO_STR RTP_STR RTP_KEEPALIVE_STR
+      )
+{
+	mgcp_trunk_set_keepalive(&g_cfg->trunk, 0);
+	return CMD_SUCCESS;
+}
+
+
 
 #define CALL_AGENT_STR "Callagent information\n"
 DEFUN(cfg_mgcp_agent_addr,
@@ -598,6 +640,15 @@
 			trunk->audio_name, VTY_NEWLINE);
 		vty_out(vty, "  %ssdp audio-payload send-ptime%s",
 			trunk->audio_send_ptime ? "" : "no ", VTY_NEWLINE);
+
+		if (trunk->keepalive_interval == MGCP_KEEPALIVE_ONCE)
+			vty_out(vty, "  rtp keep-alive once%s", VTY_NEWLINE);
+		else if (trunk->keepalive_interval)
+			vty_out(vty, "  rtp keep-alive %d%s",
+				trunk->keepalive_interval, VTY_NEWLINE);
+		else
+			vty_out(vty, "  no rtp keep-alive%s", VTY_NEWLINE);
+
 		vty_out(vty, "  loop %d%s",
 			trunk->audio_loop, VTY_NEWLINE);
 		if (trunk->omit_rtcp)
@@ -780,6 +831,40 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_trunk_rtp_keepalive,
+      cfg_trunk_rtp_keepalive_cmd,
+      "rtp keep-alive <1-120>",
+      RTP_STR RTP_KEEPALIVE_STR
+      "Keep-alive interval in secs\n"
+      )
+{
+	struct mgcp_trunk_config *trunk = vty->index;
+	mgcp_trunk_set_keepalive(trunk, atoi(argv[0]));
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_trunk_rtp_keepalive_once,
+      cfg_trunk_rtp_keepalive_once_cmd,
+      "rtp keep-alive once",
+      RTP_STR RTP_KEEPALIVE_STR
+      "Send dummy packet only once after CRCX/MDCX\n"
+      )
+{
+	struct mgcp_trunk_config *trunk = vty->index;
+	mgcp_trunk_set_keepalive(trunk, MGCP_KEEPALIVE_ONCE);
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_trunk_no_rtp_keepalive,
+      cfg_trunk_no_rtp_keepalive_cmd,
+      "no rtp keep-alive",
+      NO_STR RTP_STR RTP_KEEPALIVE_STR
+      )
+{
+	struct mgcp_trunk_config *trunk = vty->index;
+	mgcp_trunk_set_keepalive(trunk, 0);
+	return CMD_SUCCESS;
+}
 
 DEFUN(loop_endp,
       loop_endp_cmd,
@@ -999,6 +1084,9 @@
 	install_element(MGCP_NODE, &cfg_mgcp_rtp_transcoder_base_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_dscp_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_tos_cmd);
+	install_element(MGCP_NODE, &cfg_mgcp_rtp_keepalive_cmd);
+	install_element(MGCP_NODE, &cfg_mgcp_rtp_keepalive_once_cmd);
+	install_element(MGCP_NODE, &cfg_mgcp_no_rtp_keepalive_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_agent_addr_cmd);
 	install_element(MGCP_NODE, &cfg_mgcp_agent_addr_cmd_old);
 	install_element(MGCP_NODE, &cfg_mgcp_transcoder_cmd);
@@ -1024,6 +1112,9 @@
 	install_element(MGCP_NODE, &cfg_mgcp_trunk_cmd);
 	install_node(&trunk_node, config_write_trunk);
 	vty_install_default(TRUNK_NODE);
+	install_element(TRUNK_NODE, &cfg_trunk_rtp_keepalive_cmd);
+	install_element(TRUNK_NODE, &cfg_trunk_rtp_keepalive_once_cmd);
+	install_element(TRUNK_NODE, &cfg_trunk_no_rtp_keepalive_cmd);
 	install_element(TRUNK_NODE, &cfg_trunk_payload_number_cmd);
 	install_element(TRUNK_NODE, &cfg_trunk_payload_name_cmd);
 	install_element(TRUNK_NODE, &cfg_trunk_payload_number_cmd_old);