diff options
author | Holger Hans Peter Freyther <zecke@selfish.org> | 2011-08-30 08:45:36 +0200 |
---|---|---|
committer | Holger Hans Peter Freyther <zecke@selfish.org> | 2011-08-30 15:04:16 +0200 |
commit | 88467ee341dfde5f075eee5c12c3ad607fbaa8d9 (patch) | |
tree | 952907bbc6859ec3b750034679cc4a33cc84e41d | |
parent | 556f076c4f6f2d59c87a409adda8a837acac507c (diff) |
mgcp: Attempt to guess the size by looking at the AMR toc
-rw-r--r-- | openbsc/src/libmgcp/rtp_helper.c | 106 | ||||
-rw-r--r-- | openbsc/tests/mgcp/mgcp_test.c | 67 |
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) |