aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2011-08-30 08:45:36 +0200
committerHolger Hans Peter Freyther <zecke@selfish.org>2011-08-30 15:04:16 +0200
commit88467ee341dfde5f075eee5c12c3ad607fbaa8d9 (patch)
tree952907bbc6859ec3b750034679cc4a33cc84e41d
parent556f076c4f6f2d59c87a409adda8a837acac507c (diff)
mgcp: Attempt to guess the size by looking at the AMR toc
-rw-r--r--openbsc/src/libmgcp/rtp_helper.c106
-rw-r--r--openbsc/tests/mgcp/mgcp_test.c67
2 files changed, 151 insertions, 22 deletions
diff --git a/openbsc/src/libmgcp/rtp_helper.c b/openbsc/src/libmgcp/rtp_helper.c
index feb3d591d..a07db3591 100644
--- a/openbsc/src/libmgcp/rtp_helper.c
+++ b/openbsc/src/libmgcp/rtp_helper.c
@@ -48,6 +48,15 @@ struct reduced_rtp_hdr {
uint8_t data[0];
} __attribute__((packed));
+struct amr_toc {
+ uint8_t reserved : 4,
+ cmd : 4;
+ uint8_t na : 2,
+ q_bit : 1,
+ ft_bits: 4,
+ f_bit : 1;
+} __attribute__((packed));
+
#define msgb_put_struct(msg, str) \
(str *) msgb_put(msg, sizeof(str))
@@ -73,6 +82,16 @@ static void fill_rtp_state(struct rtp_hdr *hdr,
state->timestamp += 160;
}
+static int guess_amr_size(const uint8_t *_data)
+{
+ const struct amr_toc *toc;
+ toc = (struct amr_toc *) _data;
+ if (toc->ft_bits == 8 && toc->f_bit == 0 && toc->q_bit == 1)
+ return 7;
+
+ return 17;
+}
+
static void write_compressed_big(struct reduced_rtp_hdr *reduced_hdr,
struct msgb *msg,
struct llist_head *rtp_packets)
@@ -125,36 +144,58 @@ static int read_compressed_big(struct msgb *msg,
struct mgcp_rtp_compr_state *state)
{
int i;
-
- if (msgb_l2len(msg) < sizeof(*rhdr) + rhdr->payloads * 18) {
- LOGP(DMGCP, LOGL_ERROR,
- "Payloads do not fit. %d\n", rhdr->payloads);
- return -3;
- }
+ uint16_t offset = 0;
+ const uint16_t len = msgb_l2len(msg) - sizeof(*rhdr);
for (i = 0; i < rhdr->payloads; ++i) {
struct rtp_hdr *hdr;
- struct msgb *out = msgb_alloc_headroom(4096, 128, "RTP decompr");
+ struct msgb *out;
+ int alen;
+
+ if (len < offset + 1 + sizeof(struct amr_toc)) {
+ LOGP(DMGCP, LOGL_ERROR, "Can not fit RTP/AMR in %d\n", i);
+ goto clean_all;
+ }
+
+ out = msgb_alloc_headroom(4096, 128, "RTP decompr");
if (!out) {
LOGP(DMGCP, LOGL_ERROR, "Failed to allocate: %d\n", i);
- continue;
+ goto clean_all;
}
+
out->l2h = msgb_put(out, 0);
hdr = msgb_put_struct(out, struct rtp_hdr);
fill_rtp_hdr(hdr);
fill_rtp_state(hdr, state);
/* re-apply the marker bit */
- if (rhdr->data[i * 18] & RTP_EXTRA_MARKER)
+ if (rhdr->data[offset] & RTP_EXTRA_MARKER)
hdr->marker = 1;
+ offset += 1;
- out->l3h = msgb_put(out, 17);
- memcpy(out->l3h, &rhdr->data[i * 18], 17);
+ /* guess the size of the AMR payload */
+ alen = guess_amr_size(&rhdr->data[offset]);
+ if (len < offset + alen) {
+ LOGP(DMGCP, LOGL_ERROR, "Payload does not fit.\n");
+ goto clean_all;
+ }
+
+ out->l3h = msgb_put(out, alen);
+ memcpy(out->l3h, &rhdr->data[offset], alen);
msgb_enqueue(list, out);
+ offset += alen;
}
return 0;
+
+clean_all:
+ while (llist_empty(list)) {
+ struct msgb *msg = msgb_dequeue(list);
+ talloc_free(msg);
+ }
+
+ return -8;
}
static int read_compressed_slim(struct msgb *msg,
@@ -164,15 +205,20 @@ static int read_compressed_slim(struct msgb *msg,
{
int i;
- if (msgb_l2len(msg) < sizeof(*rhdr) + rhdr->payloads * 17) {
- LOGP(DMGCP, LOGL_ERROR,
- "Payloads do not fit. %d\n", rhdr->payloads);
- return -3;
- }
+ uint16_t offset = 0;
+ const uint16_t len = msgb_l2len(msg) - sizeof(*rhdr);
for (i = 0; i < rhdr->payloads; ++i) {
struct rtp_hdr *hdr;
- struct msgb *out = msgb_alloc_headroom(4096, 128, "RTP decompr");
+ struct msgb *out;
+ int alen;
+
+ if (len < offset + 1 + sizeof(struct amr_toc)) {
+ LOGP(DMGCP, LOGL_ERROR, "Can not fit RTP/AMR in %d\n", i);
+ goto clean_all;
+ }
+
+ out = msgb_alloc_headroom(4096, 128, "RTP decompr");
if (!out) {
LOGP(DMGCP, LOGL_ERROR, "Failed to allocate: %d\n", i);
continue;
@@ -183,12 +229,28 @@ static int read_compressed_slim(struct msgb *msg,
fill_rtp_hdr(hdr);
fill_rtp_state(hdr, state);
- out->l3h = msgb_put(out, 17);
- memcpy(out->l3h, &rhdr->data[i * 17], 17);
+ /* guess the size of the AMR payload */
+ alen = guess_amr_size(&rhdr->data[offset]);
+ if (len < offset + alen) {
+ LOGP(DMGCP, LOGL_ERROR, "Payload does not fit.\n");
+ goto clean_all;
+ }
+
+ out->l3h = msgb_put(out, alen);
+ memcpy(out->l3h, &rhdr->data[offset], alen);
msgb_enqueue(list, out);
+ offset += alen;
}
return 0;
+
+clean_all:
+ while (llist_empty(list)) {
+ struct msgb *msg = msgb_dequeue(list);
+ talloc_free(msg);
+ }
+
+ return -8;
}
@@ -221,6 +283,7 @@ int rtp_compress(struct mgcp_rtp_compr_state *state, struct msgb *msg,
llist_for_each_entry_safe(rtp, tmp, rtp_packets, list) {
struct rtp_hdr *hdr;
uint16_t sequence;
+ uint16_t payload_len;
if (msgb_l2len(rtp) < sizeof(struct rtp_hdr)) {
LOGP(DMGCP, LOGL_ERROR,
@@ -230,9 +293,10 @@ int rtp_compress(struct mgcp_rtp_compr_state *state, struct msgb *msg,
continue;
}
- if (msgb_l2len(rtp) < sizeof(struct rtp_hdr) + 17) {
+ payload_len = msgb_l2len(rtp) - sizeof(struct rtp_hdr);
+ if (payload_len != 7 && payload_len != 17) {
LOGP(DMGCP, LOGL_ERROR,
- "We assume every payload is 17 byte: %d\n",
+ "We assume every payload is 17 or 7 byte: %d\n",
msgb_l2len(rtp) - sizeof(struct rtp_hdr));
llist_del(&rtp->list);
talloc_free(rtp);
diff --git a/openbsc/tests/mgcp/mgcp_test.c b/openbsc/tests/mgcp/mgcp_test.c
index f07db2f79..4927027e8 100644
--- a/openbsc/tests/mgcp/mgcp_test.c
+++ b/openbsc/tests/mgcp/mgcp_test.c
@@ -108,6 +108,34 @@ static const uint8_t packet_4[] = {
0x13, 0x0e, 0x5e, 0x56, 0x6c
};
+/** test with some silence detection and clock jump */
+static const uint8_t packet_short_1[] = {
+ 0x80, 0x62, 0xcc, 0xc2, 0xf7, 0xcd, 0x4f, 0xe8,
+ 0x6f, 0x0f, 0xb1, 0xda, 0x00, 0x14, 0xff, 0x52,
+ 0x38, 0xaf, 0xab, 0xa7, 0xfd, 0xf6, 0x5f, 0xfd,
+ 0xf4, 0xac, 0x03, 0xe2, 0xec,
+};
+
+static const uint8_t packet_short_2[] = {
+ 0x80, 0x62, 0xcc, 0xc3, 0xf7, 0xcd, 0x50, 0x88,
+ 0x6f, 0x0f, 0xb1, 0xda, 0x00, 0x14, 0x83, 0x58,
+ 0x53, 0x5f, 0xfe, 0x65, 0xe3, 0x99, 0x9d, 0xdc,
+ 0xcb, 0xda, 0x9b, 0xab, 0x7c
+};
+
+static const uint8_t packet_short_3[] = {
+ 0x80, 0x62, 0xcc, 0xc4, 0xf7, 0xcd, 0x51, 0x28,
+ 0x6f, 0x0f, 0xb1, 0xda, 0x00, 0x44, 0x00, 0x00,
+ 0x00, 0x00, 0x04,
+};
+
+static const uint8_t packet_short_4[] = {
+ 0x80, 0xe2, 0xcc, 0xc5, 0xf7, 0xcd, 0x52, 0x68,
+ 0x6f, 0x0f, 0xb1, 0xda, 0x00, 0x14, 0x44, 0x7b,
+ 0xd5, 0xfd, 0xbd, 0xf5, 0x65, 0x77, 0x9f, 0xb3,
+ 0xc2, 0x90, 0x83, 0x37, 0x88,
+};
+
static struct msgb *from(const uint8_t *data, uint16_t len)
{
struct msgb *msg = msgb_alloc_headroom(4096, 128, "from");
@@ -128,6 +156,13 @@ static const struct pdata marker_normal[] = {
{ .data = packet_4, .len = sizeof(packet_4), },
};
+static const struct pdata shorter_marker[] = {
+ { .data = packet_short_1, .len = sizeof(packet_short_1) },
+ { .data = packet_short_2, .len = sizeof(packet_short_2) },
+ { .data = packet_short_3, .len = sizeof(packet_short_3) },
+ { .data = packet_short_4, .len = sizeof(packet_short_4) },
+};
+
struct estate {
const struct pdata *data;
int plen;
@@ -155,6 +190,26 @@ static const struct estate test_scenarious[] = {
.timestamp = 4157324008u,
},
},
+ /* this is testing the bigger encoding due the marker */
+ { .data = shorter_marker, .plen = ARRAY_SIZE(shorter_marker),
+ .output_size = 17 * 3 + 7 * 1 + 3 + 4 * 1,
+ .state = {
+ .last_ts = UCHAR_MAX,
+ .generated_ssrc = 0x6f0fb1da,
+ .sequence = 52418,
+ .timestamp = 4157427688u,
+ },
+ },
+ /* without the marker set, should be slim encoding */
+ { .data = shorter_marker, .plen = ARRAY_SIZE(shorter_marker) -1 ,
+ .output_size = 17 * 2 + 7 * 1 + 3,
+ .state = {
+ .last_ts = UCHAR_MAX,
+ .generated_ssrc = 0x6f0fb1da,
+ .sequence = 52418,
+ .timestamp = 4157427688u,
+ },
+ },
};
static void test_compress_one(const struct estate *edata, char *t)
@@ -169,6 +224,8 @@ static void test_compress_one(const struct estate *edata, char *t)
INIT_LLIST_HEAD(&list);
+ printf("TESTING: %s\n", t);
+
for (i = 0; i < len; ++i) {
msgs[i] = from(data[i].data, data[i].len);
msgb_enqueue(&list, msgs[i]);
@@ -185,7 +242,8 @@ static void test_compress_one(const struct estate *edata, char *t)
}
if (msgb_l2len(out) != edata->output_size) {
- fprintf(stderr, "Result is wrong size: %d\n", msgb_l2len(out));
+ fprintf(stderr, "Result is wrong size: %d %d\n",
+ edata->output_size, msgb_l2len(out));
abort();
}
@@ -212,6 +270,7 @@ static void test_compress_one(const struct estate *edata, char *t)
i, osmo_hexdump(msg->l2h, msgb_l2len(msg)));
abort();
}
+ printf("Matched %s\n", osmo_hexdump(msg->l2h, msgb_l2len(msg)));
i += 1;
}
@@ -236,6 +295,12 @@ void test_compress()
*/
test_compress_one(&test_scenarious[1], "No marker");
+
+ /**
+ * Test some shorter payloads, also a time jump at the end
+ */
+ test_compress_one(&test_scenarious[2], "Shortened and Jump");
+ test_compress_one(&test_scenarious[3], "Only shortened for slim");
}
int main(int argc, char **argv)