[PATCH 2/4] mgcp/rtp: Add counter for invalid RTP timestamp deltas

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/OpenBSC@lists.osmocom.org/.

Jacob Erlbeck jerlbeck at sysmocom.de
Thu Nov 21 18:05:43 UTC 2013


This patch modifies the patch_and_count() function to check for RTP
timestamp inconsistencies. It basically checks, whether dTS/dSeqNo
remains constant. If this fails, the corresponding counter is
incremented. There are four counter for this: Incoming and outgoing,
each for streams from the BTS and the net.

Note that this approach presumes, that the per RTP packet duration
(in samples) remains the same throughout the entire stream. Changing
the number of speech frames per channel and packet will be detected
as error.

In addition, the VTY command 'show mgcp' is extended by an optional
'stats' to show the counter values, too.

Ticket: OW#964
Sponsored-by: On-Waves ehf
---
 openbsc/include/openbsc/mgcp_internal.h |    4 ++
 openbsc/src/libmgcp/mgcp_network.c      |   73 +++++++++++++++++++++++++++++--
 openbsc/src/libmgcp/mgcp_protocol.c     |   24 ++++++++--
 openbsc/src/libmgcp/mgcp_vty.c          |   23 +++++++---
 openbsc/tests/mgcp/mgcp_test.c          |    3 +-
 5 files changed, 114 insertions(+), 13 deletions(-)

diff --git a/openbsc/include/openbsc/mgcp_internal.h b/openbsc/include/openbsc/mgcp_internal.h
index d5bd3dd..2ad7058 100644
--- a/openbsc/include/openbsc/mgcp_internal.h
+++ b/openbsc/include/openbsc/mgcp_internal.h
@@ -56,6 +56,10 @@ struct mgcp_rtp_state {
 	int32_t  timestamp_offset;
 	uint32_t jitter;
 	int32_t transit;
+
+	int32_t last_tsdelta;
+	uint32_t err_ts_in_counter;
+	uint32_t err_ts_out_counter;
 };
 
 struct mgcp_rtp_end {
diff --git a/openbsc/src/libmgcp/mgcp_network.c b/openbsc/src/libmgcp/mgcp_network.c
index 2b55527..14bc024 100644
--- a/openbsc/src/libmgcp/mgcp_network.c
+++ b/openbsc/src/libmgcp/mgcp_network.c
@@ -143,13 +143,18 @@ int mgcp_send_dummy(struct mgcp_endpoint *endp)
  * we receive will be seen as a switch in streams.
  */
 static void patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
-			    int payload, struct sockaddr_in *addr, char *data, int len)
+			    struct mgcp_rtp_end *rtp_end, struct sockaddr_in *addr,
+			    char *data, int len)
 {
 	uint32_t arrival_time;
 	int32_t transit, d;
 	uint16_t seq, udelta;
 	uint32_t timestamp;
 	struct rtp_hdr *rtp_hdr;
+	int32_t tsdelta = 0;
+	int tsdelta_valid = 0;
+	int last_tsdelta = state->last_tsdelta;
+	int payload = rtp_end->payload_type;
 
 	if (len < sizeof(*rtp_hdr))
 		return;
@@ -176,6 +181,41 @@ static void patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *s
 			"The SSRC changed on 0x%x SSRC: %u offset: %d from %s:%d in %d\n",
 			ENDPOINT_NUMBER(endp), state->ssrc, state->seq_offset,
 			inet_ntoa(addr->sin_addr), ntohs(addr->sin_port), endp->conn_mode);
