tnt has uploaded this change for review. ( https://gerrit.osmocom.org/13242
Change subject: libmsc: Allow different channel types to be requested as silent calls ...................................................................... libmsc: Allow different channel types to be requested as silent calls Change-Id: I82645708dd27864cf33ea9cc993ead0983415602 Signed-off-by: Sylvain Munaut <t...@246tnt.com> --- M include/osmocom/msc/silent_call.h M src/libmsc/msc_vty.c M src/libmsc/silent_call.c 3 files changed, 153 insertions(+), 22 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-msc refs/changes/42/13242/1 diff --git a/include/osmocom/msc/silent_call.h b/include/osmocom/msc/silent_call.h index 70324e5..dbd7dcc 100644 --- a/include/osmocom/msc/silent_call.h +++ b/include/osmocom/msc/silent_call.h @@ -2,9 +2,12 @@ #define _SILENT_CALL_H struct ran_conn; +struct gsm0808_channel_type; extern int gsm_silent_call_start(struct vlr_subscr *vsub, - void *data, int type); + struct gsm0808_channel_type *ct, + const char *traffic_dst_ip, uint16_t traffic_dst_port, + void *data); extern int gsm_silent_call_stop(struct vlr_subscr *vsub); #if 0 diff --git a/src/libmsc/msc_vty.c b/src/libmsc/msc_vty.c index 2adb2a4..4ec2e5b 100644 --- a/src/libmsc/msc_vty.c +++ b/src/libmsc/msc_vty.c @@ -1042,21 +1042,35 @@ return rc; } -#define CHAN_TYPES "(any|tch/f|tch/any|sdcch)" +#define CHAN_TYPES "(any|tch/f|tch/h|tch/any|sdcch)" #define CHAN_TYPE_HELP \ "Any channel\n" \ "TCH/F channel\n" \ + "TCH/H channel\n" \ "Any TCH channel\n" \ "SDCCH channel\n" +#define CHAN_MODES "(signalling|speech-hr|speech-fr|speech-efr|speech-amr)" +#define CHAN_MODE_HELP \ + "Signalling only\n" \ + "Speech with HR codec\n" \ + "Speech with FR codec\n" \ + "Speech with EFR codec\n" \ + "Speech with AMR codec\n" + DEFUN(subscriber_silent_call_start, subscriber_silent_call_start_cmd, - "subscriber " SUBSCR_TYPES " ID silent-call start (any|tch/f|tch/any|sdcch)", + "subscriber " SUBSCR_TYPES " ID silent-call start " CHAN_TYPES " " CHAN_MODES " [IP] [<0-65536>]", SUBSCR_HELP "Silent call operation\n" "Start silent call\n" - CHAN_TYPE_HELP) + CHAN_TYPE_HELP CHAN_MODE_HELP + "Target IP for RTP traffic (default 127.0.0.1)\n" + "Target port for RTP traffic (default: 4000)\n") { struct vlr_subscr *vsub = get_vsub_by_argv(gsmnet, argv[0], argv[1]); - int rc, type; + struct gsm0808_channel_type ct; + const char *ip = NULL; + uint16_t port = 0; + int rc, speech; if (!vsub) { vty_out(vty, "%% No subscriber found for %s %s%s", @@ -1064,16 +1078,52 @@ return CMD_WARNING; } - if (!strcmp(argv[2], "tch/f")) - type = RSL_CHANNEED_TCH_F; - else if (!strcmp(argv[2], "tch/any")) - type = RSL_CHANNEED_TCH_ForH; - else if (!strcmp(argv[2], "sdcch")) - type = RSL_CHANNEED_SDCCH; - else - type = RSL_CHANNEED_ANY; /* Defaults to ANY */ + memset(&ct, 0x00, sizeof(ct)); - rc = gsm_silent_call_start(vsub, vty, type); + if (!strcmp(argv[3], "signalling")) { + ct.ch_indctr = GSM0808_CHAN_SIGN; + ct.perm_spch[0] = 0; /* Spare but required */ + ct.perm_spch_len = 1; + } else if (!strcmp(argv[3], "speech-hr")) { + ct.ch_indctr = GSM0808_CHAN_SPEECH; + ct.perm_spch[0] = GSM0808_PERM_HR1; + ct.perm_spch_len = 1; + } else if (!strcmp(argv[3], "speech-fr")) { + ct.ch_indctr = GSM0808_CHAN_SPEECH; + ct.perm_spch[0] = GSM0808_PERM_FR1; + ct.perm_spch_len = 1; + } else if (!strcmp(argv[3], "speech-efr")) { + ct.ch_indctr = GSM0808_CHAN_SPEECH; + ct.perm_spch[0] = GSM0808_PERM_FR2; + ct.perm_spch_len = 1; + } else if (!strcmp(argv[3], "speech-amr")) { + ct.ch_indctr = GSM0808_CHAN_SPEECH; + ct.perm_spch[0] = GSM0808_PERM_FR3; + ct.perm_spch[1] = GSM0808_PERM_HR3; + ct.perm_spch_len = 2; + } + + speech = ct.ch_indctr == GSM0808_CHAN_SPEECH; + + if (!strcmp(argv[2], "tch/f")) + ct.ch_rate_type = speech ? GSM0808_SPEECH_FULL_BM : GSM0808_SIGN_FULL_BM; + else if (!strcmp(argv[2], "tch/h")) + ct.ch_rate_type = speech ? GSM0808_SPEECH_HALF_LM : GSM0808_SIGN_HALF_LM; + else if (!strcmp(argv[2], "tch/any")) + ct.ch_rate_type = speech ? GSM0808_SPEECH_FULL_PREF : GSM0808_SIGN_FULL_PREF; + else if (!strcmp(argv[2], "sdcch")) { + if (speech) { + vty_out(vty, "Can't request speech on SDCCH%s", VTY_NEWLINE); + return CMD_WARNING; + } + ct.ch_rate_type = GSM0808_SIGN_SDCCH; + } else + ct.ch_rate_type = speech ? GSM0808_SPEECH_FULL_PREF : GSM0808_SIGN_ANY; + + ip = argc >= 5 ? argv[4] : "127.0.0.1"; + port = argc >= 6 ? atoi(argv[5]) : 4000; + + rc = gsm_silent_call_start(vsub, &ct, ip, port, vty); switch (rc) { case -ENODEV: vty_out(vty, "%% Subscriber not attached%s", VTY_NEWLINE); diff --git a/src/libmsc/silent_call.c b/src/libmsc/silent_call.c index 2a9fa9c..cadd17d 100644 --- a/src/libmsc/silent_call.c +++ b/src/libmsc/silent_call.c @@ -24,6 +24,7 @@ #include <unistd.h> #include <errno.h> +#include <osmocom/core/byteswap.h> #include <osmocom/core/msgb.h> #include <osmocom/msc/signal.h> #include <osmocom/msc/debug.h> @@ -31,13 +32,37 @@ #include <osmocom/msc/gsm_subscriber.h> #include <osmocom/msc/vlr.h> +#include <osmocom/sigtran/sccp_helpers.h> + +struct silent_call_data { + struct gsm0808_channel_type ct; + + char traffic_ip[INET_ADDRSTRLEN]; + uint16_t traffic_port; + + void *data; + + struct osmo_timer_list timer; + struct ran_conn *conn; +}; + +static void timer_cb(void *data) +{ + struct silent_call_data *scd = (struct silent_call_data *)data; + ran_conn_communicating(scd->conn); + talloc_free(scd); +} + /* paging of the requested subscriber has completed */ static int paging_cb_silent(unsigned int hooknum, unsigned int event, struct msgb *msg, void *_conn, void *_data) { + struct silent_call_data *scd = (struct silent_call_data *)_data; struct ran_conn *conn = _conn; struct scall_signal_data sigdata; + struct msgb *msg_ass; int rc = 0; + int i; if (hooknum != GSM_HOOK_RR_PAGING) return -EINVAL; @@ -45,7 +70,7 @@ DEBUGP(DLSMS, "paging_cb_silent: "); sigdata.conn = conn; - sigdata.data = _data; + sigdata.data = scd->data; switch (event) { case GSM_PAGING_SUCCEEDED: @@ -56,20 +81,58 @@ conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn); #endif conn->silent_call = 1; + + /* Increment lchan reference count and mark as active*/ ran_conn_get(conn, RAN_CONN_USE_SILENT_CALL); - /* increment lchan reference count */ + + /* Schedule a timer to mark it as active */ + scd->conn = conn; + osmo_timer_setup(&scd->timer, timer_cb, scd); + osmo_timer_schedule(&scd->timer, 0, 0); + + /* Manually craft an assignement message with requested mode */ + if (scd->ct.ch_indctr == GSM0808_CHAN_SPEECH) { + struct gsm0808_speech_codec_list scl; + union { + struct sockaddr_storage st; + struct sockaddr_in in; + } rtp_addr; + + memset(&rtp_addr, 0, sizeof(rtp_addr)); + rtp_addr.in.sin_family = AF_INET; + rtp_addr.in.sin_port = osmo_htons(scd->traffic_port); + rtp_addr.in.sin_addr.s_addr = inet_addr(scd->traffic_ip); + + for (i=0; i<scd->ct.perm_spch_len; i++) + gsm0808_speech_codec_from_chan_type(&scl.codec[i], scd->ct.perm_spch[i]); + scl.len = scd->ct.perm_spch_len; + + msg_ass = gsm0808_create_ass(&scd->ct, NULL, &rtp_addr.st, &scl, NULL); + } else { + msg_ass = gsm0808_create_ass(&scd->ct, NULL, NULL, NULL, NULL); + } + + /* Send assignement message, hoping it will work */ + osmo_sccp_tx_data_msg(conn->a.scu, conn->a.conn_id, msg_ass); + + /* Signal completion */ osmo_signal_dispatch(SS_SCALL, S_SCALL_SUCCESS, &sigdata); break; + case GSM_PAGING_EXPIRED: case GSM_PAGING_BUSY: DEBUGP(DLSMS, "expired\n"); osmo_signal_dispatch(SS_SCALL, S_SCALL_EXPIRED, &sigdata); break; + default: rc = -EINVAL; break; } + if (rc) + talloc_free(scd); + return rc; } @@ -120,18 +183,33 @@ /* initiate a silent call with a given subscriber */ -int gsm_silent_call_start(struct vlr_subscr *vsub, void *data, int type) +int gsm_silent_call_start(struct vlr_subscr *vsub, + struct gsm0808_channel_type *ct, + const char *traffic_dst_ip, uint16_t traffic_dst_port, + void *data) { struct subscr_request *req; + struct silent_call_data *scd; - /* FIXME the VTY command allows selecting a silent call channel type. - * This doesn't apply to the situation after MSCSPLIT with an - * A-interface. */ - req = subscr_request_conn(vsub, paging_cb_silent, data, + scd = talloc_zero(vsub, struct silent_call_data); + + memcpy(&scd->ct, ct, sizeof(struct gsm0808_channel_type)); + + if (traffic_dst_ip) { + strncpy(scd->traffic_ip, traffic_dst_ip, sizeof(scd->traffic_ip)); + scd->traffic_port = traffic_dst_port; + } + + scd->data = data; + + req = subscr_request_conn(vsub, paging_cb_silent, scd, "establish silent call", SGSAP_SERV_IND_CS_CALL); - if (!req) + if (!req) { + talloc_free(scd); return -ENODEV; + } + return 0; } -- To view, visit https://gerrit.osmocom.org/13242 To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings Gerrit-Project: osmo-msc Gerrit-Branch: master Gerrit-MessageType: newchange Gerrit-Change-Id: I82645708dd27864cf33ea9cc993ead0983415602 Gerrit-Change-Number: 13242 Gerrit-PatchSet: 1 Gerrit-Owner: tnt <t...@246tnt.com>