From b0d9360aac5b47387371d4654cf9e1b496700d46 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 20 Mar 2018 18:09:34 +0100 Subject: More progress on osmo-sip-connector tests Change-Id: I34a5d7929264c7f5f21d3868a5f919874ffa106c --- library/MNCC_Types.ttcn | 127 +++++++++++++- library/SIP_Emulation.ttcn | 2 +- library/SIP_Templates.ttcn | 413 +++++++++++++++++++++++++++++++++++++++++++++ sip/SIP_Tests.cfg | 2 + sip/SIP_Tests.default | 4 +- sip/SIP_Tests.ttcn | 299 +++++++++++++++++++++++++++----- sip/gen_links.sh | 2 +- 7 files changed, 800 insertions(+), 49 deletions(-) create mode 100644 library/SIP_Templates.ttcn diff --git a/library/MNCC_Types.ttcn b/library/MNCC_Types.ttcn index 39f9dcef..19af2369 100644 --- a/library/MNCC_Types.ttcn +++ b/library/MNCC_Types.ttcn @@ -512,6 +512,39 @@ template MNCC_PDU ts_MNCC_SETUP_req(uint32_t call_id, charstring called, charstr } } }; +template MNCC_PDU tr_MNCC_SETUP_req(template uint32_t call_id := ?, + template charstring called := ?, + template charstring calling := *, + template charstring imsi := ?) := { + msg_type := MNCC_SETUP_REQ, + u := { + signal := { /* See 24.008 9.3.23.1 */ + callref := call_id, + bearer_cap := *, /* mandatory in CC */ + called := tr_MNCC_number(called), /* optional */ + calling := tr_MNCC_number(calling), /* optional */ + redirecting := *, /* optional */ + connected := omit, + cause := omit, + progress := *, /* optional */ + useruser := *, /* optional */ + facility := *, /* optional */ + cccap := omit, + ssversion := omit, + clir_sup := 0, + clir_inv := 0, + signal := *, /* optional */ + keypad := omit, + more := 0, + notify := 0, + emergency := *, + imsi := imsi, + lchan_type := ?, + lchan_mode := ? + } + } +}; + /* MO: MSC <- MNCC: Respons to SETUP.ind */ template MNCC_PDU ts_MNCC_SETUP_rsp(uint32_t call_id, charstring imsi := "", @@ -653,9 +686,9 @@ template MNCC_PDU ts_MNCC_SETUP_CNF(uint32_t call_id, template MNCC_number conne redirecting := omit, connected := connected, cause := omit, - progress := *, - useruser := *, - facility := *, + progress := omit, + useruser := omit, + facility := omit, cccap := omit, ssversion := omit, clir_sup := 0, @@ -664,10 +697,10 @@ template MNCC_PDU ts_MNCC_SETUP_CNF(uint32_t call_id, template MNCC_number conne keypad := omit, more := 0, notify := 0, - emergency := *, + emergency := omit, imsi := "", - lchan_type := ?, - lchan_mode := ? + lchan_type := 0, + lchan_mode := 0 } } } @@ -807,6 +840,39 @@ template MNCC_PDU tr_MNCC_CALL_CONF_ind(template uint32_t call_id, template MNCC } } } +template MNCC_PDU ts_MNCC_CALL_CONF_ind(uint32_t call_id, + template (omit) MNCC_bearer_cap bcap := omit, + template (omit) MNCC_cause cause := omit, + template (omit) MNCC_cccap cccap := omit) := { + msg_type := MNCC_CALL_CONF_IND, + u := { + signal := { /* See 24.008 9.3.2 */ + callref := call_id, + bearer_cap := bcap, + called := omit, + calling := omit, + redirecting := omit, + connected := omit, + cause := cause, + progress := omit, + useruser := omit, + facility := omit, + cccap := cccap, + ssversion := omit, + clir_sup := 0, + clir_inv := 0, + signal := omit, + keypad := omit, + more := 0, + notify := 0, + emergency := omit, + imsi := "", + lchan_type := 0, + lchan_mode := 0 + } + } +} + /* MO: MSC <- MNCC: CALL_PROC.req; call establishment initiated in network */ template MNCC_PDU ts_MNCC_CALL_PROC_req(uint32_t call_id, template MNCC_bearer_cap bcap := omit, @@ -1007,6 +1073,39 @@ template MNCC_PDU tr_MNCC_ALERT_ind(template uint32_t call_id, template MNCC_pro } } } +template (value) MNCC_PDU ts_MNCC_ALERT_ind(uint32_t call_id, + template (omit) MNCC_progress prog := omit, + template (omit) charstring fac := omit, + template (omit) MNCC_useruser uu := omit) := { + msg_type := MNCC_ALERT_IND, + u := { + signal := { /* See 24.008 9.3.1 */ + callref := call_id, + bearer_cap := omit, + called := omit, + calling := omit, + redirecting := omit, + connected := omit, + cause := omit, + progress := prog, + useruser := uu, + facility := fac, + cccap := omit, + ssversion := omit, + clir_sup := 0, + clir_inv := 0, + signal := omit, + keypad := omit, + more := 0, + notify := 0, + emergency := omit, + imsi := "", + lchan_type := 0, + lchan_mode := 0 + } + } +} + /* : MSC <- MNCC: NOTIFY.req; request to send information pertaining to a call (such as user suspended) */ template MNCC_PDU ts_MNCC_NOTIFY_req(uint32_t call_id, MNCC_notify notify) := { @@ -1794,6 +1893,22 @@ template MNCC_PDU ts_MNCC_RTP_CONNECT(uint32_t call_id, uint32_t ip, uint32_t rt } } } +template MNCC_PDU tr_MNCC_RTP_CONNECT(template uint32_t call_id, + template uint32_t ip := ?, + template uint32_t rtp_port := ?, + template uint32_t pt := ?) := { + msg_type := MNCC_RTP_CONNECT, + u := { + rtp := { + callref := call_id, + ip := ip, + rtp_port := rtp_port, + payload_type := pt, + payload_msg_type := 0 + } + } +} + /* MSC <- MNCC: RTP_FREE.req; request connect of RTP */ template MNCC_PDU ts_MNCC_RTP_FREE(uint32_t call_id) := ts_MNCC_SIMPLE_RTP(MNCC_RTP_FREE, call_id); diff --git a/library/SIP_Emulation.ttcn b/library/SIP_Emulation.ttcn index 57ec7043..3957b8f1 100644 --- a/library/SIP_Emulation.ttcn +++ b/library/SIP_Emulation.ttcn @@ -70,7 +70,7 @@ template RequestLine tr_ReqLine(template Method method) := { sipVersion := ? } -template PDU_SIP_Request tr_SIP_INVITE := { +private template PDU_SIP_Request tr_SIP_INVITE := { requestLine := tr_ReqLine(INVITE_E), msgHeader := t_SIP_msgHeader_any, messageBody := *, diff --git a/library/SIP_Templates.ttcn b/library/SIP_Templates.ttcn new file mode 100644 index 00000000..75681a91 --- /dev/null +++ b/library/SIP_Templates.ttcn @@ -0,0 +1,413 @@ +module SIP_Templates { + +import from SIPmsg_Types all; + +/* wrapper type to encapsulate the Addr_Union + parameter list used in From, To. ... */ +type record SipAddr { + Addr_Union addr, + SemicolonParam_List params optional +} + +const charstring c_SIP_VERSION := "SIP/2.0"; + +template (value) SipUrl ts_SipUrl(charstring user_or_tel, charstring host, integer portnr) := { + scheme := "sip", + userInfo := { + userOrTelephoneSubscriber := user_or_tel, + password := omit + }, + hostPort := { + host := host, + portField := portnr + }, + urlParameters := omit, + headers := omit +} +template SipUrl tr_SipUrl(template charstring user_or_tel, + template charstring host, + template integer portnr) := { + scheme := "sip", + userInfo := { + userOrTelephoneSubscriber := user_or_tel, + password := * + }, + hostPort := { + host := host, + portField := portnr + }, + urlParameters := *, + headers := * +} + +template (value) SipAddr ts_SipAddr(charstring user_or_tel, charstring host, integer portnr) := { + addr := { + nameAddr := { + displayName := omit, + addrSpec := ts_SipUrl(user_or_tel, host, portnr) + } + }, + params := omit +} +template SipAddr tr_SipAddr(template charstring user_or_tel, + template charstring host, + template integer portnr) := { + addr := { + nameAddr := { + displayName := *, + addrSpec := tr_SipUrl(user_or_tel, host, portnr) + } + }, + params := * +} + +/* build a receive template from a value: substitute '*' for omit */ +function tr_SipAddr_from_val(SipAddr tin) return template SipAddr { + var template SipAddr ret := tin; + if (tin.addr.nameAddr.displayName == omit) { + ret.addr.nameAddr.displayName := *; + } + if (tin.addr.nameAddr.addrSpec.userInfo.password == omit) { + ret.addr.nameAddr.addrSpec.userInfo.password := *; + } + if (tin.params == omit) { + ret.params := *; + } + return ret; +} + + +function tr_HostPort(template HostPort hp) return template HostPort { + var template HostPort hpout := hp; + /* if the port number is 5060, it may be omitted */ + if (isvalue(hp.portField) and valueof(hp.portField) == 5060) { + hpout.portField := 5060 ifpresent; + } + return hpout; +} + +template (value) RequestLine ts_SIP_ReqLine(Method method, template (value) SipUrl uri, + charstring ver := c_SIP_VERSION) := { + method := method, + requestUri := uri, + sipVersion := ver +} +template RequestLine tr_SIP_ReqLine(template Method method, + template SipUrl uri, + template charstring ver := c_SIP_VERSION) := { + method := method, + requestUri := uri, + sipVersion := ver +} + +template (value) StatusLine ts_SIP_StatusLine(integer status_code, charstring reason) := { + sipVersion := "SIP/2.0", + statusCode := status_code, + reasonPhrase := reason +} +template StatusLine tr_SIP_StatusLine(template integer status_code, template charstring reason) := { + sipVersion := "SIP/2.0", + statusCode := status_code, + reasonPhrase := reason +} + + +template (value) PDU_SIP_Request ts_SIP_req(template (value) RequestLine rl) := { + requestLine := rl, + msgHeader := c_SIP_msgHeader_empty, + messageBody := omit, + payload := omit +} + +const Method_List c_SIP_defaultMethods := { + "INVITE", "ACK", "BYE", "CANCEL", "OPTIONS", "PRACK", "MESSAGE", "SUBSCRIBE", + "NOTIFY", "REFER", "UPDATE" }; + +private function f_ContentTypeOrOmit(template (omit) ContentType ct, template (omit) charstring body) +return template (omit) ContentType { + /* if user explicitly stated no content type */ + if (istemplatekind(ct, "omit")) { + return omit; + } + /* if there's no body, then there's no content-type either */ + if (istemplatekind(body, "omit")) { + return omit; + } + return ct; +} + +template (value) ContentType ts_CT_SDP := { + fieldName := CONTENT_TYPE_E, + mediaType := "application/sdp" +}; + +template (value) Via ts_Via_from(SipAddr from_addr) := { + fieldName := VIA_E, + viaBody := { + { + sentProtocol := { "SIP", "2.0", "UDP" }, + sentBy := from_addr.addr.nameAddr.addrSpec.hostPort, + viaParams := omit + } + } +} + +template (value) MessageHeader ts_SIP_msgHeader_empty :=c_SIP_msgHeader_empty; +template (value) MessageHeader ts_SIP_msgh_std( CallidString call_id, + SipAddr from_addr, + SipAddr to_addr, + template (omit) SipAddr contact_addr, + charstring method, + integer seq_nr, + template (value) Via via, + template (omit) ContentType content_type := omit, + Method_List allow_methods := c_SIP_defaultMethods + ) modifies ts_SIP_msgHeader_empty := { + allow := { + fieldName := ALLOW_E, + methods := allow_methods + }, + callId := { + fieldName := CALL_ID_E, + callid := call_id + }, + contact := ts_Contact(contact_addr), + contentType := content_type, + cSeq := { + fieldName := CSEQ_E, + seqNumber := seq_nr, + method := method + }, + fromField := { + fieldName := FROM_E, + addressField := from_addr.addr, + fromParams := from_addr.params + }, + toField := { + fieldName := TO_E, + addressField := to_addr.addr, + toParams := to_addr.params + }, + userAgent := { + fieldName := USER_AGENT_E, + userAgentBody := { + "osmo-ttcn3-hacks/0.23" + } + }, + via := via +} + +private function tr_Contact(template SipAddr contact_addr) return template Contact +{ + if (istemplatekind(contact_addr, "omit")) { + return omit; + } else if (istemplatekind(contact_addr, "*")) { + return *; + } else if (istemplatekind(contact_addr, "?")) { + return ?; + } + var template Contact ret := { + fieldName := CONTACT_E, + contactBody := { + contactAddresses := { + { + addressField := contact_addr.addr, + contactParams := contact_addr.params + } + } + } + }; + return ret; +} + +private function ts_Contact(template (omit) SipAddr contact_addr) return template (omit) Contact +{ + if (istemplatekind(contact_addr, "omit")) { + return omit; + } + var template (omit) Contact ret := { + fieldName := CONTACT_E, + contactBody := { + contactAddresses := { + { + addressField := contact_addr.addr, + contactParams := contact_addr.params + } + } + } + }; + return ret; +} + + +function tr_AllowMethods(template Method_List allow_methods) return template Allow { + if (istemplatekind(allow_methods, "omit")) { + return omit; + } else if (istemplatekind(allow_methods, "*")) { + return *; + } else if (istemplatekind(allow_methods, "?")) { + return ?; + } + var template Allow ret := { + fieldName := ALLOW_E, + methods := allow_methods + } + return ret +} + +template MessageHeader tr_SIP_msgh_std( template CallidString call_id, + template SipAddr from_addr, + template SipAddr to_addr, + template SipAddr contact_addr, + template charstring method, + template ContentType content_type := *, + template integer seq_nr := ?, + template Method_List allow_methods := * + ) modifies t_SIP_msgHeader_any := { + allow := tr_AllowMethods(allow_methods), + callId := { + fieldName := CALL_ID_E, + callid := call_id + }, + contact := tr_Contact(contact_addr), + contentType := content_type, + cSeq := { + fieldName := CSEQ_E, + seqNumber := seq_nr, + method := method + }, + fromField := { + fieldName := FROM_E, + addressField := from_addr.addr, + fromParams := from_addr.params + }, + toField := { + fieldName := TO_E, + addressField := to_addr.addr, + toParams := to_addr.params + }, + userAgent := *, + via := { + fieldName := VIA_E, + viaBody := { + { + sentProtocol := { "SIP", "2.0", "UDP" }, + sentBy := tr_HostPort(from_addr.addr.nameAddr.addrSpec.hostPort), + viaParams := * + } + } + } +} + + +template (value) PDU_SIP_Request ts_SIP_INVITE( CallidString call_id, + SipAddr from_addr, + SipAddr to_addr, + integer seq_nr, + template (omit) charstring body + ) := { + requestLine := ts_SIP_ReqLine(INVITE_E, to_addr.addr.nameAddr.addrSpec), + msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, from_addr, "INVITE", seq_nr, + ts_Via_from(from_addr), f_ContentTypeOrOmit(ts_CT_SDP, body)), + messageBody := body, + payload := omit +} +template PDU_SIP_Request tr_SIP_INVITE( template CallidString call_id, + template SipAddr from_addr, + template SipAddr to_addr, + template integer seq_nr, + template charstring body + ) := { + requestLine := tr_SIP_ReqLine(INVITE_E, to_addr.addr.nameAddr.addrSpec), + msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, ?, "INVITE", *, seq_nr), + messageBody := body, + payload := omit +} + +template (value) PDU_SIP_Request ts_SIP_BYE( CallidString call_id, + SipAddr from_addr, + SipAddr to_addr, + integer seq_nr, + template (omit) charstring body + ) := { + requestLine := ts_SIP_ReqLine(BYE_E, to_addr.addr.nameAddr.addrSpec), + msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, "BYE", seq_nr, + ts_Via_from(from_addr), f_ContentTypeOrOmit(ts_CT_SDP, body)), + messageBody := body, + payload := omit +} + +template PDU_SIP_Request tr_SIP_BYE( template CallidString call_id, + template SipAddr from_addr, + template SipAddr to_addr, + template integer seq_nr, + template charstring body + ) := { + requestLine := tr_SIP_ReqLine(BYE_E, to_addr.addr.nameAddr.addrSpec), + msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, omit, "BYE", *, seq_nr), + messageBody := body, + payload := omit +} + + +template (value) PDU_SIP_Request ts_SIP_ACK( CallidString call_id, + SipAddr from_addr, + SipAddr to_addr, + integer seq_nr, + template (omit) charstring body + ) := { + requestLine := ts_SIP_ReqLine(ACK_E, to_addr.addr.nameAddr.addrSpec), + msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, from_addr, "ACK", seq_nr, + ts_Via_from(from_addr), f_ContentTypeOrOmit(ts_CT_SDP, body)), + messageBody := body, + payload := omit +} +template PDU_SIP_Request tr_SIP_ACK( template CallidString call_id, + template SipAddr from_addr, + template SipAddr to_addr, + template integer seq_nr, + template charstring body + ) := { + requestLine := tr_SIP_ReqLine(ACK_E, to_addr.addr.nameAddr.addrSpec), + msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, *, "ACK", *, seq_nr), + messageBody := body, + payload := omit +} + + + +template (value) PDU_SIP_Response ts_SIP_Response( CallidString call_id, + SipAddr from_addr, + SipAddr to_addr, + charstring method, + integer status_code, + integer seq_nr, + charstring reason, + Via via, + template (omit) charstring body := omit + ) := { + statusLine := ts_SIP_StatusLine(status_code, reason), + msgHeader := ts_SIP_msgh_std(call_id, from_addr, to_addr, omit, method, seq_nr, + via, f_ContentTypeOrOmit(ts_CT_SDP, body)), + messageBody := body, + payload := omit +} + +template PDU_SIP_Response tr_SIP_Response( template CallidString call_id, + template SipAddr from_addr, + template SipAddr to_addr, + template SipAddr contact_addr, + template charstring method, + template integer status_code, + template integer seq_nr := ?, + template charstring reason := ?, + template charstring body := ? + ) := { + statusLine := tr_SIP_StatusLine(status_code, reason), + msgHeader := tr_SIP_msgh_std(call_id, from_addr, to_addr, contact_addr, method, *, seq_nr), + messageBody := body, + payload := omit +} + + + +} diff --git a/sip/SIP_Tests.cfg b/sip/SIP_Tests.cfg index db435afd..222d3a1b 100644 --- a/sip/SIP_Tests.cfg +++ b/sip/SIP_Tests.cfg @@ -7,6 +7,8 @@ # Local configuration below [LOGGING] +"SIP_Test-SIP".FileMask := ERROR | WARNING +"SIP_Test-MNCC".FileMask := ERROR | WARNING [TESTPORT_PARAMETERS] diff --git a/sip/SIP_Tests.default b/sip/SIP_Tests.default index b0abf189..5f7de905 100644 --- a/sip/SIP_Tests.default +++ b/sip/SIP_Tests.default @@ -13,7 +13,7 @@ mtc.FileMask := ERROR | WARNING; *.SIPVTY.CTRL_DETECT_SERVER_DISCONNECTED := "yes" *.SIPVTY.CTRL_READMODE := "buffered" *.SIPVTY.CTRL_CLIENT_CLEANUP_LINEFEED := "yes" -*.SIPVTY.PROMPT1 := "OsmoMNCC> " +*.SIPVTY.PROMPT1 := "OsmoSIPcon> " *.SIP.local_sip_port := "5060" *.SIP.default_local_address := "127.0.0.2" @@ -23,7 +23,7 @@ mtc.FileMask := ERROR | WARNING; [MODULE_PARAMETERS] -Osmocom_VTY_Functions.mp_prompt_prefix := "OsmoMNCC"; +Osmocom_VTY_Functions.mp_prompt_prefix := "OsmoSIPcon"; [MAIN_CONTROLLER] diff --git a/sip/SIP_Tests.ttcn b/sip/SIP_Tests.ttcn index de2f4987..f690dc70 100644 --- a/sip/SIP_Tests.ttcn +++ b/sip/SIP_Tests.ttcn @@ -17,9 +17,10 @@ import from SDP_Types all; import from SIP_Emulation all; import from SIPmsg_Types all; +import from SIP_Templates all; modulepar { - //charstring mp_local_host := "127.0.0.2; + charstring mp_local_host := "127.0.0.2"; charstring mp_osmosip_host := "127.0.0.1"; integer mp_osmosip_port_ctrl := -1; /* RFU */ charstring mp_mncc := "/tmp/mncc"; @@ -38,7 +39,48 @@ type component ConnHdlr extends SIP_ConnHdlr, MNCC_ConnHdlr { } type record ConnHdlrPars { - float t_guard + float t_guard, + CallPars g_cp optional +} + +type record CallPars { + boolean is_mo, + charstring calling, + charstring called, + + uint32_t mncc_call_id optional, + + CallParsComputed comp optional +} + +type record CallParsComputed { + CallidString sip_call_id, + SipAddr sip_url_ext, + SipAddr sip_url_gsm, + charstring sip_body, + integer sip_seq_nr +} + +private template (value) CallPars t_CallPars(boolean is_mo) := { + is_mo := is_mo, + calling := "12345", + called := "98766", + mncc_call_id := omit, + comp := omit +} + +private function f_CallPars_compute(inout CallPars cp) { + if (cp.is_mo) { + cp.comp.sip_url_ext := valueof(ts_SipAddr(cp.called, mp_local_host, 5060)); + cp.comp.sip_url_gsm := valueof(ts_SipAddr(cp.calling, mp_osmosip_host, 5060)); + cp.mncc_call_id := f_rnd_int(429496725); + } else { + cp.comp.sip_url_ext := valueof(ts_SipAddr(cp.calling, mp_local_host, 5060)); + cp.comp.sip_url_gsm := valueof(ts_SipAddr(cp.called, mp_osmosip_host, 5060)); + cp.comp.sip_call_id := hex2str(f_rnd_hexstring(15)); + } + cp.comp.sip_seq_nr := f_rnd_int(4294967295); + cp.comp.sip_body := ""; } @@ -105,67 +147,246 @@ runs on ConnHdlr { template (value) ConnHdlrPars t_Pars := { - t_guard := 30.0 + t_guard := 30.0, + g_cp := omit } -private function f_TC_mo_setup(charstring id) runs on ConnHdlr { +/* Establish a mobile terminated call described in 'cp' */ +function f_establish_mt(inout CallPars cp) runs on ConnHdlr { + var template SipAddr sip_addr_gsm := tr_SipAddr_from_val(cp.comp.sip_url_gsm); + var template SipAddr sip_addr_ext := tr_SipAddr_from_val(cp.comp.sip_url_ext); var PDU_SIP_Request sip_req; + var MNCC_PDU mncc; + + /* Ask MNCC_Emulation to "expect" a call to the given called number */ + f_create_mncc_expect(cp.called); + + /* OSC <- SIP: A party sends SIP invite for a MT-call into OSC */ + SIP.send(ts_SIP_INVITE(cp.comp.sip_call_id, cp.comp.sip_url_ext, cp.comp.sip_url_gsm, + cp.comp.sip_seq_nr, cp.comp.sip_body)); + /* MSC <- OSC: OSC generates MNCC_SETUP_REQ from INVITE */ + MNCC.receive(tr_MNCC_SETUP_req) -> value mncc { + cp.mncc_call_id := mncc.u.signal.callref; + } + /* OSC -> SIP */ + SIP.receive(tr_SIP_Response(cp.comp.sip_call_id, sip_addr_ext, sip_addr_gsm, *, + "INVITE", 100, ?, "Trying", *)); + + /* MSC -> OSC: After MS sends CALL CONF in response to SETUP */ + MNCC.send(ts_MNCC_CALL_CONF_ind(cp.mncc_call_id)); + /* MSC <- OSC: OSC asks MSC to create RTP socket */ + MNCC.receive(tr_MNCC_RTP_CREATE(cp.mncc_call_id)); + MNCC.send(ts_MNCC_RTP_CREATE(cp.mncc_call_id)); + + /* MSC -> OSC: After MS is ringing and sent CC ALERTING */ + MNCC.send(ts_MNCC_ALERT_ind(cp.mncc_call_id)); + SIP.clear; + SIP.receive(tr_SIP_Response(cp.comp.sip_call_id, sip_addr_ext, sip_addr_gsm, *, + "INVITE", 180, ?, "Ringing", *)); + + /* MSC -> OSC: After MT user has picked up and sent CC CONNECT */ + MNCC.send(ts_MNCC_SETUP_CNF(cp.mncc_call_id)); + + SIP.clear; + interleave { + /* MSC <- OSC: OSC asks MSC to connect its RTP stream to remote end */ + [] MNCC.receive(tr_MNCC_RTP_CONNECT(cp.mncc_call_id)) {} + /* OSC -> SIP: OSC confirms call establishment to SIP side */ + [] SIP.receive(tr_SIP_Response(cp.comp.sip_call_id, sip_addr_ext, sip_addr_gsm, ?, + "INVITE", 200, ?, "OK", ?)) {} + } + /* OSC <- SIP: SIP world acknowledges "200 OK" */ + SIP.send(ts_SIP_ACK(cp.comp.sip_call_id, cp.comp.sip_url_ext, cp.comp.sip_url_gsm, + cp.comp.sip_seq_nr, omit)); + /* MSC <- OSC: OSC sends SETUP COMPL to MNCC (which triggers CC CONNECT ACK */ + MNCC.receive(tr_MNCC_SETUP_COMPL_req(cp.mncc_call_id)); +} - var MNCC_number dst := valueof(ts_MNCC_number("01234567")); - var MNCC_number src := valueof(ts_MNCC_number("112")); - - f_create_sip_expect(valueof(ts_SIP_Url("+01234567"))); - - log("sending mncc setup"); - MNCC.send(ts_MNCC_SETUP_ind(2342, dst, src, "262420123456789")); - - MNCC.receive(tr_MNCC_RTP_CREATE(2342)); - MNCC.send(ts_MNCC_RTP_CREATE(2342)); +/* Establish a mobile originated call described in 'cp' */ +function f_establish_mo(inout CallPars cp) runs on ConnHdlr { + var MNCC_number dst := valueof(ts_MNCC_number(cp.called, GSM48_TON_UNKNOWN)); + var MNCC_number src := valueof(ts_MNCC_number(cp.calling, GSM48_TON_UNKNOWN)); + var template SipAddr sip_addr_gsm := tr_SipAddr_from_val(cp.comp.sip_url_gsm); + var template SipAddr sip_addr_ext := tr_SipAddr_from_val(cp.comp.sip_url_ext); + var PDU_SIP_Request sip_req; + var integer seq_nr; + + f_create_sip_expect(cp.comp.sip_url_ext.addr.nameAddr.addrSpec); + + /* MSC -> OSC: MSC sends SETUP.ind after CC SETUP was received from MS */ + MNCC.send(ts_MNCC_SETUP_ind(cp.mncc_call_id, dst, src, "262420123456789")); + /* MSC <- OSC: Create GSM side RTP socket */ + MNCC.receive(tr_MNCC_RTP_CREATE(cp.mncc_call_id)) { + var MNCC_PDU mncc := valueof(ts_MNCC_RTP_CREATE(cp.mncc_call_id)); + mncc.u.rtp.payload_msg_type := oct2int('0300'O); + MNCC.send(mncc); /* FIXME: port/ip */ + } + /* OSC -> SIP: Send INVITE with GSM side IP/Port in SDP */ + SIP.receive(tr_SIP_INVITE(?, sip_addr_gsm, sip_addr_ext, ?, ?)) -> value sip_req { + cp.comp.sip_url_gsm.params := sip_req.msgHeader.fromField.fromParams; + cp.comp.sip_call_id := sip_req.msgHeader.callId.callid; + seq_nr := sip_req.msgHeader.cSeq.seqNumber; + } + /* OSC <- SIP: Notify call is proceeding */ + SIP.send(ts_SIP_Response(cp.comp.sip_call_id, cp.comp.sip_url_gsm, cp.comp.sip_url_ext, + "INVITE", 100, seq_nr, "Trying", sip_req.msgHeader.via)); + /* MSC <- OSC: "100 Trying" translated to MNCC_CALL_PROC_REQ */ + MNCC.receive(tr_MNCC_CALL_PROC_req(cp.mncc_call_id)); + + /* OSC <- SIP: SIP-terminated user is ringing now */ + SIP.send(ts_SIP_Response(cp.comp.sip_call_id, cp.comp.sip_url_gsm, cp.comp.sip_url_ext, + "INVITE", 180, seq_nr, "Ringing", sip_req.msgHeader.via)); + + /* MSC <- OSC: "180 Ringing" translated to MNCC_ALERT_REQ */ + MNCC.receive(tr_MNCC_ALERT_req(cp.mncc_call_id)) {} + + /* OSC <- SIP: SIP-terminated user has accepted the call */ + SIP.send(ts_SIP_Response(cp.comp.sip_call_id, cp.comp.sip_url_gsm, cp.comp.sip_url_ext, + "INVITE", 200, seq_nr, "OK", sip_req.msgHeader.via, + cp.comp.sip_body)); + MNCC.receive(tr_MNCC_RTP_CONNECT(cp.mncc_call_id)); + /* MSC <- OSC: "200 OK" translated to MNCC_SETUP_RSP */ + MNCC.receive(tr_MNCC_SETUP_rsp(cp.mncc_call_id)); + + /* MSC -> OSC: CC CONNECT ACK was received from MS */ + MNCC.send(ts_MNCC_SETUP_COMPL_ind(cp.mncc_call_id)); + /* OSC -> SIP: Acknowledge the call */ + SIP.receive(tr_SIP_ACK(cp.comp.sip_call_id, sip_addr_gsm, sip_addr_ext, ?, omit)); +} - SIP.receive(PDU_SIP_Request:?) -> value sip_req { - log(sip_req); +/* Release call from the mobile side */ +function f_release_mobile(inout CallPars cp) runs on ConnHdlr { + var template SipAddr sip_addr_gsm := tr_SipAddr_from_val(cp.comp.sip_url_gsm); + var template SipAddr sip_addr_ext := tr_SipAddr_from_val(cp.comp.sip_url_ext); + var PDU_SIP_Request sip_req; + SIP.clear; + /* MSC -> OSC: Simulate a CC DISCONNET from the MT user */ + MNCC.send(ts_MNCC_DISC_ind(cp.mncc_call_id, ts_MNCC_cause(0))); + /* OSC -> SIP: Expect BYE from OSC to SIP side */ + SIP.receive(tr_SIP_BYE(cp.comp.sip_call_id, sip_addr_gsm, sip_addr_ext, ?, *)) -> value sip_req { + cp.comp.sip_url_gsm.params := sip_req.msgHeader.fromField.fromParams; } + /* OSC <- SIP: Acknowledge the BYE */ + SIP.send(ts_SIP_Response(cp.comp.sip_call_id, cp.comp.sip_url_gsm, cp.comp.sip_url_ext, + "BYE", 200, sip_req.msgHeader.cSeq.seqNumber, "OK", + sip_req.msgHeader.via)); + /* MSC <- OSC: Send REL_REQ to MSC, triggers CC RELEASE REQ to MS */ + MNCC.receive(tr_MNCC_REL_req(cp.mncc_call_id)); // CAUSE? + /* MSC -> OSC: MS has responded with CC CLEAR COMPL, triggers MNCC_REL_CNF */ + MNCC.send(ts_MNCC_REL_cnf(cp.mncc_call_id, ts_MNCC_cause(0))); +} + +/* Release call from the SIP side */ +function f_release_sip(inout CallPars cp) runs on ConnHdlr { + var template SipAddr sip_addr_gsm := tr_SipAddr_from_val(cp.comp.sip_url_gsm); + var template SipAddr sip_addr_ext := tr_SipAddr_from_val(cp.comp.sip_url_ext); + /* OSC <- SIP: SIP-side sends a BYE to OSC */ + SIP.send(ts_SIP_BYE(cp.comp.sip_call_id, cp.comp.sip_url_ext, cp.comp.sip_url_gsm, + cp.comp.sip_seq_nr, omit)); + /* MSC <- OSC: Expect OSC to cause MNCC Disconnect Request */ + MNCC.receive(tr_MNCC_DISC_req(cp.mncc_call_id)); + /* MSC -> OSC: Indicate GSM side release */ + MNCC.send(ts_MNCC_REL_ind(cp.mncc_call_id, ts_MNCC_cause(0))); + /* OSC -> SIP: Confirmation to SIP side */ + SIP.receive(tr_SIP_Response(cp.comp.sip_call_id, sip_addr_ext, sip_addr_gsm, *, + "BYE", 200, cp.comp.sip_seq_nr, "OK", omit)); } -testcase TC_mo_setup() runs on test_CT { +/* Successful MT Call, which is subsequently released by GSM side */ +private function f_TC_mt_success_rel_gsm(charstring id) runs on ConnHdlr { + var CallPars cp := valueof(t_CallPars(false)); + f_CallPars_compute(cp); + cp.comp.sip_body := "v=0\r\no=Osmocom 0 0 IN IP4 0.0.0.0\r\ns=GSM Call\r\nc=IN IP4 0.0.0.0\r\nt=0 0\r\nm=audio 0 RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n"; + f_sleep(3.0) + + f_establish_mt(cp); + /* now call is fully established */ + f_sleep(2.0); + f_release_mobile(cp); + setverdict(pass); +} +testcase TC_mt_success_rel_gsm() runs on test_CT { var ConnHdlrPars pars; var ConnHdlr vc_conn; - f_init(); - pars := valueof(t_Pars); - vc_conn := f_start_handler(refers(f_TC_mo_setup), pars); + vc_conn := f_start_handler(refers(f_TC_mt_success_rel_gsm), pars); vc_conn.done; } +/* Successful MT Call, which is subsequently released by SIP side */ +private function f_TC_mt_success_rel_sip(charstring id) runs on ConnHdlr { + var CallPars cp := valueof(t_CallPars(false)); + f_CallPars_compute(cp); + cp.comp.sip_body := "v=0\r\no=Osmocom 0 0 IN IP4 0.0.0.0\r\ns=GSM Call\r\nc=IN IP4 0.0.0.0\r\nt=0 0\r\nm=audio 0 RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n"; + f_sleep(3.0) + + f_establish_mt(cp); + /* now call is fully established */ + f_sleep(2.0); + f_release_sip(cp); + setverdict(pass); +} +testcase TC_mt_success_rel_sip() runs on test_CT { + var ConnHdlrPars pars; + var ConnHdlr vc_conn; + f_init(); + pars := valueof(t_Pars); + vc_conn := f_start_handler(refers(f_TC_mt_success_rel_sip), pars); + vc_conn.done; +} +/* Successful MO Call, which is subsequently released by GSM side */ +private function f_TC_mo_success_rel_gsm(charstring id) runs on ConnHdlr { + var CallPars cp := valueof(t_CallPars(true)); + f_CallPars_compute(cp); + cp.comp.sip_body := "v=0\r\no=Osmocom 0 0 IN IP4 0.0.0.0\r\ns=GSM Call\r\nc=IN IP4 0.0.0.0\r\nt=0 0\r\nm=audio 0 RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n"; + f_sleep(3.0) - -/* SIP specifics */ - -const integer c_SIP_PORT := 5060; - -template (value) SIP_comm_adress ts_SipAddr(charstring rhost, - template (omit) charstring lhost := omit, - integer rport := c_SIP_PORT, - integer lport := c_SIP_PORT, - SIP_com_prot prot := UDP_E) := { - remote_host := rhost, - remote_port := rport, - local_host := lhost, - local_port := lport, - protocol := prot + f_establish_mo(cp); + /* now call is fully established */ + f_sleep(2.0); + f_release_mobile(cp); + setverdict(pass); } - -template (value) ASP_SIP_open ts_SIP_open(SIP_comm_adress addr) := { - addr := addr +testcase TC_mo_success_rel_gsm() runs on test_CT { + var ConnHdlrPars pars; + var ConnHdlr vc_conn; + f_init(); + pars := valueof(t_Pars); + vc_conn := f_start_handler(refers(f_TC_mo_success_rel_gsm), pars); + vc_conn.done; } +/* Successful MO Call, which is subsequently released by SIP side */ +private function f_TC_mo_success_rel_sip(charstring id) runs on ConnHdlr { + var CallPars cp := valueof(t_CallPars(true)); + f_CallPars_compute(cp); + cp.comp.sip_body := "v=0\r\no=Osmocom 0 0 IN IP4 0.0.0.0\r\ns=GSM Call\r\nc=IN IP4 0.0.0.0\r\nt=0 0\r\nm=audio 0 RTP/AVP 0\r\na=rtpmap:0 GSM/8000\r\n"; + f_sleep(3.0) + + f_establish_mo(cp); + /* now call is fully established */ + f_sleep(2.0); + f_release_sip(cp); + setverdict(pass); +} +testcase TC_mo_success_rel_sip() runs on test_CT { + var ConnHdlrPars pars; + var ConnHdlr vc_conn; + f_init(); + pars := valueof(t_Pars); + vc_conn := f_start_handler(refers(f_TC_mo_success_rel_sip), pars); + vc_conn.done; +} control { - execute( TC_mo_setup() ); + execute( TC_mt_success_rel_gsm() ); + execute( TC_mt_success_rel_sip() ); + execute( TC_mo_success_rel_gsm() ); + execute( TC_mo_success_rel_sip() ); } diff --git a/sip/gen_links.sh b/sip/gen_links.sh index ff640560..37c0a70f 100755 --- a/sip/gen_links.sh +++ b/sip/gen_links.sh @@ -43,7 +43,7 @@ FILES="General_Types.ttcn GSM_Types.ttcn Osmocom_Types.ttcn MNCC_Types.ttcn MNCC FILES+="IPA_Types.ttcn IPA_Emulation.ttcnpp IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc " FILES+="Osmocom_CTRL_Types.ttcn Osmocom_CTRL_Functions.ttcn Osmocom_CTRL_Adapter.ttcn " FILES+="RTP_CodecPort.ttcn RTP_CodecPort_CtrlFunctDef.cc " -FILES+="SIP_Emulation.ttcn " +FILES+="SIP_Emulation.ttcn SIP_Templates.ttcn " gen_links $DIR $FILES ignore_pp_results -- cgit v1.2.3