From db2d431697609d473de433b7028f81ce499a02c0 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Tue, 3 Dec 2013 14:43:34 +0100 Subject: mgcp/rtp: Add RTP header patch mode configuration This adds datastructures and a VTY frontend to configure the different type of RTP header patching: SSRC and timestamp. Note that timestamp patching is not yet implemented. Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/mgcp.h | 4 + openbsc/include/openbsc/mgcp_internal.h | 10 ++- openbsc/src/libmgcp/mgcp_network.c | 2 +- openbsc/src/libmgcp/mgcp_protocol.c | 21 ++++- openbsc/src/libmgcp/mgcp_vty.c | 145 +++++++++++++++++++++++++++++++- openbsc/tests/mgcp/mgcp_test.c | 6 +- 6 files changed, 181 insertions(+), 7 deletions(-) diff --git a/openbsc/include/openbsc/mgcp.h b/openbsc/include/openbsc/mgcp.h index 4e22e0f5e..8ab52ce1a 100644 --- a/openbsc/include/openbsc/mgcp.h +++ b/openbsc/include/openbsc/mgcp.h @@ -118,6 +118,10 @@ struct mgcp_trunk_config { int omit_rtcp; + /* RTP patching */ + int force_constant_ssrc; /* 0: don't, 1: once */ + int force_constant_timing; + /* spec handling */ int force_realloc; diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h index 0b52c1c06..02e193df2 100644 --- a/openbsc/include/openbsc/mgcp_internal.h +++ b/openbsc/include/openbsc/mgcp_internal.h @@ -83,6 +83,10 @@ struct mgcp_rtp_end { int frames_per_packet; char *fmtp_extra; + /* RTP patching */ + int force_constant_ssrc; + int force_constant_timing; + /* * Each end has a socket... */ @@ -142,9 +146,6 @@ struct mgcp_endpoint { struct mgcp_rtp_state net_state; struct mgcp_rtp_state bts_state; - /* SSRC/seq/ts patching for loop */ - int allow_patch; - /* fields for re-transmission */ char *last_trans; char *last_response; @@ -176,6 +177,9 @@ static inline int endp_back_channel(int endpoint) struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int index); struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index); +void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change, + struct mgcp_rtp_end *rtp); + void mgcp_state_calc_loss(struct mgcp_rtp_state *s, struct mgcp_rtp_end *, uint32_t *expected, int *loss); uint32_t mgcp_state_calc_jitter(struct mgcp_rtp_state *); diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c index 53f1a20e9..367cebd9b 100644 --- a/openbsc/src/libmgcp/mgcp_network.c +++ b/openbsc/src/libmgcp/mgcp_network.c @@ -264,7 +264,7 @@ void mgcp_patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *sta state->seq_offset = (state->out_stream.last_seq + 1) - seq; state->timestamp_offset = (state->out_stream.last_timestamp + tsdelta) - timestamp; - state->patch = endp->allow_patch; + state->patch = rtp_end->force_constant_ssrc; LOGP(DMGCP, LOGL_NOTICE, "The SSRC changed on 0x%x SSRC: %u offset: %d tsdelta: %d " "from %s:%d in %d\n", diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c index a0b905de0..c703bec13 100644 --- a/openbsc/src/libmgcp/mgcp_protocol.c +++ b/openbsc/src/libmgcp/mgcp_protocol.c @@ -614,6 +614,21 @@ static int parse_sdp_data(struct mgcp_rtp_end *rtp, struct mgcp_parse_data *p) return found_media; } +void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change, + struct mgcp_rtp_end *rtp) +{ + struct mgcp_trunk_config *tcfg = endp->tcfg; + + rtp->force_constant_timing = tcfg->force_constant_timing; + rtp->force_constant_ssrc = tcfg->force_constant_ssrc; + + LOGP(DMGCP, LOGL_DEBUG, + "Configuring RTP endpoint: local port %d%s%s\n", + ntohs(rtp->rtp_port), + rtp->force_constant_timing ? ", force constant timing" : "", + rtp->force_constant_ssrc ? ", force constant ssrc" : ""); +} + static struct msgb *handle_create_con(struct mgcp_parse_data *p) { struct mgcp_trunk_config *tcfg; @@ -688,6 +703,8 @@ mgcp_header_done: /* initialize */ endp->net_end.rtp_port = endp->net_end.rtcp_port = endp->bts_end.rtp_port = endp->bts_end.rtcp_port = 0; + mgcp_rtp_end_config(endp, 0, &endp->net_end); + mgcp_rtp_end_config(endp, 0, &endp->bts_end); /* set to zero until we get the info */ memset(&endp->net_end.addr, 0, sizeof(endp->net_end.addr)); @@ -825,6 +842,9 @@ static struct msgb *handle_modify_con(struct mgcp_parse_data *p) } } + mgcp_rtp_end_config(endp, 1, &endp->net_end); + mgcp_rtp_end_config(endp, 1, &endp->bts_end); + /* modify */ LOGP(DMGCP, LOGL_DEBUG, "Modified endpoint on: 0x%x Server: %s:%u\n", ENDPOINT_NUMBER(endp), inet_ntoa(endp->net_end.addr), ntohs(endp->net_end.rtp_port)); @@ -1121,7 +1141,6 @@ void mgcp_free_endp(struct mgcp_endpoint *endp) memset(&endp->bts_state, 0, sizeof(endp->bts_state)); endp->conn_mode = endp->orig_mode = MGCP_CONN_NONE; - endp->allow_patch = 0; memset(&endp->taps, 0, sizeof(endp->taps)); } diff --git a/openbsc/src/libmgcp/mgcp_vty.c b/openbsc/src/libmgcp/mgcp_vty.c index 5aeb3930e..e48b0503e 100644 --- a/openbsc/src/libmgcp/mgcp_vty.c +++ b/openbsc/src/libmgcp/mgcp_vty.c @@ -31,6 +31,7 @@ #include #define RTCP_OMIT_STR "Drop RTCP packets in both directions\n" +#define RTP_PATCH_STR "Modify RTP packet header in both directions\n" static struct mgcp_config *g_cfg = NULL; @@ -88,6 +89,13 @@ static int config_write_mgcp(struct vty *vty) vty_out(vty, " rtcp-omit%s", VTY_NEWLINE); else vty_out(vty, " no rtcp-omit%s", VTY_NEWLINE); + if (g_cfg->trunk.force_constant_ssrc || g_cfg->trunk.force_constant_timing) { + vty_out(vty, " %srtp-patch ssrc%s", + g_cfg->trunk.force_constant_ssrc ? "" : "no ", VTY_NEWLINE); + vty_out(vty, " %srtp-patch timestamp%s", + g_cfg->trunk.force_constant_timing ? "" : "no ", VTY_NEWLINE); + } else + vty_out(vty, " no rtp-patch%s", VTY_NEWLINE); if (g_cfg->trunk.audio_payload != -1) vty_out(vty, " sdp audio-payload number %d%s", g_cfg->trunk.audio_payload, VTY_NEWLINE); @@ -421,6 +429,61 @@ DEFUN(cfg_mgcp_no_omit_rtcp, return CMD_SUCCESS; } +DEFUN(cfg_mgcp_patch_rtp_ssrc, + cfg_mgcp_patch_rtp_ssrc_cmd, + "rtp-patch ssrc", + RTP_PATCH_STR + "Force a fixed SSRC\n" + ) +{ + g_cfg->trunk.force_constant_ssrc = 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_no_patch_rtp_ssrc, + cfg_mgcp_no_patch_rtp_ssrc_cmd, + "no rtp-patch ssrc", + NO_STR RTP_PATCH_STR + "Force a fixed SSRC\n" + ) +{ + g_cfg->trunk.force_constant_ssrc = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_patch_rtp_ts, + cfg_mgcp_patch_rtp_ts_cmd, + "rtp-patch timestamp", + RTP_PATCH_STR + "Adjust RTP timestamp\n" + ) +{ + g_cfg->trunk.force_constant_timing = 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_no_patch_rtp_ts, + cfg_mgcp_no_patch_rtp_ts_cmd, + "no rtp-patch timestamp", + NO_STR RTP_PATCH_STR + "Adjust RTP timestamp\n" + ) +{ + g_cfg->trunk.force_constant_timing = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_mgcp_no_patch_rtp, + cfg_mgcp_no_patch_rtp_cmd, + "no rtp-patch", + NO_STR RTP_PATCH_STR) +{ + g_cfg->trunk.force_constant_ssrc = 0; + g_cfg->trunk.force_constant_timing = 0; + return CMD_SUCCESS; +} + + #define CALL_AGENT_STR "Callagent information\n" DEFUN(cfg_mgcp_agent_addr, cfg_mgcp_agent_addr_cmd, @@ -511,6 +574,13 @@ static int config_write_trunk(struct vty *vty) vty_out(vty, " rtcp-omit%s", VTY_NEWLINE); else vty_out(vty, " no rtcp-omit%s", VTY_NEWLINE); + if (trunk->force_constant_ssrc || trunk->force_constant_timing) { + vty_out(vty, " %srtp-patch ssrc%s", + trunk->force_constant_ssrc ? "" : "no ", VTY_NEWLINE); + vty_out(vty, " %srtp-patch timestamp%s", + trunk->force_constant_timing ? "" : "no ", VTY_NEWLINE); + } else + vty_out(vty, " no rtp-patch%s", VTY_NEWLINE); if (trunk->audio_fmtp_extra) vty_out(vty, " sdp audio fmtp-extra %s%s", trunk->audio_fmtp_extra, VTY_NEWLINE); @@ -599,6 +669,66 @@ DEFUN(cfg_trunk_no_omit_rtcp, return CMD_SUCCESS; } +DEFUN(cfg_trunk_patch_rtp_ssrc, + cfg_trunk_patch_rtp_ssrc_cmd, + "rtp-patch ssrc", + RTP_PATCH_STR + "Force a fixed SSRC\n" + ) +{ + struct mgcp_trunk_config *trunk = vty->index; + trunk->force_constant_ssrc = 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_trunk_no_patch_rtp_ssrc, + cfg_trunk_no_patch_rtp_ssrc_cmd, + "no rtp-patch ssrc", + NO_STR RTP_PATCH_STR + "Force a fixed SSRC\n" + ) +{ + struct mgcp_trunk_config *trunk = vty->index; + trunk->force_constant_ssrc = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_trunk_patch_rtp_ts, + cfg_trunk_patch_rtp_ts_cmd, + "rtp-patch timestamp", + RTP_PATCH_STR + "Adjust RTP timestamp\n" + ) +{ + struct mgcp_trunk_config *trunk = vty->index; + trunk->force_constant_timing = 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_trunk_no_patch_rtp_ts, + cfg_trunk_no_patch_rtp_ts_cmd, + "no rtp-patch timestamp", + NO_STR RTP_PATCH_STR + "Adjust RTP timestamp\n" + ) +{ + struct mgcp_trunk_config *trunk = vty->index; + trunk->force_constant_timing = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_trunk_no_patch_rtp, + cfg_trunk_no_patch_rtp_cmd, + "no rtp-patch", + NO_STR RTP_PATCH_STR) +{ + struct mgcp_trunk_config *trunk = vty->index; + trunk->force_constant_ssrc = 0; + trunk->force_constant_timing = 0; + return CMD_SUCCESS; +} + + DEFUN(loop_endp, loop_endp_cmd, "loop-endpoint <0-64> NAME (0|1)", @@ -636,7 +766,10 @@ DEFUN(loop_endp, endp->conn_mode = MGCP_CONN_LOOPBACK; else endp->conn_mode = endp->orig_mode; - endp->allow_patch = 1; + + /* Handle it like a MDCX, switch on SSRC patching if enabled */ + mgcp_rtp_end_config(endp, 1, &endp->bts_end); + mgcp_rtp_end_config(endp, 1, &endp->net_end); return CMD_SUCCESS; } @@ -827,6 +960,11 @@ int mgcp_vty_init(void) install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd); install_element(MGCP_NODE, &cfg_mgcp_omit_rtcp_cmd); install_element(MGCP_NODE, &cfg_mgcp_no_omit_rtcp_cmd); + install_element(MGCP_NODE, &cfg_mgcp_patch_rtp_ssrc_cmd); + install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_ssrc_cmd); + install_element(MGCP_NODE, &cfg_mgcp_patch_rtp_ts_cmd); + install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_ts_cmd); + install_element(MGCP_NODE, &cfg_mgcp_no_patch_rtp_cmd); install_element(MGCP_NODE, &cfg_mgcp_sdp_fmtp_extra_cmd); install_element(MGCP_NODE, &cfg_mgcp_trunk_cmd); @@ -839,6 +977,11 @@ int mgcp_vty_init(void) install_element(TRUNK_NODE, &cfg_trunk_loop_cmd); install_element(TRUNK_NODE, &cfg_trunk_omit_rtcp_cmd); install_element(TRUNK_NODE, &cfg_trunk_no_omit_rtcp_cmd); + install_element(TRUNK_NODE, &cfg_trunk_patch_rtp_ssrc_cmd); + install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_ssrc_cmd); + install_element(TRUNK_NODE, &cfg_trunk_patch_rtp_ts_cmd); + install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_ts_cmd); + install_element(TRUNK_NODE, &cfg_trunk_no_patch_rtp_cmd); install_element(TRUNK_NODE, &cfg_trunk_sdp_fmtp_extra_cmd); return 0; diff --git a/openbsc/tests/mgcp/mgcp_test.c b/openbsc/tests/mgcp/mgcp_test.c index 8e130bbd8..908773a69 100644 --- a/openbsc/tests/mgcp/mgcp_test.c +++ b/openbsc/tests/mgcp/mgcp_test.c @@ -558,6 +558,9 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts) trunk.number_endpoints = 1; trunk.endpoints = &endp; + trunk.force_constant_ssrc = patch_ssrc; + trunk.force_constant_timing = patch_ts; + endp.tcfg = &trunk; /* This doesn't free endp but resets/frees all fields of the structure @@ -568,7 +571,6 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts) mgcp_free_endp(&endp); rtp->payload_type = 98; - endp.allow_patch = patch_ssrc; for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) { struct rtp_packet_info *info = test_rtp_packets1 + i; @@ -577,6 +579,8 @@ static void test_packet_error_detection(int patch_ssrc, int patch_ts) OSMO_ASSERT(info->len >= 0); memmove(buffer, info->data, info->len); + mgcp_rtp_end_config(&endp, 1, rtp); + mgcp_patch_and_count(&endp, &state, rtp, &addr, buffer, info->len); -- cgit v1.2.3