aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2011-09-04 17:21:39 +0200
committerHarald Welte <laforge@gnumonks.org>2011-09-04 17:21:39 +0200
commitf41f2a7f92d7eea87e3f036a849bf8b131e2b389 (patch)
tree8d123aae7dd6ff180e88cda72d94546fb07aa8c6
parent099fb3b17cf29d6d152abb4d2cf4aef76916f8a0 (diff)
AMR: double-check CMI/CMR/CMC values
We have to make sure that a phone cannot request codec modes which are not part of the active set...
-rw-r--r--src/common/rsl.c22
-rw-r--r--src/osmo-bts-sysmo/tch.c72
2 files changed, 76 insertions, 18 deletions
diff --git a/src/common/rsl.c b/src/common/rsl.c
index 59185124..29a0fb71 100644
--- a/src/common/rsl.c
+++ b/src/common/rsl.c
@@ -1020,9 +1020,12 @@ static int rsl_tx_ipac_XXcx_ack(struct gsm_lchan *lchan, int inc_pt2,
name = "MDCX";
ia.s_addr = htonl(lchan->abis_ip.bound_ip);
- LOGP(DRSL, LOGL_INFO, "%s RSL Tx IPAC_%s_ACK (local %s:%u)\n",
- gsm_lchan_name(lchan), name, inet_ntoa(ia),
- lchan->abis_ip.bound_port);
+ LOGP(DRSL, LOGL_INFO, "%s RSL Tx IPAC_%s_ACK (local %s:%u, ",
+ gsm_lchan_name(lchan), name,
+ inet_ntoa(ia), lchan->abis_ip.bound_port);
+ ia.s_addr = htonl(lchan->abis_ip.connect_ip);
+ LOGPC(DRSL, LOGL_INFO, "remote %s:%u)\n",
+ inet_ntoa(ia), lchan->abis_ip.connect_port);
/* Connection ID */
msgb_tv16_put(msg, RSL_IE_IPAC_CONN_ID, htons(lchan->abis_ip.conn_id));
@@ -1215,7 +1218,14 @@ static int rsl_rx_ipac_XXcx(struct msgb *msg)
if (connect_ip && connect_port) {
struct in_addr ia;
- ia.s_addr = *connect_ip;
+ /* Special rule: If connect_ip == 0.0.0.0, use RSL IP
+ * address */
+ if (*connect_ip == 0) {
+ struct ipabis_link *link =
+ lchan->ts->trx->rsl_link;
+ ia.s_addr = htonl(link->ip);
+ } else
+ ia.s_addr = *connect_ip;
rc = osmo_rtp_socket_connect(lchan->abis_ip.rtp_socket,
inet_ntoa(ia), ntohs(*connect_port));
if (rc < 0) {
@@ -1229,8 +1239,10 @@ static int rsl_rx_ipac_XXcx(struct msgb *msg)
inc_ip_port, dch->c.msg_type);
}
/* save IP address and port number */
- lchan->abis_ip.connect_ip = ntohl(*connect_ip);
+ lchan->abis_ip.connect_ip = ntohl(ia.s_addr);
lchan->abis_ip.connect_port = ntohs(*connect_port);
+ } else {
+ /* FIXME: discard all codec frames */
}
/* Everything has succeeded, we can store new values in lchan */
if (payload_type) {
diff --git a/src/osmo-bts-sysmo/tch.c b/src/osmo-bts-sysmo/tch.c
index 12250108..dd2ae32d 100644
--- a/src/osmo-bts-sysmo/tch.c
+++ b/src/osmo-bts-sysmo/tch.c
@@ -198,8 +198,10 @@ static int rtppayload_to_l1_hr(uint8_t *l1_payload, uint8_t *rtp_payload,
}
#define AMR_TOC_QBIT 0x04
+#define AMR_CMR_NONE 0xF
-static struct msgb *l1_to_rtppayload_amr(uint8_t *l1_payload, uint8_t payload_len)
+static struct msgb *l1_to_rtppayload_amr(uint8_t *l1_payload, uint8_t payload_len,
+ uint8_t active_codec_set)
{
struct msgb *msg = msgb_alloc_headroom(1024, 128, "L1C-to-RTP");
uint8_t *cur;
@@ -207,6 +209,21 @@ static struct msgb *l1_to_rtppayload_amr(uint8_t *l1_payload, uint8_t payload_le
uint8_t cmr = l1_payload[1];
uint8_t amr_if2_len = payload_len - 2;
+#warning Only use CMR when it actually appears according to TDMA time
+#if 0
+ /* CMR can never be > 7 */
+ if (cmr > 7)
+ cmr = AMR_CMR_NONE;
+ else {
+ /* Make sure the CMR of the phone is in the active codec set */
+ if (!(active_codec_set & (1 << cmr))) {
+ LOGP(DL1C, LOGL_NOTICE, "L1->RTP: overriding CMR %u\n", cmr);
+ cmr = AMR_CMR_NONE;
+ }
+ }
+#else
+ cmr = AMR_CMR_NONE;
+#endif
/* RFC 3267 4.4.1 Payload Header */
msgb_put_u8(msg, (cmr << 4));
@@ -234,16 +251,48 @@ enum amr_frame_type {
* \param[in] payload_len length of \a rtp_payload
* \returns number of \a l1_payload bytes filled
*/
-static int rtppayload_to_l1_amr(uint8_t *l1_payload, uint8_t *rtp_payload, uint8_t payload_len)
+static int rtppayload_to_l1_amr(uint8_t *l1_payload, uint8_t *rtp_payload,
+ uint8_t payload_len, const uint8_t active_codec_set)
{
uint8_t ft = (rtp_payload[1] >> 3) & 0xf;
uint8_t cmr = rtp_payload[0] >> 4;
+ uint8_t *l1_cmi = l1_payload;
+ uint8_t *l1_cmr = l1_payload+1;
uint8_t amr_if2_core_len = payload_len - 2;
- /* CMC is in upper 4 bits of RTP payload header, and we simply
- * copy the CMR into the CMC */
- l1_payload[1] = cmr;
+ /* step1: shift everything right one nibble; make space for FT */
+ osmo_nibble_shift_right(l1_payload+2, rtp_payload+2, amr_if2_core_len*2 -1);
+ /* step2: reverse the bit-order within every byte of the IF2
+ * core frame contained in the RTP payload */
+ osmo_revbytebits_buf(l1_payload+2, amr_if2_core_len);
+
+ /* CMI in downlink tells the L1 encoder which encoding function
+ * it will use, so we have to use the frame type */
+ switch (ft) {
+ case 0: case 1: case 2: case 3:
+ case 4: case 5: case 6: case 7:
+ *l1_cmi = ft;
+ break;
+ case AMR_FT_SID_AMR:
+ /* extract the mode indiciation from last 3 bits of
+ * 39 bit SID frame */
+ *l1_cmi = *(l1_payload+2+4) >> 4;
+ break;
+ default:
+ LOGP(DL1C, LOGL_ERROR, "unsupported AMR FT 0x%02x\n", ft);
+ break;
+ }
+ /* Codec Mode Request is in upper 4 bits of RTP payload header,
+ * and we simply copy the CMR into the CMC */
+ if (cmr == 0xF)
+ *l1_cmr = 2;
+ else if (!(active_codec_set & (1 << cmr))) {
+ /* FIXME: we need some state about the last codec mode */
+ LOGP(DL1C, LOGL_NOTICE, "RTP->L1: overriding CMR %u\n", cmr);
+ *l1_cmr = 2;
+ } else
+ *l1_cmr = cmr;
#if 0
/* check for bad quality indication */
if (rtp_payload[1] & AMR_TOC_QBIT) {
@@ -260,12 +309,6 @@ static int rtppayload_to_l1_amr(uint8_t *l1_payload, uint8_t *rtp_payload, uint8
}
#endif
- /* step1: shift everything right one nibble; make space for FT */
- osmo_nibble_shift_right(l1_payload+2, rtp_payload+2, amr_if2_core_len*2 -1);
- /* step2: reverse the bit-order within every byte of the IF2
- * core frame contained in the RTP payload */
- osmo_revbytebits_buf(l1_payload+2, amr_if2_core_len);
-
/* lower 4 bit of first FR2 byte contains FT */
l1_payload[2] |= ft;
@@ -296,6 +339,7 @@ void bts_model_rtp_rx_cb(struct osmo_rtp_socket *rs, uint8_t *rtp_pl,
GsmL1_MsgUnitParam_t *msu_param = &data_req->msgUnitParam;
uint8_t *payload_type = &msu_param->u8Buffer[0];
uint8_t *l1_payload = &msu_param->u8Buffer[1];
+ uint8_t *mr_conf = &lchan->mr_conf;
int rc;
DEBUGP(DL1C, "%s RTP IN: %s\n", gsm_lchan_name(lchan),
@@ -321,7 +365,8 @@ void bts_model_rtp_rx_cb(struct osmo_rtp_socket *rs, uint8_t *rtp_pl,
#endif
case GSM48_CMODE_SPEECH_AMR:
*payload_type = GsmL1_TchPlType_Amr;
- rc = rtppayload_to_l1_amr(l1_payload, rtp_pl, rtp_pl_len);
+ rc = rtppayload_to_l1_amr(l1_payload, rtp_pl,
+ rtp_pl_len, mr_conf[1]);
break;
default:
/* we don't support CSD modes */
@@ -371,6 +416,7 @@ int l1if_tch_rx(struct gsm_lchan *lchan, struct msgb *l1p_msg)
GsmL1_PhDataInd_t *data_ind = &l1p->u.phDataInd;
uint8_t payload_type = data_ind->msgUnitParam.u8Buffer[0];
uint8_t *payload = data_ind->msgUnitParam.u8Buffer + 1;
+ uint8_t *mr_conf = &lchan->mr_conf;
uint8_t payload_len;
struct msgb *rmsg = NULL;
@@ -421,7 +467,7 @@ int l1if_tch_rx(struct gsm_lchan *lchan, struct msgb *l1p_msg)
break;
#endif
case GsmL1_TchPlType_Amr:
- rmsg = l1_to_rtppayload_amr(payload, payload_len);
+ rmsg = l1_to_rtppayload_amr(payload, payload_len, mr_conf[1]);
break;
}