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...
This commit is contained in:
Harald Welte 2011-09-04 17:21:39 +02:00
parent 099fb3b17c
commit f41f2a7f92
2 changed files with 76 additions and 18 deletions

View File

@ -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) {

View File

@ -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;
}