diff --git a/TODO-RELEASE b/TODO-RELEASE index d0852fc9b..f172501ae 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -7,3 +7,4 @@ # If any interfaces have been added since the last public release: c:r:a + 1. # If any interfaces have been removed or changed since the last public release: c:r:0. #library what description / commit summary line +libosmogsm >1.7.0 BTS_FEAT_OSMUX, RSL_IE_OSMO_OSMUX_CID diff --git a/include/osmocom/bsc/bts.h b/include/osmocom/bsc/bts.h index 752a00a73..b690652f3 100644 --- a/include/osmocom/bsc/bts.h +++ b/include/osmocom/bsc/bts.h @@ -590,6 +590,9 @@ struct gsm_bts { struct amr_multirate_conf mr_full; struct amr_multirate_conf mr_half; + /* osmux config: */ + enum osmux_usage use_osmux; + /* PCU socket state */ char *pcu_sock_path; struct pcu_sock_state *pcu_state; diff --git a/include/osmocom/bsc/lchan.h b/include/osmocom/bsc/lchan.h index a6048c26b..2de1227a7 100644 --- a/include/osmocom/bsc/lchan.h +++ b/include/osmocom/bsc/lchan.h @@ -299,6 +299,12 @@ struct gsm_lchan { uint8_t rr_cause; bool valid; } ass_compl; + + struct { + bool use; + uint8_t local_cid; + uint8_t remote_cid; + } osmux; } abis_ip; /* At first, the Timing Advance from the initial Channel Request. Later, the Timing Advance value received from diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c index 8ec94a91d..1c60405c4 100644 --- a/src/osmo-bsc/abis_rsl.c +++ b/src/osmo-bsc/abis_rsl.c @@ -2739,11 +2739,15 @@ static void ipac_parse_rtp(struct gsm_lchan *lchan, struct tlv_parsed *tv, const port = ntohs(port); lchan->abis_ip.connect_port = port; } + if (TLVP_PRESENT(tv, RSL_IE_OSMO_OSMUX_CID)) { + lchan->abis_ip.osmux.remote_cid = tlvp_val8(tv, RSL_IE_OSMO_OSMUX_CID, 0); + } LOG_LCHAN(lchan, LOGL_DEBUG, "Rx IPACC %s ACK:" - " BTS=%s:%u conn_id=%u rtp_payload2=0x%02x speech_mode=0x%02x\n", + " BTS=%s:%u conn_id=%u rtp_payload2=0x%02x speech_mode=0x%02x osmux_use=%d osmux_loc_cid=%d\n", label, ip_to_a(lchan->abis_ip.bound_ip), lchan->abis_ip.bound_port, - lchan->abis_ip.conn_id, lchan->abis_ip.rtp_payload2, lchan->abis_ip.speech_mode); + lchan->abis_ip.conn_id, lchan->abis_ip.rtp_payload2, lchan->abis_ip.speech_mode, + lchan->abis_ip.osmux.use, lchan->abis_ip.osmux.local_cid); } /*! Send Issue IPA RSL CRCX to configure the RTP port of the BTS. @@ -2768,9 +2772,13 @@ int rsl_tx_ipacc_crcx(const struct gsm_lchan *lchan) /* 0x1- == receive-only, 0x-1 == EFR codec */ msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode); msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD, lchan->abis_ip.rtp_payload); + if (lchan->abis_ip.osmux.use) + msgb_tlv_put(msg, RSL_IE_OSMO_OSMUX_CID, 1, &lchan->abis_ip.osmux.local_cid); - LOG_LCHAN(lchan, LOGL_DEBUG, "Sending IPACC CRCX to BTS: speech_mode=0x%02x RTP_PAYLOAD=%d\n", - lchan->abis_ip.speech_mode, lchan->abis_ip.rtp_payload); + LOG_LCHAN(lchan, LOGL_DEBUG, + "Sending IPACC CRCX to BTS: speech_mode=0x%02x RTP_PAYLOAD=%d osmux_use=%d osmux_loc_cid=%d\n", + lchan->abis_ip.speech_mode, lchan->abis_ip.rtp_payload, + lchan->abis_ip.osmux.use, lchan->abis_ip.osmux.local_cid); msg->dst = rsl_chan_link(lchan); @@ -2808,6 +2816,8 @@ struct msgb *rsl_make_ipacc_mdcx(const struct gsm_lchan *lchan, uint32_t dest_ip msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD, lchan->abis_ip.rtp_payload); if (lchan->abis_ip.rtp_payload2) msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD2, lchan->abis_ip.rtp_payload2); + if (lchan->abis_ip.osmux.use) + msgb_tlv_put(msg, RSL_IE_OSMO_OSMUX_CID, 1, &lchan->abis_ip.osmux.local_cid); msg->dst = rsl_chan_link(lchan); @@ -2865,6 +2875,15 @@ static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg) return -EINVAL; } + if (!lchan->abis_ip.osmux.use && TLVP_PRESENT(&tv, RSL_IE_OSMO_OSMUX_CID)) { + LOGP(DRSL, LOGL_NOTICE, "Received unexpected IE Osmux CID\n"); + return -EINVAL; + } + if (lchan->abis_ip.osmux.use && !TLVP_PRESENT(&tv, RSL_IE_OSMO_OSMUX_CID)) { + LOGP(DRSL, LOGL_NOTICE, "Mandatory IE Osmux CID missing\n"); + return -EINVAL; + } + ipac_parse_rtp(lchan, &tv, "CRCX"); osmo_fsm_inst_dispatch(lchan->fi_rtp, LCHAN_RTP_EV_IPACC_CRCX_ACK, 0); diff --git a/src/osmo-bsc/bts.c b/src/osmo-bsc/bts.c index 4976fe660..95e7430b1 100644 --- a/src/osmo-bsc/bts.c +++ b/src/osmo-bsc/bts.c @@ -428,6 +428,8 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, struct gsm_bts_sm *bts_sm memcpy(&bts->mr_half.bts_mode[0], &amr_hr_ms_bts_mode[0], sizeof(amr_hr_ms_bts_mode)); bts->mr_half.num_modes = ARRAY_SIZE(amr_hr_ms_bts_mode); + bts->use_osmux = OSMUX_USAGE_OFF; + bts_cbch_init(bts); bts_etws_init(bts); @@ -507,6 +509,13 @@ int gsm_bts_check_cfg(struct gsm_bts *bts) bts_gprs_mode_name(bts->gprs.mode)); return -EINVAL; } + if (bts->use_osmux == OSMUX_USAGE_ONLY && + !osmo_bts_has_feature(&bts->features, BTS_FEAT_OSMUX)) { + LOGP(DNM, LOGL_ERROR, + "(bts=%u) osmux use set to 'only', but BTS does not support Osmux\n", + bts->nr); + return -EINVAL; + } } /* Verify the physical channel mapping */ diff --git a/src/osmo-bsc/bts_vty.c b/src/osmo-bsc/bts_vty.c index 492cb9a5b..39007685f 100644 --- a/src/osmo-bsc/bts_vty.c +++ b/src/osmo-bsc/bts_vty.c @@ -2965,6 +2965,42 @@ DEFUN_USRATTR(cfg_bts_amr_hr_hyst3, return check_amr_config(vty); } +#define OSMUX_STR "RTP multiplexing\n" +DEFUN_USRATTR(cfg_bts_osmux, + cfg_bts_osmux_cmd, + X(BSC_VTY_ATTR_NEW_LCHAN), + "osmux (on|off|only)", + OSMUX_STR "Enable OSMUX\n" "Disable OSMUX\n" "Only use OSMUX\n") +{ + struct gsm_bts *bts = vty->index; + enum osmux_usage use; + + if (strcmp(argv[0], "off") == 0) + use = OSMUX_USAGE_OFF; + else if (strcmp(argv[0], "on") == 0) + use = OSMUX_USAGE_ON; + else if (strcmp(argv[0], "only") == 0) + use = OSMUX_USAGE_ONLY; + else + goto err; + + if (!is_osmobts(bts)) + goto err; + + if (bts->features_known && use != OSMUX_USAGE_OFF && + !osmo_bts_has_feature(&bts->features, BTS_FEAT_OSMUX)) + goto err; + + bts->use_osmux = use; + return CMD_SUCCESS; + +err: + LOGP(DNM, LOGL_ERROR, + "(bts=%u) Unable to set 'osmux %s', BTS does not support Osmux\n", + bts->nr, argv[0]); + return CMD_WARNING; +} + #define TNUM_STR "T-number, optionally preceded by 't' or 'T'\n" DEFUN_ATTR(cfg_bts_t3113_dynamic, cfg_bts_t3113_dynamic_cmd, "timer-dynamic TNNNN", @@ -4512,6 +4548,11 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) config_write_bts_amr(vty, bts, &bts->mr_full, 1); config_write_bts_amr(vty, bts, &bts->mr_half, 0); + if (bts->use_osmux != OSMUX_USAGE_OFF) { + vty_out(vty, " osmux %s%s", bts->use_osmux == OSMUX_USAGE_ON ? "on" : "only", + VTY_NEWLINE); + } + config_write_bts_gprs(vty, bts); if (bts->excl_from_rf_lock) @@ -4773,6 +4814,7 @@ int bts_vty_init(void) install_element(BTS_NODE, &cfg_bts_amr_hr_hyst2_cmd); install_element(BTS_NODE, &cfg_bts_amr_hr_hyst3_cmd); install_element(BTS_NODE, &cfg_bts_amr_hr_start_mode_cmd); + install_element(BTS_NODE, &cfg_bts_osmux_cmd); install_element(BTS_NODE, &cfg_bts_pcu_sock_cmd); install_element(BTS_NODE, &cfg_bts_acc_rotate_cmd); install_element(BTS_NODE, &cfg_bts_acc_rotate_quantum_cmd); diff --git a/src/osmo-bsc/lchan_rtp_fsm.c b/src/osmo-bsc/lchan_rtp_fsm.c index 504bb342e..87c235f36 100644 --- a/src/osmo-bsc/lchan_rtp_fsm.c +++ b/src/osmo-bsc/lchan_rtp_fsm.c @@ -138,9 +138,10 @@ static void lchan_rtp_fsm_wait_mgw_endpoint_available_onenter(struct osmo_fsm_in uint32_t prev_state) { struct gsm_lchan *lchan = lchan_rtp_fi_lchan(fi); + struct gsm_bts *bts = lchan->ts->trx->bts; struct osmo_mgcpc_ep *mgwep; struct osmo_mgcpc_ep_ci *use_mgwep_ci = lchan_use_mgw_endpoint_ci_bts(lchan); - struct mgcp_conn_peer crcx_info = {}; + struct mgcp_conn_peer crcx_info; if (!is_ipaccess_bts(lchan->ts->trx->bts)) { LOG_LCHAN_RTP(lchan, LOGL_DEBUG, "Audio link to-BTS via E1, skipping IPACC\n"); @@ -163,13 +164,20 @@ static void lchan_rtp_fsm_wait_mgw_endpoint_available_onenter(struct osmo_fsm_in lchan->mgw_endpoint_ci_bts = osmo_mgcpc_ep_ci_add(mgwep, "to-BTS"); + crcx_info = (struct mgcp_conn_peer){ + .ptime = 20, + .x_osmo_osmux_use = bts->use_osmux != OSMUX_USAGE_OFF, + .x_osmo_osmux_cid = -1, /* -1 is wildcard */ + }; if (lchan->conn) { crcx_info.call_id = lchan->conn->sccp.conn_id; if (lchan->conn->sccp.msc) crcx_info.x_osmo_ign = lchan->conn->sccp.msc->x_osmo_ign; } - crcx_info.ptime = 20; mgcp_pick_codec(&crcx_info, lchan, true); + /* TODO: lchan_rtp_fail() here if crcx_info->codecs[] contains non-AMR and bts->use_osmux=ONLY. + If bts->use_osmux=ON, only set .x_osmo_osmux_use if there's an AMR in crcx_info->codecs[]. + IF osmux=no, always set x_osmo_osmux_use=false*/ osmo_mgcpc_ep_ci_request(lchan->mgw_endpoint_ci_bts, MGCP_VERB_CRCX, &crcx_info, fi, LCHAN_RTP_EV_MGW_ENDPOINT_AVAILABLE, LCHAN_RTP_EV_MGW_ENDPOINT_ERROR, @@ -179,11 +187,26 @@ static void lchan_rtp_fsm_wait_mgw_endpoint_available_onenter(struct osmo_fsm_in static void lchan_rtp_fsm_wait_mgw_endpoint_available(struct osmo_fsm_inst *fi, uint32_t event, void *data) { struct gsm_lchan *lchan = lchan_rtp_fi_lchan(fi); + struct gsm_bts *bts = lchan->ts->trx->bts; switch (event) { case LCHAN_RTP_EV_MGW_ENDPOINT_AVAILABLE: LOG_LCHAN_RTP(lchan, LOGL_DEBUG, "MGW endpoint: %s\n", osmo_mgcpc_ep_ci_name(lchan_use_mgw_endpoint_ci_bts(lchan))); + if (osmo_mgcpc_ep_ci_get_crcx_info_to_osmux_cid(lchan->mgw_endpoint_ci_bts, + &lchan->abis_ip.osmux.local_cid)) { + if (bts->use_osmux == OSMUX_USAGE_OFF) { + lchan_rtp_fail("Got Osmux CID from MGW but we didn't ask for it"); + return; + } + lchan->abis_ip.osmux.use = true; + } else { + if (bts->use_osmux == OSMUX_USAGE_ONLY) { + lchan_rtp_fail("Got no Osmux CID from MGW but Osmux is mandatory"); + return; + } + lchan->abis_ip.osmux.use = false; + } lchan_rtp_fsm_state_chg(LCHAN_RTP_ST_WAIT_LCHAN_READY); return; @@ -415,6 +438,8 @@ static void connect_mgw_endpoint_to_lchan(struct osmo_fsm_inst *fi, mdcx_info = (struct mgcp_conn_peer){ .port = to_lchan->abis_ip.bound_port, .ptime = 20, + .x_osmo_osmux_use = lchan->abis_ip.osmux.use, + .x_osmo_osmux_cid = lchan->abis_ip.osmux.remote_cid, }; mgcp_pick_codec(&mdcx_info, to_lchan, true);