diff options
author | Pablo Neira Ayuso <pablo@gnumonks.org> | 2013-05-24 11:56:07 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@gnumonks.org> | 2013-05-24 12:16:49 +0200 |
commit | 70214a15d1d575802d821c3555f61c3797a0a89b (patch) | |
tree | b5cf3b05f2b25c93c6694b8044046c4c48f40df4 | |
parent | 9d6d126c230f480510622dbb1a0f13cdef640146 (diff) |
osmux: further sanity checkings for AMR FT
According to RFC3267, AMR FT upper 9 should be discarded. This patch
adds extra validation to make sure that input RTP traffic encapsulating
AMR payload and OSMUX amr_ft field are OK with regards to that
restriction.
-rw-r--r-- | include/osmocom/netif/amr.h | 1 | ||||
-rw-r--r-- | src/amr.c | 19 | ||||
-rw-r--r-- | src/osmux.c | 30 |
3 files changed, 45 insertions, 5 deletions
diff --git a/include/osmocom/netif/amr.h b/include/osmocom/netif/amr.h index 21ba9da..863915e 100644 --- a/include/osmocom/netif/amr.h +++ b/include/osmocom/netif/amr.h @@ -78,6 +78,7 @@ static inline void *osmo_amr_get_payload(struct amr_hdr *amrh) #define AMR_FT_SID 8 /* SID */ #define AMR_FT_MAX 9 +int osmo_amr_ft_valid(uint8_t amr_ft); size_t osmo_amr_bytes(uint8_t amr_cmr); #endif @@ -41,3 +41,22 @@ size_t osmo_amr_bytes(uint8_t amr_ft) { return amr_ft_to_bytes[amr_ft]; } + +int osmo_amr_ft_valid(uint8_t amr_ft) +{ + /* + * Extracted from RFC3267: + * + * "... with a FT value in the range 9-14 for AMR ... the whole packet + * SHOULD be discarded." + * + * "... packets containing only NO_DATA frames (FT=15) SHOULD NOT be + * transmitted." + * + * So, let's discard frames with a AMR FT >= 9. + */ + if (amr_ft >= 9) + return 0; + + return 1; +} diff --git a/src/osmux.c b/src/osmux.c index 9438d42..a844372 100644 --- a/src/osmux.c +++ b/src/osmux.c @@ -59,6 +59,13 @@ struct osmux_hdr *osmux_xfrm_output_pull(struct msgb *msg) size_t len; osmuxh = (struct osmux_hdr *)msg->data; + + if (!osmo_amr_ft_valid(osmuxh->amr_ft)) { + LOGP(DLMIB, LOGL_ERROR, "Discarding bad AMR FT %d\n", + osmuxh->amr_ft); + return NULL; + } + len = osmo_amr_bytes(osmuxh->amr_ft) * (osmuxh->ctr+1) + sizeof(struct osmux_hdr); @@ -311,6 +318,9 @@ static int osmux_rtp_amr_payload_len(struct msgb *msg, struct rtp_hdr *rtph) if (amrh == NULL) return -1; + if (!osmo_amr_ft_valid(amrh->ft)) + return -1; + return amr_len - sizeof(struct amr_hdr); } @@ -367,7 +377,7 @@ osmux_batch_add(struct osmux_batch *batch, struct msgb *msg, int ccid) { struct rtp_hdr *rtph; struct batch_list_node *node; - int found = 0, bytes = 0; + int found = 0, bytes = 0, amr_payload_len; llist_for_each_entry(node, &batch->node_list, head) { if (node->ccid == ccid) { @@ -380,8 +390,12 @@ osmux_batch_add(struct osmux_batch *batch, struct msgb *msg, int ccid) if (rtph == NULL) return 0; + amr_payload_len = osmux_rtp_amr_payload_len(msg, rtph); + if (amr_payload_len < 0) + return 0; + /* First check if there is room for this message in the batch */ - bytes += osmux_rtp_amr_payload_len(msg, rtph); + bytes += amr_payload_len; if (!found) bytes += sizeof(struct osmux_hdr); @@ -443,7 +457,7 @@ osmux_batch_add(struct osmux_batch *batch, struct msgb *msg, int ccid) */ int osmux_xfrm_input(struct osmux_in_handle *h, struct msgb *msg, int ccid) { - int ret; + int ret, first_rtp_msg; struct rtp_hdr *rtph; struct osmux_batch *batch = (struct osmux_batch *)h->internal_data; @@ -463,14 +477,20 @@ int osmux_xfrm_input(struct osmux_in_handle *h, struct msgb *msg, int ccid) /* This is the first message in the batch, start the * batch timer to deliver it. */ - if (llist_empty(&batch->node_list)) { + first_rtp_msg = llist_empty(&batch->node_list) ? 1 : 0; + + /* Add this RTP to the OSMUX batch */ + ret = osmux_batch_add(batch, msg, ccid); + if (ret < 0) + return 0; + + if (first_rtp_msg) { LOGP(DLMIB, LOGL_DEBUG, "osmux start timer batch\n"); osmo_timer_schedule(&batch->timer, 0, h->batch_factor * DELTA_RTP_MSG); } - ret = osmux_batch_add(batch, msg, ccid); break; } return ret; |