+	} else {
+		/* Compute current per-packet timestamp delta */
+		if (state->initialized && seq != state->max_seq) {
+			int corr_timestamp = state->timestamp_offset + timestamp;
+			tsdelta =
+				(int32_t)(corr_timestamp - state->last_timestamp) /
+				(int16_t)(seq - state->max_seq);
+
+			if (tsdelta == 0) {
+				state->err_ts_in_counter += 1;
+				LOGP(DMGCP, LOGL_ERROR,
+				     "Input timestamp delta is %d "
+				     "on 0x%x SSRC: %u timestamp: %u "
+				     "from %s:%d in %d\n",
+				     tsdelta,
+				     ENDPOINT_NUMBER(endp), state->ssrc, timestamp,
+				     inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
+				     endp->conn_mode);
+			} else
+				tsdelta_valid = 1;
+		}
+
+		if (tsdelta_valid && state->last_tsdelta != tsdelta) {
+			if (state->last_tsdelta) {
+				state->err_ts_in_counter += 1;
+				LOGP(DMGCP, LOGL_ERROR,
+				     "Input timestamp delta changes from %d to %d "
+				     "on 0x%x SSRC: %u timestamp: %u from %s:%d in %d\n",
+				     state->last_tsdelta, tsdelta,
+				     ENDPOINT_NUMBER(endp), state->ssrc, timestamp,
+				     inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
+				     endp->conn_mode);
+			}
+			state->last_tsdelta = tsdelta;
+		}
 	}
 
 	/* apply the offset and store it back to the packet */
@@ -188,6 +228,33 @@ static void patch_and_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *s
 		rtp_hdr->timestamp = htonl(timestamp);
 	}
 
+	/* Check again, whether the timestamps are still valid */
+	if (last_tsdelta && seq != state->max_seq) {
+		tsdelta = (timestamp - state->last_timestamp) /
+			(seq - state->max_seq);
+
+		if (tsdelta == 0) {
+			state->err_ts_out_counter += 1;
+			LOGP(DMGCP, LOGL_ERROR,
+			     "Output timestamp delta is %d "
+			     "on 0x%x SSRC: %u timestamp: %u "
+			     "from %s:%d in %d\n",
+			     tsdelta,
+			     ENDPOINT_NUMBER(endp), state->ssrc, timestamp,
+			     inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
+			     endp->conn_mode);
+		} else if (last_tsdelta != tsdelta) {
+			state->err_ts_out_counter += 1;
+			LOGP(DMGCP, LOGL_ERROR,
+			     "Output timestamp delta changes from %d to %d "
+			     "on 0x%x SSRC: %u timestamp: %u from %s:%d in %d\n",
+			     last_tsdelta, tsdelta,
+			     ENDPOINT_NUMBER(endp), state->ssrc, timestamp,
+			     inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
+			     endp->conn_mode);
+		}
+	}
+
 	/*
 	 * The below takes the shape of the validation from Appendix A. Check
 	 * if there is something weird with the sequence number, otherwise check
@@ -280,7 +347,7 @@ static int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp,
 	if (dest == MGCP_DEST_NET) {
 		if (is_rtp) {
 			patch_and_count(endp, &endp->bts_state,
-					endp->net_end.payload_type,
+					&endp->net_end,
 					addr, buf, rc);
 			forward_data(endp->net_end.rtp.fd,
 				     &endp->taps[MGCP_TAP_NET_OUT], buf, rc);
@@ -295,7 +362,7 @@ static int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp,
 	} else {
 		if (is_rtp) {
 			patch_and_count(endp, &endp->net_state,
-					endp->bts_end.payload_type,
+					&endp->bts_end,
 					addr, buf, rc);
 			forward_data(endp->bts_end.rtp.fd,
 				     &endp->taps[MGCP_TAP_BTS_OUT], buf, rc);
diff --git a/openbsc/src/libmgcp/mgcp_protocol.c b/openbsc/src/libmgcp/mgcp_protocol.c
index 616e0a9..b19b8a0 100644
--- a/openbsc/src/libmgcp/mgcp_protocol.c
+++ b/openbsc/src/libmgcp/mgcp_protocol.c
@@ -1163,14 +1163,30 @@ void mgcp_format_stats(struct mgcp_endpoint *endp, char *msg, size_t size)
 {
 	uint32_t expected, jitter;
 	int ploss;
+	int nchars;
 	mgcp_state_calc_loss(&endp->net_state, &endp->net_end,
 				&expected, &ploss);
 	jitter = mgcp_state_calc_jitter(&endp->net_state);
 
-	snprintf(msg, size, "\r\nP: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
-			endp->bts_end.packets, endp->bts_end.octets,
-			endp->net_end.packets, endp->net_end.octets,
-			ploss, jitter);
+	nchars = snprintf(msg, size,
+			  "\r\nP: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
+			  endp->bts_end.packets, endp->bts_end.octets,
+			  endp->net_end.packets, endp->net_end.octets,
+			  ploss, jitter);
+	if (nchars < 0 || nchars >= size)
+		goto truncate;
+
+	msg += nchars;
+	size -= nchars;
+
+	/* Error Counter */
+	snprintf(msg, size,
+		 "\r\nX-Osmo: EC TIS=%u, TOS=%u, TIR=%u, TOR=%u",
+		 endp->net_state.err_ts_in_counter,
+		 endp->net_state.err_ts_out_counter,
+		 endp->bts_state.err_ts_in_counter,
+		 endp->bts_state.err_ts_out_counter);
+truncate:
 	msg[size - 1] = '\0';
 }
 
