This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
Harald Welte gerrit-no-reply at lists.osmocom.orgReview at https://gerrit.osmocom.org/7698 msc: Initial SMS testing (MO + MT SMS, successful case, no SMPP) Change-Id: I707330454ffab87daebf22ba83e6ba2873996424 --- M library/L3_Templates.ttcn M msc/BSC_ConnectionHandler.ttcn M msc/MSC_Tests.ttcn 3 files changed, 502 insertions(+), 3 deletions(-) git pull ssh://gerrit.osmocom.org:29418/osmo-ttcn3-hacks refs/changes/98/7698/1 diff --git a/library/L3_Templates.ttcn b/library/L3_Templates.ttcn index 3203b0e..3304662 100644 --- a/library/L3_Templates.ttcn +++ b/library/L3_Templates.ttcn @@ -2,7 +2,7 @@ /* L3 Templates, building on top of MobileL3*_Types from Ericsson. * - * (C) 2017 by Harald Welte <laforge at gnumonks.org> + * (C) 2017-2018 by Harald Welte <laforge at gnumonks.org> * All rights reserved. * * Released under the terms of GNU General Public License, Version 2 or @@ -17,7 +17,7 @@ import from MobileL3_RRM_Types all; import from MobileL3_CC_Types all; import from MobileL3_GMM_SM_Types all; -//import from MobileL3_SMS_Types all; +import from MobileL3_SMS_Types all; /* TS 24.007 Table 11.3 TI Flag */ const BIT1 c_TIF_ORIG := '0'B; @@ -2168,4 +2168,284 @@ with { extension "prototype(convert) encode(RAW)" }; + +/* SMS TPDU Layer */ + +template (value) TPDU_RP_DATA_MS_SGSN ts_SMS_SUBMIT(OCT1 msg_ref, template (value) TP_DA dst_addr, + template (value) OCT1 pid, template (value) OCT1 dcs, + integer length_ind, octetstring user_data) := { + sMS_SUBMIT := { + tP_MTI := '01'B, /* SUBMIT */ + tP_RD := '1'B, /* reject duplicates */ + tP_VPF := '00'B, /* not present */ + tP_SRR := '0'B, /* no status report requested */ + tP_UDHI := '0'B, /* no user data header in UD */ + tP_RP := '0'B, /* no reply path */ + tP_MR := msg_ref, + tP_DA := dst_addr, + tP_PID := pid, + tP_DCS := dcs, + tP_VP := omit, + tP_UDL_UD := { + tP_LengthIndicator := length_ind, + tP_UD := user_data + } + } +} + +template TPDU_RP_DATA_SGSN_MS tr_SMS_DELIVER(template TP_OA src_addr := ?, + template octetstring user_data := ?, + template OCT1 pid := ?, template OCT1 dcs := ?, + template BIT1 mms := ? + ) := { + sMS_DELIVER := { + tP_MTI := '00'B, /* DELIVER */ + tP_MMS := mms, /* more messages to send */ + tP_LP := ?, /* ?!? */ + tP_Spare := '0'B, + tP_SRI := '0'B, /* status report indication */ + tP_UDHI := '0'B, /* no user data header in UD */ + tP_RP := '0'B, /* no reply path */ + tP_OA := src_addr, + tP_PID := pid, + tP_DCS := dcs, + tP_SCTS := ?, + tP_UDL_UD := { + tP_LengthIndicator := ?, + tP_UD := user_data + } + } +} + +/* RP Layer */ + +private function ts_RpOrig(template (omit) RP_NumberingPlan_and_NumberDigits rp_orig) +return RP_OriginatorAddressLV { + var RP_OriginatorAddressLV ret; + if (istemplatekind(rp_orig, "omit")) { + ret := { 0, omit }; + } else { + ret := { 0, valueof(rp_orig) }; + } + return ret; +} + +private function ts_RpDst(template (omit) RP_NumberingPlan_and_NumberDigits rp_dst) +return RP_DestinationAddressLV { + var RP_DestinationAddressLV ret; + if (istemplatekind(rp_dst, "omit")) { + ret := { 0, omit }; + } else { + ret := { 0, valueof(rp_dst) }; + } + return ret; +} + +template (value) RPDU_MS_SGSN ts_RP_DATA_MO(OCT1 msg_ref, + template (omit) RP_NumberingPlan_and_NumberDigits rp_orig, + template (omit) RP_NumberingPlan_and_NumberDigits rp_dst, + template (value) TPDU_RP_DATA_MS_SGSN tpdu) := { + rP_DATA_MS_SGSN := { + rP_MTI := '000'B, + rP_Spare := '00000'B, + rP_MessageReference := msg_ref, + rP_OriginatorAddress := ts_RpOrig(rp_orig), + rP_DestinationAddress := ts_RpDst(rp_dst), + rP_User_Data := { + rP_LengthIndicator := 0, /* overwritten */ + rP_TPDU := tpdu + } + } +} + +template RPDU_SGSN_MS tr_RP_DATA_MT(template OCT1 msg_ref, + template RP_NumberingPlan_and_NumberDigits rp_orig, + template RP_NumberingPlan_and_NumberDigits rp_dst, + template TPDU_RP_DATA_SGSN_MS tpdu) := { + rP_DATA_SGSN_MS := { + rP_MTI := '001'B, + rP_Spare := '00000'B, + rP_MessageReference := msg_ref, + rP_OriginatorAddress := { ?, rp_orig }, + rP_DestinationAddress := { ?, rp_dst }, + rP_User_Data := { + rP_LengthIndicator := ?, + rP_TPDU := tpdu + } + + } +} + +template (value) RPDU_MS_SGSN ts_RP_ACK_MO(OCT1 msg_ref) := { + rP_ACK_MS_SGSN := { + rP_MTI := '010'B, + rP_Spare := '00000'B, + rP_MessageReference := msg_ref, + rP_User_Data := omit /* FIXME: report */ + } +} + +template RPDU_SGSN_MS tr_RP_ACK_MT(template OCT1 msg_ref) := { + rP_ACK_SGSN_MS := { + rP_MTI := '011'B, + rP_Spare := '00000'B, + rP_MessageReference := msg_ref, + rP_User_Data := omit /* FIXME: report */ + } +} + +template (value) RPDU_MS_SGSN ts_RP_ERROR_MO(OCT1 msg_ref, uint7_t cause) := { + rP_ERROR_MS_SGSN := { + rP_MTI := '100'B, + rP_Spare := '00000'B, + rP_Message_Reference := msg_ref, + rP_CauseLV := { + rP_LengthIndicator := 0, /* overwritten */ + rP_CauseV := { + causeValue := int2bit(cause, 7), + ext := '0'B + }, + rP_diagnisticField := omit + }, + rP_User_Data := omit /* FIXME: report */ + } +} + +private function f_cause_or_wc(template uint7_t cause) return template BIT7 { + if (istemplatekind(cause, "?")) { + return ?; + } else if (istemplatekind(cause, "*")) { + return *; + } else { + return int2bit(valueof(cause), 7); + } +} + +template RPDU_SGSN_MS tr_RP_ERROR_MT(template OCT1 msg_ref, template uint7_t cause) := { + rP_ERROR_SGSN_MS := { + rP_MTI := '101'B, + rP_Spare := '00000'B, + rP_Message_Reference := msg_ref, + rP_CauseLV := { + rP_LengthIndicator := 0, /* overwritten */ + rP_CauseV := { + causeValue := f_cause_or_wc(cause), + ext := '0'B + }, + rP_diagnisticField := omit + }, + rP_User_Data := omit /* FIXME: report */ + } +} + + +template (value) RPDU_MS_SGSN ts_RP_SMMA_MO(OCT1 msg_ref) := { + rP_SMMA := { + rP_MTI := '110'B, + rP_Spare := '00000'B, + rP_MessageReference := msg_ref + } +} + + + + +/* CP Layer */ + +template (value) L3_SMS_MS_SGSN ts_CP_DATA_MO(template (value) RPDU_MS_SGSN rpdu) := { + cP_DATA := { + cP_messageType := '00000001'B, + cP_User_Data := { + lengthIndicator := 0, /* overwritten */ + cP_RPDU := rpdu + } + } +} + +template (value) L3_SMS_MS_SGSN ts_CP_ACK_MO := { + cP_ACK := { + cP_messageType := '00000100'B + } +} + +template (value) L3_SMS_MS_SGSN ts_CP_ERROR_MO(OCT1 cause) := { + cP_ERROR := { + cP_messageType := '00010000'B, + cP_Cause := { + causeValue := cause + } + } +} + +template L3_SMS_SGSN_MS tr_CP_DATA_MT(template RPDU_SGSN_MS rpdu) := { + cP_DATA := { + cP_messageType := '00000001'B, + cP_User_Data := { + lengthIndicator := ?, + cP_RPDU := rpdu + } + } +} + +template L3_SMS_SGSN_MS tr_CP_ACK_MT := { + cP_ACK := { + cP_messageType := '00000100'B + } +} + +template L3_SMS_SGSN_MS tr_CP_ERROR_MT(template OCT1 cause) := { + cP_ERROR := { + cP_messageType := '00010000'B, + cP_Cause := { + causeValue := cause + } + } +} + +/* L3 Wrapper */ + +template (value) PDU_ML3_MS_NW ts_ML3_MO_SMS(uint3_t tid, BIT1 ti_flag, + template (value) L3_SMS_MS_SGSN sms_mo) := { + discriminator := '1001'B, + tiOrSkip := { + transactionId := { + tio := int2bit(tid, 3), + tiFlag := ti_flag, + tIExtension := omit + } + }, + msgs := { + sms := sms_mo + } +} + +private function f_tid_or_wc(template uint3_t tid) return template BIT3 { + var template BIT3 ret; + if (istemplatekind(tid, "*")) { + return *; + } else if (istemplatekind(tid, "?")) { + return ?; + } else { + return int2bit(valueof(tid), 3); + } +} + +template PDU_ML3_NW_MS tr_ML3_MT_SMS(template uint3_t tid, template BIT1 ti_flag, + template L3_SMS_SGSN_MS sms_mt) := { + discriminator := '1001'B, + tiOrSkip := { + transactionId := { + tio := f_tid_or_wc(tid), + tiFlag := ti_flag, + tIExtension := omit + } + }, + msgs := { + sms := sms_mt + } +} + + + + } diff --git a/msc/BSC_ConnectionHandler.ttcn b/msc/BSC_ConnectionHandler.ttcn index 73368a2..733daab 100644 --- a/msc/BSC_ConnectionHandler.ttcn +++ b/msc/BSC_ConnectionHandler.ttcn @@ -25,6 +25,7 @@ import from MobileL3_CommonIE_Types all; import from MobileL3_MM_Types all; import from MobileL3_CC_Types all; +import from MobileL3_SMS_Types all; import from L3_Templates all; import from L3_Common all; @@ -186,7 +187,8 @@ type enumerated EstablishType { EST_TYPE_MO_CALL, EST_TYPE_EMERG_CALL, - EST_TYPE_PAG_RESP + EST_TYPE_PAG_RESP, + EST_TYPE_MO_SMS }; /* helper function to fully establish a dedicated channel */ @@ -211,6 +213,9 @@ } case (EST_TYPE_PAG_RESP) { l3_info := valueof(ts_PAG_RESP(mi)); + } + case (EST_TYPE_MO_SMS) { + l3_info := valueof(ts_CM_SERV_REQ(CM_TYPE_MO_SMS, mi)); } } @@ -742,6 +747,146 @@ } } +type record SmsParametersTp { + OCT1 msg_ref, + TP_DA da, + OCT1 pid, + OCT1 dcs, + integer udl, + octetstring ud +} +type record SmsParametersRp { + OCT1 msg_ref, + RP_NumberingPlan_and_NumberDigits orig optional, + RP_NumberingPlan_and_NumberDigits dest optional +} +type record SmsParameters { + SmsParametersTp tp, + SmsParametersRp rp, + uint3_t tid, + OCT1 dlci, + uint7_t exp_rp_err optional +} + +template (value) TP_DA ts_TP_DA(BIT4 npl, BIT3 ton, hexstring addr) := { + tP_DA_NoPad := { + tP_LengthIndicator := 0, /* overwritten */ + tP_NumberingPlanID := npl, + tP_TypeOfNumber := ton, + tp_Spare := '0'B, + tP_DAValue := addr + } +} + +template (value) SmsParameters t_SmsPars(hexstring tp_daddr := '12345'H) := { + tp := { + msg_ref := '23'O, + da := ts_TP_DA('0000'B, '000'B, tp_daddr), + pid := '00'O, + dcs := '00'O, + udl := 0, + ud := ''O + }, + rp := { + msg_ref := '42'O, + orig := omit, + dest := { '0000'B, '000'B, '0'B, '98765'H } + }, + tid := 0, + dlci := '03'O, + exp_rp_err := omit +} + +private altstep as_other_sms() runs on BSC_ConnHdlr { + [] BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_SMS(?, ?, ?), ?)) { + setverdict(fail, "Unexpected SMS related PDU from MSC"); + self.stop; + } +} + +/* Submit a MO-SMS over an already existing (and authenticated, ...) DTAP connection */ +function f_mo_sms(inout SmsParameters spars) +runs on BSC_ConnHdlr { + var template (value) TPDU_RP_DATA_MS_SGSN tp_mo; + var template (value) RPDU_MS_SGSN rp_mo; + var template (value) PDU_ML3_MS_NW l3_mo; + + var template TPDU_RP_DATA_SGSN_MS tp_mt; + var template RPDU_SGSN_MS rp_mt; + var template PDU_ML3_NW_MS l3_mt; + + var default d := activate(as_other_sms()); + + tp_mo := ts_SMS_SUBMIT(spars.tp.msg_ref, spars.tp.da, spars.tp.pid, spars.tp.dcs, + spars.tp.udl, spars.tp.ud); + rp_mo := ts_RP_DATA_MO(spars.rp.msg_ref, spars.rp.orig, spars.rp.dest, tp_mo); + l3_mo := ts_ML3_MO_SMS(spars.tid, c_TIF_ORIG, ts_CP_DATA_MO(rp_mo)); + BSSAP.send(ts_PDU_DTAP_MO(l3_mo, spars.dlci, true)); + /* receive CP-ACK for CP-DATA above */ + BSSAP.receive(tr_PDU_DTAP_MT(tr_ML3_MT_SMS(spars.tid, c_TIF_REPL, tr_CP_ACK_MT), spars.dlci)); + + if (ispresent(spars.exp_rp_err)) { + /* expect an RP-ERROR message from MSC with given cause */ + rp_mt := tr_RP_ERROR_MT(spars.rp.msg_ref, spars.exp_rp_err); + l3_mt := tr_ML3_MT_SMS(spars.tid, c_TIF_REPL, tr_CP_DATA_MT(rp_mt)); + BSSAP.receive(tr_PDU_DTAP_MT(l3_mt, spars.dlci)); + /* send CP-ACK for CP-DATA just received */ + l3_mo := ts_ML3_MO_SMS(spars.tid, c_TIF_ORIG, ts_CP_ACK_MO); + BSSAP.send(ts_PDU_DTAP_MO(l3_mo, spars.dlci, true)); + } else { + /* expect RP-ACK for RP-DATA */ + rp_mt := tr_RP_ACK_MT(spars.rp.msg_ref); + l3_mt := tr_ML3_MT_SMS(spars.tid, c_TIF_REPL, tr_CP_DATA_MT(rp_mt)); + BSSAP.receive(tr_PDU_DTAP_MT(l3_mt, spars.dlci)); + /* send CP-ACO for CP-DATA just received */ + l3_mo := ts_ML3_MO_SMS(spars.tid, c_TIF_ORIG, ts_CP_ACK_MO); + BSSAP.send(ts_PDU_DTAP_MO(l3_mo, spars.dlci, true)); + } + deactivate(d); + setverdict(pass); +} + +/* receive MT-SMS delivered from the MSC/SMSC over an already existing DTAP connection */ +function f_mt_sms(inout SmsParameters spars) +runs on BSC_ConnHdlr { + var template (value) TPDU_RP_DATA_MS_SGSN tp_mo; + var template (value) RPDU_MS_SGSN rp_mo; + var template (value) PDU_ML3_MS_NW l3_mo; + + var template TPDU_RP_DATA_SGSN_MS tp_mt; + var template RPDU_SGSN_MS rp_mt; + var template PDU_ML3_NW_MS l3_mt; + + var PDU_DTAP_MT dtap_mt; + + var default d := activate(as_other_sms()); + + /* Expect CP-DATA(RP-DATA(SMS-DELIVER)) */ + tp_mt := tr_SMS_DELIVER(?, spars.tp.ud, spars.tp.pid, spars.tp.dcs, ?); + rp_mt := tr_RP_DATA_MT(?, ?, omit, tp_mt); + l3_mt := tr_ML3_MT_SMS(?, c_TIF_ORIG, tr_CP_DATA_MT(rp_mt)); + BSSAP.receive(tr_PDU_DTAP_MT(l3_mt, spars.dlci)) -> value dtap_mt; + /* Extract relevant identifiers */ + spars.tid := bit2int(dtap_mt.dtap.tiOrSkip.transactionId.tio); + spars.rp.msg_ref := dtap_mt.dtap.msgs.sms.cP_DATA.cP_User_Data.cP_RPDU.rP_DATA_SGSN_MS.rP_MessageReference; + + /* send CP-ACK for CP-DATA just received */ + l3_mo := ts_ML3_MO_SMS(spars.tid, c_TIF_REPL, ts_CP_ACK_MO); + BSSAP.send(ts_PDU_DTAP_MO(l3_mo, spars.dlci, true)); + + /* send RP-ACK for RP-DATA */ + rp_mo := ts_RP_ACK_MO(spars.rp.msg_ref); + l3_mo := ts_ML3_MO_SMS(spars.tid, c_TIF_REPL, ts_CP_DATA_MO(rp_mo)); + BSSAP.send(ts_PDU_DTAP_MO(l3_mo, spars.dlci, true)); + + /* expect CP-ACK for CP-DATA(RP-ACK) just sent */ + l3_mt := tr_ML3_MT_SMS(spars.tid, c_TIF_REPL, tr_CP_ACK_MT); + BSSAP.receive(tr_PDU_DTAP_MT(l3_mt, spars.dlci)); + + deactivate(d); + setverdict(pass); +} + diff --git a/msc/MSC_Tests.ttcn b/msc/MSC_Tests.ttcn index 503f98b..b5108c7 100644 --- a/msc/MSC_Tests.ttcn +++ b/msc/MSC_Tests.ttcn @@ -1815,6 +1815,77 @@ setverdict(pass); } +/* LU followed by MO SMS */ +private function f_tc_lu_and_mo_sms(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + var SmsParameters spars := valueof(t_SmsPars); + + f_init_handler(pars); + + /* Perform location update and call */ + f_perform_lu(); + + f_establish_fully(EST_TYPE_MO_SMS); + + //spars.exp_rp_err := 96; /* invalid mandatory information */ + f_mo_sms(spars); + + f_expect_clear(); +} +testcase TC_lu_and_mo_sms() runs on MTC_CT { + var BSC_ConnHdlr vc_conn; + f_init(); + vc_conn := f_start_handler(refers(f_tc_lu_and_mo_sms), 42); + vc_conn.done; +} + +private function f_vty_sms_send(charstring imsi, charstring msisdn, charstring text) +runs on MTC_CT { + f_vty_transceive(MSCVTY, "subscriber imsi "&imsi&" sms sender msisdn "&msisdn&" send "&text); +} + +/* LU followed by MT SMS */ +private function f_tc_lu_and_mt_sms(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr { + var SmsParameters spars := valueof(t_SmsPars); + var OCT4 tmsi; + + f_init_handler(pars); + + /* Perform location update and call */ + f_perform_lu(); + + /* register an 'expect' for given IMSI (+TMSI) */ + if (isvalue(g_pars.tmsi)) { + tmsi := g_pars.tmsi; + } else { + tmsi := 'FFFFFFFF'O; + } + f_bssmap_register_imsi(g_pars.imsi, tmsi); + + /* FIXME: actually cause MSC to send a SMS via VTY or SMPP */ + + /* MSC->BSC: expect PAGING from MSC */ + BSSAP.receive(tr_BSSMAP_Paging(g_pars.imsi)); + /* Establish DTAP / BSSAP / SCCP connection */ + f_establish_fully(EST_TYPE_PAG_RESP); + + spars.tp.ud := 'C8329BFD064D9B53'O; + f_mt_sms(spars); + + f_expect_clear(); +} +testcase TC_lu_and_mt_sms() runs on MTC_CT { + var BSC_ConnHdlrPars pars; + var BSC_ConnHdlr vc_conn; + f_init(); + pars := f_init_pars(43); + vc_conn := f_start_handler_with_pars(refers(f_tc_lu_and_mt_sms), pars); + f_sleep(2.0); + f_vty_sms_send(hex2str(pars.imsi), "2342", "Hello SMS"); + vc_conn.done; +} + + + /* TODO: * continue to send repeated MO signalling messages to keep channel open: does MSC tmeout? * malformed messages (missing IE, invalid message type): properly rejected? @@ -1876,6 +1947,9 @@ execute( TC_lu_and_mt_call() ); + execute( TC_lu_and_mo_sms() ); + execute( TC_lu_and_mt_sms() ); + /* Run this last: at the time of writing this test crashes the MSC */ execute( TC_lu_imsi_auth_tmsi_encr_3_1_log_msc_debug() ); } -- To view, visit https://gerrit.osmocom.org/7698 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I707330454ffab87daebf22ba83e6ba2873996424 Gerrit-PatchSet: 1 Gerrit-Project: osmo-ttcn3-hacks Gerrit-Branch: master Gerrit-Owner: Harald Welte <laforge at gnumonks.org>