diff --git a/library/Osmocom_Gb_Types.ttcn b/library/Osmocom_Gb_Types.ttcn index 86b4d4991..a0242c3e2 100644 --- a/library/Osmocom_Gb_Types.ttcn +++ b/library/Osmocom_Gb_Types.ttcn @@ -116,6 +116,41 @@ module Osmocom_Gb_Types { return ret; } + function ts_SNS_IP_ADDR(template (omit) IPAddress ip) return template (omit) IP_Address_NS { + var template (omit) IP_Address_NS ret; + if (istemplatekind(ip, "omit")) { + return omit; + } else { + ret.iEI := '0B'O; + ret.ipAddress := ip; + if (ischosen(ip.ip4Address)) { + ret.addressType := '01'O; + } else { + ret.addressType := '02'O; + } + } + return ret; + } + function tr_SNS_IP_ADDR(template IPAddress ip) return template IP_Address_NS { + var template IP_Address_NS ret; + ret.iEI := '0B'O; + if (istemplatekind(ip, "omit")) { + return omit; + } else if (istemplatekind(ip, "*")) { + return *; + } else if (istemplatekind(ip, "?")) { + return ?; + } else { + ret.ipAddress := ip; + if (ischosen(ip.ip4Address)) { + ret.addressType := '01'O; + } else { + ret.addressType := '02'O; + } + } + return ret; + } + private function f_oct_or_wc(template integer inp, integer len) return template octetstring { if (istemplatekind(inp, "omit")) { return omit; @@ -475,6 +510,8 @@ octetstring sdu) := { var template ListofIP6Elements r; if (istemplatekind(elem, "omit")) { return omit; + } else if (istemplatekind(elem, "*")) { + return *; } else { r := { iEI := '06'O, @@ -526,6 +563,92 @@ octetstring sdu) := { } } + template (value) PDU_NS ts_SNS_ADD(Nsei nsei, uint8_t trans_id, + template (omit) IP4_Elements v4, + template (omit) IP6_Elements v6 := omit) := { + pDU_SNS_Add := { + nsPduType := '0D'O, + nSEI_NS := ts_NS_IE_NSEI(nsei), + transactionID := trans_id, + listofIP4Elements := ts_SNS_IE_ListIP4(v4), + listofIP6Elements := ts_SNS_IE_ListIP6(v6) + } + } + template PDU_NS tr_SNS_ADD(template Nsei nsei, template uint8_t trans_id, + template IP4_Elements v4, + template IP6_Elements v6 := omit) := { + pDU_SNS_Add := { + nsPduType := '0D'O, + nSEI_NS := tr_NS_IE_NSEI(nsei), + transactionID := trans_id, + listofIP4Elements := tr_SNS_IE_ListIP4(v4), + listofIP6Elements := tr_SNS_IE_ListIP6(v6) + } + } + + template (value) PDU_NS ts_SNS_DEL(Nsei nsei, uint8_t trans_id, + template (omit) IPAddress ip_sns, + template (omit) IP4_Elements v4, + template (omit) IP6_Elements v6 := omit) := { + pDU_SNS_Delete := { + nsPduType := '11'O, + nSEI_NS := ts_NS_IE_NSEI(nsei), + transactionID := trans_id, + iP_Address_NS := ts_SNS_IP_ADDR(ip_sns), + listofIP4Elements := ts_SNS_IE_ListIP4(v4), + listofIP6Elements := ts_SNS_IE_ListIP6(v6) + } + } + template PDU_NS tr_SNS_DEL(template Nsei nsei, template uint8_t trans_id, + template IPAddress ip_sns, + template IP4_Elements v4, + template IP6_Elements v6 := omit) := { + pDU_SNS_Delete := { + nsPduType := '11'O, + nSEI_NS := tr_NS_IE_NSEI(nsei), + transactionID := trans_id, + iP_Address_NS := tr_SNS_IP_ADDR(ip_sns), + listofIP4Elements := tr_SNS_IE_ListIP4(v4), + listofIP6Elements := tr_SNS_IE_ListIP6(v6) + } + } + + + template (value) PDU_NS ts_SNS_ACK(Nsei nsei, uint8_t trans_id, + template (omit) NsCause cause := omit, + template (omit) IP4_Elements v4 := omit, + template (omit) IP6_Elements v6 := omit) := { + pDU_SNS_Ack := { + nsPduType := '0C'O, + nSEI_NS := ts_NS_IE_NSEI(nsei), + transactionID := trans_id, + causeNS := ts_NS_IE_CAUSE_omit(cause), + iP_Address_NS := omit, + listofIP4Elements := ts_SNS_IE_ListIP4(v4), + listofIP6Elements := ts_SNS_IE_ListIP6(v6) + } + } + template PDU_NS tr_SNS_ACK(template Nsei nsei, template uint8_t trans_id := ?, + template NsCause cause := omit, + template IP4_Elements v4 := *, + template IP6_Elements v6 := *) := { + pDU_SNS_Ack := { + nsPduType := '0C'O, + nSEI_NS := tr_NS_IE_NSEI(nsei), + transactionID := trans_id, + causeNS := tr_NS_IE_CAUSE(cause), + iP_Address_NS := omit, + listofIP4Elements := tr_SNS_IE_ListIP4(v4), + listofIP6Elements := tr_SNS_IE_ListIP6(v6) + } + } + + + + + + + type record BssgpCellId { RoutingAreaIdentification ra_id, CellIdentity cell_id diff --git a/pcu/PCU_Tests_RAW_SNS.ttcn b/pcu/PCU_Tests_RAW_SNS.ttcn index fb4d8f778..41a4059f4 100644 --- a/pcu/PCU_Tests_RAW_SNS.ttcn +++ b/pcu/PCU_Tests_RAW_SNS.ttcn @@ -67,6 +67,29 @@ runs on RAW_NS_CT { rx := f_ns_exp(tr_SNS_CONFIG_ACK(g_nsconfig[idx].nsei, cause), idx); } +function f_outgoing_sns_add(integer idx_add, uint8_t w_sig := 1, uint8_t w_user := 1, integer idx := 0) +runs on RAW_NS_CT { + log("f_outgoing_sns_add(idx_add=", idx_add, ")"); + var PDU_NS rx; + var template (omit) IP4_Elements v4 := { ts_SNS_IPv4(g_nsconfig[idx_add].local_ip, + g_nsconfig[idx_add].local_udp_port, + w_sig, w_user) }; + NSCP[idx].send(t_NS_Send(g_ns_conn_id[idx], ts_SNS_ADD(g_nsconfig[idx].nsei, 23, v4))); + rx := f_ns_exp(tr_SNS_ACK(g_nsconfig[idx].nsei, 23, omit, v4)); +} + +function f_outgoing_sns_del(integer idx_del, uint8_t w_sig := 1, uint8_t w_user := 1, integer idx := 0) +runs on RAW_NS_CT { + log("f_outgoing_sns_del(idx_del=", idx_del, ")"); + var PDU_NS rx; + var template (omit) IP4_Elements v4 := { ts_SNS_IPv4(g_nsconfig[idx_del].local_ip, + g_nsconfig[idx_del].local_udp_port, + w_sig, w_user) }; + NSCP[idx].send(t_NS_Send(g_ns_conn_id[idx], ts_SNS_DEL(g_nsconfig[idx].nsei, 24, omit, v4))); + rx := f_ns_exp(tr_SNS_ACK(g_nsconfig[idx].nsei, 24, omit, v4)); +} + + /* PCU-originated SNS-SIZE: successful case */ testcase TC_sns_po_size_success() runs on RAW_NS_CT { @@ -130,17 +153,89 @@ testcase TC_sns_so_config_success() runs on RAW_NS_CT { as_rx_bvc_unblock_tx_ack(mp_gb_cfg.bvci, oneshot := true); /* wait for one FLOW-CONTROL BVC and then ACK any further in the future */ - as_rx_bvc_fc_tx_ack(mp_gb_cfg.bvci, oneshot := true); - activate(as_rx_bvc_fc_tx_ack(mp_gb_cfg.bvci)); + as_rx_bvc_fc_tx_ack(mp_gb_cfg.bvci, oneshot := true, idx := 1); + activate(as_rx_bvc_fc_tx_ack(mp_gb_cfg.bvci, idx := 1)); setverdict(pass); } +private function f_sns_bringup_1c1u() runs on RAW_NS_CT { + /* Activate two NS codec ports */ + f_init_ns_codec(); + f_init_ns_codec(1); + f_init_pcuif(); + /* Perform Size + BSS-originated config */ + f_incoming_sns_size(); + f_incoming_sns_config(); + /* perform SGSN-originated config using idx==0 for signalling and idx==1 for user traffic */ + f_outgoing_sns_config_1c1u(); + + /* wait for one ALIVE cycle, then ACK any further ALIVE in the background + * for both NS-VCs */ + as_rx_alive_tx_ack(oneshot := true, idx := 0); + activate(as_rx_alive_tx_ack(idx := 0)); + as_rx_alive_tx_ack(oneshot := true, idx := 1); + activate(as_rx_alive_tx_ack(idx := 1)); + + /* perform outgoing ALIVE procedure for both NS-VCs */ + f_outgoing_ns_alive(0); + f_outgoing_ns_alive(1); + + /* Expect BVC-RESET for signaling (0) and ptp BVCI */ + as_rx_bvc_reset_tx_ack(0, oneshot := true); + as_rx_bvc_reset_tx_ack(mp_gb_cfg.bvci, oneshot := true); + /* Expect UNBLOCK for ptp BVCI on signaling NS-VC (idx==0) */ + as_rx_bvc_unblock_tx_ack(mp_gb_cfg.bvci, oneshot := true); + + /* wait for one FLOW-CONTROL BVC and then ACK any further in the future. Flow + * control happens on the p-t-p BVCI and hence on index 1 */ + as_rx_bvc_fc_tx_ack(mp_gb_cfg.bvci, oneshot := true, idx := 1); + activate(as_rx_bvc_fc_tx_ack(mp_gb_cfg.bvci, idx := 1)); +} + +/* Test full IP-SNS bring-up with two NS-VCs, one sig-only and one user-only */ +testcase TC_sns_1c1u() runs on RAW_NS_CT { + f_sns_bringup_1c1u(); + setverdict(pass); +} + +/* Test adding new IP endpoints at runtime */ +testcase TC_sns_add() runs on RAW_NS_CT { + f_sns_bringup_1c1u(); + + /* crate another NS codec port on the tester side */ + f_init_ns_codec(2); + + f_outgoing_sns_add(idx_add := 2, w_sig := 0, w_user := 1, idx := 0); + + /* wait for one ALIVE cycle, then ACK any further ALIVE in the background */ + as_rx_alive_tx_ack(oneshot := true, idx := 2); + activate(as_rx_alive_tx_ack(idx := 2)); + + f_outgoing_ns_alive(2); + /* TODO: Should we expect FLOW-CONTROL BVC here too? */ + setverdict(pass); +} + +/* Test deleting IP endpoints at runtime */ +testcase TC_sns_del() runs on RAW_NS_CT { + f_sns_bringup_1c1u(); + + f_outgoing_sns_del(idx_del := 1, w_sig := 0, w_user := 1, idx := 0); + /* FIXME: ensure we don't receive anything on just-deleted NS-VC anymore */ + setverdict(pass); +} + + + control { execute( TC_sns_po_size_success() ); execute( TC_sns_po_size_nack() ); execute( TC_sns_po_config_success() ); execute( TC_sns_po_config_nack() ); execute( TC_sns_so_config_success() ); + execute( TC_sns_1c1u() ); + execute( TC_sns_add() ); + execute( TC_sns_del() ); } }