diff --git a/openbsc/src/libmgcp/mgcp_vty.c b/openbsc/src/libmgcp/mgcp_vty.c
index 3c239d8..528a312 100644
--- a/openbsc/src/libmgcp/mgcp_vty.c
+++ b/openbsc/src/libmgcp/mgcp_vty.c
@@ -114,7 +114,7 @@ static int config_write_mgcp(struct vty *vty)
 	return CMD_SUCCESS;
 }
 
-static void dump_trunk(struct vty *vty, struct mgcp_trunk_config *cfg)
+static void dump_trunk(struct vty *vty, struct mgcp_trunk_config *cfg, int verbose)
 {
 	int i;
 
@@ -139,18 +139,31 @@ static void dump_trunk(struct vty *vty, struct mgcp_trunk_config *cfg)
 			endp->bts_end.packets, endp->net_end.packets,
 			endp->trans_net.packets, endp->trans_bts.packets,
 			VTY_NEWLINE);
+
+		if (verbose)
+			vty_out(vty,
+				"  Timestamp Errs: BTS %d->%d, Net %d->%d%s",
+				endp->bts_state.err_ts_in_counter,
+				endp->bts_state.err_ts_out_counter,
+				endp->net_state.err_ts_in_counter,
+				endp->net_state.err_ts_out_counter,
+				VTY_NEWLINE);
 	}
 }
 
-DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp",
-      SHOW_STR "Display information about the MGCP Media Gateway")
+DEFUN(show_mcgp, show_mgcp_cmd,
+      "show mgcp [stats]",
+      SHOW_STR
+      "Display information about the MGCP Media Gateway\n"
+      "Include Statistics\n")
 {
 	struct mgcp_trunk_config *trunk;
+	int show_stats = argc >= 1;
 
-	dump_trunk(vty, &g_cfg->trunk);
+	dump_trunk(vty, &g_cfg->trunk, show_stats);
 
 	llist_for_each_entry(trunk, &g_cfg->trunks, entry)
-		dump_trunk(vty, trunk);
+		dump_trunk(vty, trunk, show_stats);
 
 	return CMD_SUCCESS;
 }
diff --git a/openbsc/tests/mgcp/mgcp_test.c b/openbsc/tests/mgcp/mgcp_test.c
index 5565e73..3499ee3 100644
--- a/openbsc/tests/mgcp/mgcp_test.c
+++ b/openbsc/tests/mgcp/mgcp_test.c
@@ -97,7 +97,8 @@
 		 "C: 2\r\n"
 
 #define DLCX_RET "250 7 OK\r\n"			\
-		 "P: PS=0, OS=0, PR=0, OR=0, PL=0, JI=0\r\n"
+		 "P: PS=0, OS=0, PR=0, OR=0, PL=0, JI=0\r\n" \
+		 "X-Osmo: EC TIS=0, TOS=0, TIR=0, TOR=0\r\n"
 
 #define RQNT	 "RQNT 186908780 1 at mgw MGCP 1.0\r\n"	\
 		 "X: B244F267488\r\n"			\
-- 
1.7.9.5





More information about the OpenBSC mailing list