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