Review 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 <lafo...@gnumonks.org>
+ * (C) 2017-2018 by Harald Welte <lafo...@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 <lafo...@gnumonks.org>

Reply via email to