aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2019-05-07 01:20:17 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2019-05-09 00:55:11 +0200
commit0ac6315212a35522495ea216f14f94a6d4f9fbb3 (patch)
tree9891b55103dd801453793000b46517b09d8309e4
parent2ca1ab492a8c5e1aa508df0779c7b7ab34129fe0 (diff)
msc: add inter-BSC and inter-MSC Handover tests
-rw-r--r--library/BSSMAP_Templates.ttcn163
-rw-r--r--library/GSUP_Types.ttcn245
-rw-r--r--library/L3_Templates.ttcn53
-rw-r--r--library/RAN_Emulation.ttcnpp129
-rw-r--r--msc/BSC_ConnectionHandler.ttcn21
-rw-r--r--msc/MSC_Tests.ttcn496
6 files changed, 1015 insertions, 92 deletions
diff --git a/library/BSSMAP_Templates.ttcn b/library/BSSMAP_Templates.ttcn
index 4df39d42..b7230cd3 100644
--- a/library/BSSMAP_Templates.ttcn
+++ b/library/BSSMAP_Templates.ttcn
@@ -307,7 +307,7 @@ modifies tr_BSSAP_BSSMAP := {
}
}
-template BSSMAP_IE_CellIdentifierList ts_BSSMAP_IE_CidList(BSSMAP_FIELD_CellIdentificationList cid_list) := {
+template BSSMAP_IE_CellIdentifierList ts_BSSMAP_IE_CidList(template BSSMAP_FIELD_CellIdentificationList cid_list) := {
elementIdentifier := '1A'O,
lengthIndicator := 0, /* overwritten */
cellIdentifierDiscriminator := '0000'B, /* overwritten */
@@ -315,31 +315,6 @@ template BSSMAP_IE_CellIdentifierList ts_BSSMAP_IE_CidList(BSSMAP_FIELD_CellIden
cellIdentificationList := cid_list
}
-template PDU_BSSAP ts_BSSMAP_HandoReq(BssmapCause cause, BSSMAP_FIELD_CellIdentificationList cid_list)
-modifies ts_BSSAP_BSSMAP := {
- pdu := {
- bssmap := {
- handoverRequired := {
- messageType := '11'O,
- cause := ts_BSSMAP_IE_Cause(cause),
- responseRequest := omit,
- cellIdentifierList := ts_BSSMAP_IE_CidList(cid_list),
- circuitPoolList := omit,
- currentChannelType1 := omit,
- speechVersion := omit,
- queueingIndicator := omit,
- oldToNewBSSInfo := omit,
- sourceToTargetRNCTransparentInfo := omit,
- sourceToTargetRNCTransparentInfoCDMA := omit,
- gERANClassmark := omit,
- talkerPriority := omit,
- speechCodec := omit,
- cSG_Identifier := omit
- }
- }
- }
-}
-
const OCT1 ChRate_ANY := '00'O;
const OCT1 ChRate_TCHF := '08'O;
const OCT1 ChRate_TCHH := '09'O;
@@ -703,6 +678,33 @@ template PDU_BSSAP tr_BSSMAP_ClearRequest modifies tr_BSSAP_BSSMAP := {
}
}
+template PDU_BSSAP ts_BSSMAP_HandoverRequired(BssmapCause cause,
+ template BSSMAP_FIELD_CellIdentificationList cid_list)
+modifies ts_BSSAP_BSSMAP := {
+ pdu := {
+ bssmap := {
+ handoverRequired := {
+ messageType := '11'O,
+ cause := ts_BSSMAP_IE_Cause(cause),
+ responseRequest := omit,
+ cellIdentifierList := ts_BSSMAP_IE_CidList(cid_list),
+ circuitPoolList := omit,
+ currentChannelType1 := omit,
+ speechVersion := omit,
+ queueingIndicator := omit,
+ oldToNewBSSInfo := omit,
+ sourceToTargetRNCTransparentInfo := omit,
+ sourceToTargetRNCTransparentInfoCDMA := omit,
+ gERANClassmark := omit,
+ talkerPriority := omit,
+ speechCodec := omit,
+ cSG_Identifier := omit
+ }
+ }
+ }
+}
+
+
template PDU_BSSAP tr_BSSMAP_HandoverRequired modifies tr_BSSAP_BSSMAP := {
pdu := {
bssmap := {
@@ -713,6 +715,38 @@ template PDU_BSSAP tr_BSSMAP_HandoverRequired modifies tr_BSSAP_BSSMAP := {
}
}
+template PDU_BSSAP tr_BSSMAP_HandoverRequiredReject modifies tr_BSSAP_BSSMAP := {
+ pdu := {
+ bssmap := {
+ handoverRequiredReject := {
+ messageType := '1A'O
+ }
+ }
+ }
+}
+
+template PDU_BSSAP tr_BSSMAP_HandoverCommand
+modifies tr_BSSAP_BSSMAP := {
+ pdu := {
+ bssmap := {
+ handoverCommand := {
+ messageType := '13'O
+ }
+ }
+ }
+}
+
+template PDU_BSSAP tr_BSSMAP_HandoverSucceeded
+modifies tr_BSSAP_BSSMAP := {
+ pdu := {
+ bssmap := {
+ handoverSucceeded := {
+ messageType := '15'O
+ }
+ }
+ }
+}
+
template (value) PDU_BSSAP ts_BSSMAP_HandoverCommand(octetstring layer3info)
modifies ts_BSSAP_BSSMAP := {
pdu := {
@@ -751,6 +785,16 @@ template PDU_BSSAP tr_BSSMAP_HandoverFailure modifies tr_BSSAP_BSSMAP := {
}
}
+template PDU_BSSAP tr_BSSMAP_HandoverRequest modifies tr_BSSAP_BSSMAP := {
+ pdu := {
+ bssmap := {
+ handoverRequest := {
+ messageType := '10'O
+ }
+ }
+ }
+}
+
template PDU_BSSAP ts_BSSMAP_HandoverRequest(
template BSSMAP_IE_CircuitIdentityCode cic := omit,
template BSSMAP_IE_AoIP_TransportLayerAddress aoip_tla := omit,
@@ -826,6 +870,41 @@ modifies tr_BSSAP_BSSMAP := {
}
}
+template PDU_BSSAP ts_BSSMAP_HandoverRequestAcknowledge(
+ template octetstring layer3info,
+ template LIN1 layer3infoLength,
+ template BSSMAP_IE_AoIP_TransportLayerAddress aoIPTransportLayer := omit,
+ template BSSMAP_IE_SpeechCodec speechCodec := omit,
+ template BSSMAP_IE_ChosenChannel chosenChannel := omit,
+ template BSSMAP_IE_ChosenEncryptionAlgorithm chosenEncryptionAlgorithm := omit)
+modifies ts_BSSAP_BSSMAP := {
+ pdu := {
+ bssmap := {
+ handoverRequestAck := {
+ messageType := '12'O,
+ layer3Information := {
+ elementIdentifier := '17'O,
+ lengthIndicator := layer3infoLength,
+ layer3info := layer3info
+ },
+ chosenChannel := chosenChannel,
+ chosenEncryptionAlgorithm := chosenEncryptionAlgorithm,
+ circuitPool := omit,
+ speechVersion := omit,
+ circuitIdentityCode := omit,
+ lSAIdentifier := omit,
+ newBSSToOldBSSInfo := omit,
+ interSystemInformation := omit,
+ talkerPriority := omit,
+ aoIPTransportLayer := aoIPTransportLayer,
+ codecList := omit,
+ speechCodec := speechCodec,
+ lCLS_bSS_Status := omit
+ }
+ }
+ }
+}
+
template PDU_BSSAP tr_BSSMAP_HandoverDetect
modifies tr_BSSAP_BSSMAP := {
pdu := {
@@ -838,6 +917,18 @@ modifies tr_BSSAP_BSSMAP := {
}
}
+template PDU_BSSAP ts_BSSMAP_HandoverDetect
+modifies ts_BSSAP_BSSMAP := {
+ pdu := {
+ bssmap := {
+ handoverDetect := {
+ messageType := '1B'O,
+ talkerPriority := omit
+ }
+ }
+ }
+}
+
template PDU_BSSAP tr_BSSMAP_HandoverComplete
modifies tr_BSSAP_BSSMAP := {
pdu := {
@@ -856,6 +947,24 @@ modifies tr_BSSAP_BSSMAP := {
}
}
+template PDU_BSSAP ts_BSSMAP_HandoverComplete
+modifies ts_BSSAP_BSSMAP := {
+ pdu := {
+ bssmap := {
+ handoverComplete := {
+ messageType := '14'O,
+ rR_Cause := omit,
+ talkerPriority := omit,
+ speechCodec := omit,
+ codecList := omit,
+ chosenEncryptionAlgorithm := omit,
+ chosenChannel := omit,
+ lCLS_BSS_Status := omit
+ }
+ }
+ }
+}
+
template PDU_BSSAP tr_BSSMAP_HandoverPerformed
modifies tr_BSSAP_BSSMAP := {
pdu := {
@@ -975,7 +1084,7 @@ modifies ts_BSSAP_BSSMAP := {
messageType := '52'O,
iMSI := ts_BSSMAP_Imsi(imsi_digits),
tMSI := f_tmsi_or_omit(tmsi),
- cellIdentifierList := ts_BSSMAP_IE_CidList(valueof(cid_list)),
+ cellIdentifierList := ts_BSSMAP_IE_CidList(cid_list),
channelNeeded := chneed,
eMLPP_Priority := omit,
pagingInformation := omit /* only VGCS/VBS flag */
diff --git a/library/GSUP_Types.ttcn b/library/GSUP_Types.ttcn
index c024d371..73f45626 100644
--- a/library/GSUP_Types.ttcn
+++ b/library/GSUP_Types.ttcn
@@ -55,7 +55,16 @@ type enumerated GSUP_IEI {
OSMO_GSUP_SM_ALERT_RSN_IE ('46'O),
OSMO_GSUP_IMEI_IE ('50'O),
- OSMO_GSUP_IMEI_RESULT_IE ('51'O)
+ OSMO_GSUP_IMEI_RESULT_IE ('51'O),
+
+ OSMO_GSUP_MESSAGE_CLASS_IE ('0a'O),
+
+ OSMO_GSUP_SOURCE_NAME_IE ('60'O),
+ OSMO_GSUP_DESTINATION_NAME_IE ('61'O),
+ OSMO_GSUP_AN_APDU_IE ('62'O),
+ OSMO_GSUP_CAUSE_RR_IE ('63'O),
+ OSMO_GSUP_CAUSE_BSSAP_IE ('64'O),
+ OSMO_GSUP_CAUSE_SM_IE ('65'O)
} with { variant "FIELDLENGTH(8)" };
type enumerated GSUP_MessageType {
@@ -103,7 +112,27 @@ type enumerated GSUP_MessageType {
OSMO_GSUP_MSGT_CHECK_IMEI_REQUEST ('00110000'B),
OSMO_GSUP_MSGT_CHECK_IMEI_ERROR ('00110001'B),
- OSMO_GSUP_MSGT_CHECK_IMEI_RESULT ('00110010'B)
+ OSMO_GSUP_MSGT_CHECK_IMEI_RESULT ('00110010'B),
+
+ OSMO_GSUP_MSGT_E_PREPARE_HANDOVER_REQUEST ('00110100'B),
+ OSMO_GSUP_MSGT_E_PREPARE_HANDOVER_ERROR ('00110101'B),
+ OSMO_GSUP_MSGT_E_PREPARE_HANDOVER_RESULT ('00110110'B),
+
+ OSMO_GSUP_MSGT_E_PREPARE_SUBSEQUENT_HANDOVER_REQUEST ('00111000'B),
+ OSMO_GSUP_MSGT_E_PREPARE_SUBSEQUENT_HANDOVER_ERROR ('00111001'B),
+ OSMO_GSUP_MSGT_E_PREPARE_SUBSEQUENT_HANDOVER_RESULT ('00111010'B),
+
+ OSMO_GSUP_MSGT_E_SEND_END_SIGNAL_REQUEST ('00111100'B),
+ OSMO_GSUP_MSGT_E_SEND_END_SIGNAL_ERROR ('00111101'B),
+ OSMO_GSUP_MSGT_E_SEND_END_SIGNAL_RESULT ('00111110'B),
+
+ OSMO_GSUP_MSGT_E_PROCESS_ACCESS_SIGNALLING_REQUEST ('01000000'B),
+ OSMO_GSUP_MSGT_E_FORWARD_ACCESS_SIGNALLING_REQUEST ('01000100'B),
+
+ OSMO_GSUP_MSGT_E_CLOSE ('01000111'B),
+ OSMO_GSUP_MSGT_E_ABORT ('01001011'B),
+
+ OSMO_GSUP_MSGT_E_ROUTING_ERROR ('01001110'B)
} with { variant "FIELDLENGTH(8)" };
type enumerated GSUP_CancelType {
@@ -128,6 +157,14 @@ type enumerated GSUP_SessionState {
OSMO_GSUP_SESSION_STATE_END (3)
} with { variant "FIELDLENGTH(8)" };
+type enumerated GSUP_Message_Class {
+ OSMO_GSUP_MESSAGE_CLASS_UNSET (0),
+ OSMO_GSUP_MESSAGE_CLASS_SUBSCRIBER_MANAGEMENT (1),
+ OSMO_GSUP_MESSAGE_CLASS_SMS (2),
+ OSMO_GSUP_MESSAGE_CLASS_USSD (3),
+ OSMO_GSUP_MESSAGE_CLASS_INTER_MSC (4)
+} with { variant "FIELDLENGTH(8)" };
+
type record GSUP_MSISDN {
uint8_t len,
hexstring digits optional
@@ -138,6 +175,16 @@ type record GSUP_IMEI {
hexstring digits optional
} with { variant (len) "LENGTHTO(digits)" };
+type enumerated GSUP_AN_PROTO {
+ OSMO_GSUP_AN_PROTO_48006 (1),
+ OSMO_GSUP_AN_PROTO_25413 (2)
+} with { variant "FIELDLENGTH(8)" };
+
+type record GSUP_AN_APDU {
+ GSUP_AN_PROTO proto,
+ octetstring pdu
+};
+
type record GSUP_IE {
GSUP_IEI tag,
uint8_t len,
@@ -175,6 +222,13 @@ type record GSUP_IE {
sm_alert_rsn, tag = OSMO_GSUP_SM_ALERT_RSN_IE;
imei, tag = OSMO_GSUP_IMEI_IE;
imei_result, tag = OSMO_GSUP_IMEI_RESULT_IE;
+ message_class, tag = OSMO_GSUP_MESSAGE_CLASS_IE;
+ source_name, tag = OSMO_GSUP_SOURCE_NAME_IE;
+ destination_name, tag = OSMO_GSUP_DESTINATION_NAME_IE;
+ an_apdu, tag = OSMO_GSUP_AN_APDU_IE;
+ cause_rr, tag = OSMO_GSUP_CAUSE_RR_IE;
+ cause_bssap, tag = OSMO_GSUP_CAUSE_BSSAP_IE;
+ cause_sm, tag = OSMO_GSUP_CAUSE_SM_IE;
)"
};
@@ -219,7 +273,18 @@ type union GSUP_IeValue {
GSUP_SM_ALERT_RSN_Type sm_alert_rsn,
GSUP_IMEI imei,
- GSUP_IMEIResult imei_result
+ GSUP_IMEIResult imei_result,
+
+ GSUP_Message_Class message_class,
+
+ octetstring source_name,
+ octetstring destination_name,
+
+ GSUP_AN_APDU an_apdu,
+
+ OCT1 cause_rr,
+ OCT1 cause_bssap,
+ OCT1 cause_sm
};
type record GSUP_PDU {
@@ -930,6 +995,70 @@ template GSUP_IE tr_GSUP_IE_SSInfo(template octetstring ss) := {
}
}
+template GSUP_IE tr_GSUP_IE_Message_Class(template GSUP_Message_Class val) := {
+ tag := OSMO_GSUP_MESSAGE_CLASS_IE,
+ len := ?,
+ val := {
+ message_class := val
+ }
+}
+
+template (value) GSUP_IE ts_GSUP_IE_Message_Class(GSUP_Message_Class val) := {
+ tag := OSMO_GSUP_MESSAGE_CLASS_IE,
+ len := 0, /* overwritten */
+ val := {
+ message_class := val
+ }
+}
+
+template GSUP_IE tr_GSUP_IE_Source_Name(template octetstring name) := {
+ tag := OSMO_GSUP_SOURCE_NAME_IE,
+ len := ?,
+ val := {
+ source_name := name
+ }
+}
+
+template (value) GSUP_IE ts_GSUP_IE_Source_Name(octetstring name) := {
+ tag := OSMO_GSUP_SOURCE_NAME_IE,
+ len := 0, /* overwritten */
+ val := {
+ source_name := name
+ }
+}
+
+template GSUP_IE tr_GSUP_IE_Destination_Name(template octetstring name) := {
+ tag := OSMO_GSUP_DESTINATION_NAME_IE,
+ len := ?,
+ val := {
+ destination_name := name
+ }
+}
+
+template (value) GSUP_IE ts_GSUP_IE_Destination_Name(octetstring name) := {
+ tag := OSMO_GSUP_DESTINATION_NAME_IE,
+ len := 0, /* overwritten */
+ val := {
+ destination_name := name
+ }
+}
+
+template GSUP_IE tr_GSUP_IE_AN_APDU(template GSUP_AN_APDU an_apdu) := {
+ tag := OSMO_GSUP_AN_APDU_IE,
+ len := ?,
+ val := {
+ an_apdu := an_apdu
+ }
+}
+
+template (value) GSUP_IE ts_GSUP_IE_AN_APDU(GSUP_AN_APDU an_apdu) := {
+ tag := OSMO_GSUP_AN_APDU_IE,
+ len := 0, /* overwritten */
+ val := {
+ an_apdu := an_apdu
+ }
+}
+
private function f_gen_ts_ss_ies(
hexstring imsi,
OCT4 sid,
@@ -962,14 +1091,20 @@ private function f_gen_tr_ss_ies(
tr_GSUP_IE_SessionId(sid),
tr_GSUP_IE_SessionState(state)
};
+ var integer last_idx := 3;
/* Optional SS payload */
if (istemplatekind(ss, "*")) {
ies[3] := *;
+ last_idx := last_idx + 1;
} else if (not istemplatekind(ss, "omit")) {
ies[3] := tr_GSUP_IE_SSInfo(ss);
+ last_idx := last_idx + 1;
}
+ ies[last_idx] := tr_GSUP_IE_Message_Class(OSMO_GSUP_MESSAGE_CLASS_USSD);
+ last_idx := last_idx + 1;
+
return ies;
}
@@ -1036,7 +1171,8 @@ template GSUP_PDU tr_GSUP_PROC_SS_ERR(
tr_GSUP_IE_IMSI(imsi),
tr_GSUP_IE_Cause(cause),
tr_GSUP_IE_SessionId(sid),
- tr_GSUP_IE_SessionState(state)
+ tr_GSUP_IE_SessionState(state),
+ tr_GSUP_IE_Message_Class(OSMO_GSUP_MESSAGE_CLASS_SMS)
}
);
@@ -1069,7 +1205,8 @@ template GSUP_PDU tr_GSUP_MO_FORWARD_SM_REQ(
tr_GSUP_IE_SM_RP_MR(sm_rp_mr),
tr_GSUP_IE_SM_RP_DA(sm_rp_da),
tr_GSUP_IE_SM_RP_OA(sm_rp_oa),
- tr_GSUP_IE_SM_RP_UI(sm_rp_ui)
+ tr_GSUP_IE_SM_RP_UI(sm_rp_ui),
+ tr_GSUP_IE_Message_Class(OSMO_GSUP_MESSAGE_CLASS_SMS)
}
);
@@ -1090,7 +1227,8 @@ template GSUP_PDU tr_GSUP_MO_FORWARD_SM_RES(
OSMO_GSUP_MSGT_MO_FORWARD_SM_RESULT,
{
tr_GSUP_IE_IMSI(imsi),
- tr_GSUP_IE_SM_RP_MR(sm_rp_mr)
+ tr_GSUP_IE_SM_RP_MR(sm_rp_mr),
+ tr_GSUP_IE_Message_Class(OSMO_GSUP_MESSAGE_CLASS_SMS)
}
);
@@ -1115,7 +1253,8 @@ template GSUP_PDU tr_GSUP_MO_FORWARD_SM_ERR(
{
tr_GSUP_IE_IMSI(imsi),
tr_GSUP_IE_SM_RP_MR(sm_rp_mr),
- tr_GSUP_IE_SM_RP_CAUSE(sm_rp_cause)
+ tr_GSUP_IE_SM_RP_CAUSE(sm_rp_cause),
+ tr_GSUP_IE_Message_Class(OSMO_GSUP_MESSAGE_CLASS_SMS)
}
);
@@ -1162,7 +1301,8 @@ template GSUP_PDU tr_GSUP_MT_FORWARD_SM_REQ(
tr_GSUP_IE_SM_RP_DA(sm_rp_da),
tr_GSUP_IE_SM_RP_OA(sm_rp_oa),
tr_GSUP_IE_SM_RP_UI(sm_rp_ui),
- tr_GSUP_IE_SM_RP_MMS(sm_rp_mms)
+ tr_GSUP_IE_SM_RP_MMS(sm_rp_mms),
+ tr_GSUP_IE_Message_Class(OSMO_GSUP_MESSAGE_CLASS_SMS)
}
);
@@ -1183,7 +1323,8 @@ template GSUP_PDU tr_GSUP_MT_FORWARD_SM_RES(
OSMO_GSUP_MSGT_MT_FORWARD_SM_RESULT,
{
tr_GSUP_IE_IMSI(imsi),
- tr_GSUP_IE_SM_RP_MR(sm_rp_mr)
+ tr_GSUP_IE_SM_RP_MR(sm_rp_mr),
+ tr_GSUP_IE_Message_Class(OSMO_GSUP_MESSAGE_CLASS_SMS)
}
);
@@ -1208,7 +1349,8 @@ template GSUP_PDU tr_GSUP_MT_FORWARD_SM_ERR(
{
tr_GSUP_IE_IMSI(imsi),
tr_GSUP_IE_SM_RP_MR(sm_rp_mr),
- tr_GSUP_IE_SM_RP_CAUSE(sm_rp_cause)
+ tr_GSUP_IE_SM_RP_CAUSE(sm_rp_cause),
+ tr_GSUP_IE_Message_Class(OSMO_GSUP_MESSAGE_CLASS_SMS)
}
);
@@ -1233,7 +1375,8 @@ template GSUP_PDU tr_GSUP_MO_READY_FOR_SM_REQ(
{
tr_GSUP_IE_IMSI(imsi),
tr_GSUP_IE_SM_RP_MR(sm_rp_mr),
- tr_GSUP_IE_SM_ALERT_RSN(sm_alert_rsn)
+ tr_GSUP_IE_SM_ALERT_RSN(sm_alert_rsn),
+ tr_GSUP_IE_Message_Class(OSMO_GSUP_MESSAGE_CLASS_SMS)
}
);
@@ -1254,7 +1397,8 @@ template GSUP_PDU tr_GSUP_MO_READY_FOR_SM_RES(
OSMO_GSUP_MSGT_READY_FOR_SM_RESULT,
{
tr_GSUP_IE_IMSI(imsi),
- tr_GSUP_IE_SM_RP_MR(sm_rp_mr)
+ tr_GSUP_IE_SM_RP_MR(sm_rp_mr),
+ tr_GSUP_IE_Message_Class(OSMO_GSUP_MESSAGE_CLASS_SMS)
}
);
@@ -1279,7 +1423,8 @@ template GSUP_PDU tr_GSUP_MO_READY_FOR_SM_ERR(
{
tr_GSUP_IE_IMSI(imsi),
tr_GSUP_IE_SM_RP_MR(sm_rp_mr),
- tr_GSUP_IE_SM_RP_CAUSE(sm_rp_cause)
+ tr_GSUP_IE_SM_RP_CAUSE(sm_rp_cause),
+ tr_GSUP_IE_Message_Class(OSMO_GSUP_MESSAGE_CLASS_SMS)
}
);
@@ -1293,5 +1438,79 @@ function f_gsup_find_ie(GSUP_PDU msg, GSUP_IEI iei, out GSUP_IeValue ret) return
return false;
}
+template GSUP_AN_APDU t_GSUP_AN_APDU(
+ template GSUP_AN_PROTO an_proto := ?,
+ template octetstring pdu := ?
+) := {
+ proto := an_proto,
+ pdu := pdu
+};
+
+template GSUP_PDU tr_GSUP_E_AN_APDU(
+ template GSUP_MessageType msgt,
+ template hexstring imsi := ?,
+ template octetstring source_name := ?,
+ template octetstring destination_name := ?,
+ template GSUP_AN_APDU an_apdu := ?
+) := tr_GSUP(
+ msgt,
+ {
+ tr_GSUP_IE_IMSI(imsi),
+ tr_GSUP_IE_Message_Class(OSMO_GSUP_MESSAGE_CLASS_INTER_MSC),
+ tr_GSUP_IE_Source_Name(source_name),
+ tr_GSUP_IE_Destination_Name(destination_name),
+ tr_GSUP_IE_AN_APDU(an_apdu)
+ }
+);
+
+template GSUP_PDU tr_GSUP_E_NO_PDU(
+ template GSUP_MessageType msgt,
+ template hexstring imsi := ?,
+ template octetstring source_name := ?,
+ template octetstring destination_name := ?
+) := tr_GSUP(
+ msgt,
+ {
+ tr_GSUP_IE_IMSI(imsi),
+ tr_GSUP_IE_Message_Class(OSMO_GSUP_MESSAGE_CLASS_INTER_MSC),
+ tr_GSUP_IE_Source_Name(source_name),
+ tr_GSUP_IE_Destination_Name(destination_name)
+ }
+);
+
+template (value) GSUP_PDU ts_GSUP_E_AN_APDU(
+ GSUP_MessageType msgt,
+ hexstring imsi,
+ octetstring source_name,
+ octetstring destination_name,
+ GSUP_AN_APDU an_apdu
+) := ts_GSUP(
+ msgt,
+ {
+ valueof(ts_GSUP_IE_IMSI(imsi)),
+ valueof(ts_GSUP_IE_Message_Class(OSMO_GSUP_MESSAGE_CLASS_INTER_MSC)),
+ valueof(ts_GSUP_IE_Source_Name(source_name)),
+ valueof(ts_GSUP_IE_Destination_Name(destination_name)),
+ valueof(ts_GSUP_IE_AN_APDU(an_apdu))
+ }
+);
+
+template (value) GSUP_PDU ts_GSUP_E_PrepareHandoverResult(
+ hexstring imsi,
+ hexstring msisdn,
+ octetstring source_name,
+ octetstring destination_name,
+ GSUP_AN_APDU an_apdu
+) := ts_GSUP(
+ OSMO_GSUP_MSGT_E_PREPARE_HANDOVER_RESULT,
+ {
+ valueof(ts_GSUP_IE_IMSI(imsi)),
+ valueof(ts_GSUP_IE_MSISDN(msisdn)),
+ valueof(ts_GSUP_IE_Message_Class(OSMO_GSUP_MESSAGE_CLASS_INTER_MSC)),
+ valueof(ts_GSUP_IE_Source_Name(source_name)),
+ valueof(ts_GSUP_IE_Destination_Name(destination_name)),
+ valueof(ts_GSUP_IE_AN_APDU(an_apdu))
+ }
+);
} with { encode "RAW"; variant "FIELDORDER(msb)" }
diff --git a/library/L3_Templates.ttcn b/library/L3_Templates.ttcn
index 4d71f270..cf6d64ce 100644
--- a/library/L3_Templates.ttcn
+++ b/library/L3_Templates.ttcn
@@ -582,6 +582,59 @@ template (value) PDU_ML3_NW_MS ts_RR_HandoverCommand := {
}
}
+template PDU_ML3_NW_MS tr_RR_HandoverCommand := {
+ discriminator := '0110'B,
+ tiOrSkip := {
+ skipIndicator := '0000'B
+ },
+ msgs := {
+ rrm := {
+ handoverCommand := {
+ messageType := '00101011'B,
+ cellDescription := ?,
+ channelDescription2 := ?,
+ handoverReference := ?,
+ powerCommandAndAccesstype := ?,
+ synchronizationIndication := *,
+ frequencyShortListAfterTime := *,
+ frequencyListAfterTime := *,
+ cellChannelDescription := *,
+ multislotAllocation := *,
+ modeOfChannelSet1 := *,
+ modeOfChannelSet2 := *,
+ modeOfChannelSet3 := *,
+ modeOfChannelSet4 := *,
+ modeOfChannelSet5 := *,
+ modeOfChannelSet6 := *,
+ modeOfChannelSet7 := *,
+ modeOfChannelSet8 := *,
+ descrOf2ndCh_at := *,
+ modeOf2ndChannel := *,
+ frequencyChannelSequence_at := *,
+ mobileAllocation_at := *,
+ startingTime := *,
+ timeDifference := *,
+ timingAdvance := *,
+ frequencyShortListBeforeTime := *,
+ frequencyListBeforeTime := *,
+ descrOf1stCh_bt := *,
+ descrOf2ndCh_bt := *,
+ frequencyChannelSequence_bt := *,
+ mobileAllocation_bt := *,
+ cipherModeSetting := *,
+ vGCS_TargetModeIndication := *,
+ multiRateConfiguration := *,
+ dynamicARFCN_Mapping := *,
+ vGCS_Ciphering_Parameters := *,
+ dedicatedServiceInformation := *,
+ pLMNIndex := *,
+ extendedTSCSet_afterTime := *,
+ extendedTSCSet_beforeTime := *
+ }
+ }
+ }
+}
+
function ts_CM3_TLV(template (omit) OCTN cm3) return template MobileStationClassmark3_TLV {
if (not isvalue(cm3)) {
return omit;
diff --git a/library/RAN_Emulation.ttcnpp b/library/RAN_Emulation.ttcnpp
index d6d74e26..843cc9e1 100644
--- a/library/RAN_Emulation.ttcnpp
+++ b/library/RAN_Emulation.ttcnpp
@@ -133,6 +133,7 @@ type port RAN_Conn_PT message {
RAN_Conn_Prim;
} with { extension "internal" };
+type uint2_t N_Sd_Array[4];
/* represents a single BSSAP connection over SCCP */
type record ConnectionData {
@@ -146,7 +147,7 @@ type record ConnectionData {
/* CIC that has been used for voice of this channel (BSC side) */
integer cic optional,
/* array of N(SD) values for MO DTAP messages, indexed by discriminator */
- uint2_t n_sd[4]
+ N_Sd_Array n_sd
}
type record ImsiMapping {
@@ -671,28 +672,51 @@ private function f_L3_is_rr(template octetstring l3) return boolean {
return false;
}
+function f_next_n_sd(inout N_Sd_Array n_sd, in integer n_sd_idx) return uint2_t {
+ var uint2_t seq_nr;
+ if (n_sd_idx == 0) {
+ seq_nr := n_sd[0];
+ n_sd[0] := (n_sd[0] + 1) mod 4;
+ } else if (n_sd_idx >= 1 and n_sd_idx <= 3) {
+ seq_nr := n_sd[n_sd_idx];
+ n_sd[n_sd_idx] := (n_sd[n_sd_idx] + 1) mod 2;
+ } else {
+ /* no sequence number to patch */
+ seq_nr := 0;
+ }
+ return seq_nr;
+}
+
/* patch N(SD) into enc_l3, according to 24.007 11.2.3.2 */
-function f_ML3_patch_seq(inout ConnectionData cd, in PDU_ML3_MS_NW dtap, inout octetstring enc_l3) {
+function f_ML3_patch_seq_nr(in uint2_t seq_nr, inout octetstring enc_l3) {
+ log("patching N(SD)=", seq_nr, " into dtap ", enc_l3);
+ enc_l3[1] := (enc_l3[1] and4b '3f'O) or4b bit2oct(int2bit(seq_nr, 8) << 6);
+ log("patched enc_l3: ", enc_l3);
+}
+
+function f_ML3_n_sd_idx(in PDU_ML3_MS_NW dtap) return integer {
var uint2_t seq_nr;
if (ischosen(dtap.msgs.cc) or ischosen(dtap.msgs.mm) or ischosen(dtap.msgs.ss)) {
- seq_nr := cd.n_sd[0];
- cd.n_sd[0] := (cd.n_sd[0] + 1) mod 4;
+ return 0;
} else if (ischosen(dtap.msgs.gcc)) {
- seq_nr := cd.n_sd[1];
- cd.n_sd[1] := (cd.n_sd[1] + 1) mod 2;
+ return 1;
} else if (ischosen(dtap.msgs.bcc)) {
- seq_nr := cd.n_sd[2];
- cd.n_sd[2] := (cd.n_sd[2] + 1) mod 2;
+ return 2;
} else if (ischosen(dtap.msgs.loc)) {
- seq_nr := cd.n_sd[3];
- cd.n_sd[3] := (cd.n_sd[3] + 1) mod 2;
- } else {
- /* no sequence number to patch */
+ return 3;
+ }
+ /* no sequence number to patch */
+ return -1;
+}
+
+/* patch N(SD) into enc_l3, according to 24.007 11.2.3.2 */
+function f_ML3_patch_seq(inout ConnectionData cd, in PDU_ML3_MS_NW dtap, inout octetstring enc_l3) {
+ var integer n_sd_idx := f_ML3_n_sd_idx(dtap);
+ if (n_sd_idx < 0) {
return;
}
- log("patching N(SD)=", seq_nr, " into dtap ", enc_l3);
- enc_l3[1] := (enc_l3[1] and4b '3f'O) or4b bit2oct(int2bit(seq_nr, 8) << 6);
- log("patched enc_l3: ", enc_l3);
+ var uint2_t seq_nr := f_next_n_sd(cd.n_sd, n_sd_idx);
+ f_ML3_patch_seq_nr(seq_nr, enc_l3);
}
private altstep as_reset_ack() runs on RAN_Emulation_CT {
@@ -732,6 +756,8 @@ private altstep as_main_bssap() runs on RAN_Emulation_CT {
var BSSAP_Conn_Req creq;
var PDU_BSSAP bssap;
var RAN_ConnHdlr vc_conn;
+ var integer targetPointCode;
+ var N_Sd_Array last_n_sd;
/* SCCP -> Client: UNIT-DATA (connectionless SCCP) from a BSC */
[] BSSAP.receive(BSSAP_N_UNITDATA_ind:?) -> value ud_ind {
@@ -823,7 +849,18 @@ private altstep as_main_bssap() runs on RAN_Emulation_CT {
ConnectionTable[idx].n_sd[0] := 1;
log("patch: N(SD) for ConnIdx ", idx, " set to 1");
}
+ }
+
+ [] PROC.getcall(RAN_last_n_sd:{?,-}) -> param(vc_conn) {
+ var integer idx := f_idx_by_comp(vc_conn);
+ last_n_sd := ConnectionTable[idx].n_sd;
+ PROC.reply(RAN_last_n_sd:{vc_conn, last_n_sd}) to vc_conn;
+ }
+ [] PROC.getcall(RAN_continue_after_n_sd:{?,?}) -> param(last_n_sd, vc_conn) {
+ var integer idx := f_idx_by_comp(vc_conn);
+ ConnectionTable[idx].n_sd := last_n_sd;
+ PROC.reply(RAN_continue_after_n_sd:{last_n_sd, vc_conn}) to vc_conn;
}
#else
[false] CLIENT.receive {}
@@ -1045,6 +1082,7 @@ function main(RanOps ops, charstring id) runs on RAN_Emulation_CT {
var octetstring l3_info;
var hexstring imsi;
var OCT4 tmsi;
+ var integer targetPointCode;
alt {
[g_ran_ops.protocol == RAN_PROTOCOL_BSSAP] as_main_bssap();
@@ -1075,6 +1113,11 @@ function main(RanOps ops, charstring id) runs on RAN_Emulation_CT {
PROC.reply(RAN_register:{l3_info, vc_hdlr}) to vc_hdlr;
}
+ [] PROC.getcall(RAN_register_handoverRequest:{?,?}) -> param(targetPointCode, vc_hdlr) {
+ f_create_expect(omit, vc_hdlr, targetPointCode);
+ PROC.reply(RAN_register_handoverRequest:{targetPointCode, vc_hdlr}) to vc_hdlr;
+ }
+
[] PROC.getcall(RAN_register_imsi:{?,?,?}) -> param(imsi, tmsi, vc_hdlr) {
f_create_imsi(imsi, tmsi, vc_hdlr);
PROC.reply(RAN_register_imsi:{imsi, tmsi, vc_hdlr}) to vc_hdlr;
@@ -1101,18 +1144,26 @@ private function f_mgcp_ep_extract_cic(charstring inp) return integer {
type record ExpectData {
/* L3 payload based on which we can match it */
octetstring l3_payload optional,
+ integer handoverRequestPointCode optional,
/* component reference for this connection */
RAN_ConnHdlr vc_conn
}
/* procedure based port to register for incoming connections */
signature RAN_register(in octetstring l3, in RAN_ConnHdlr hdlr);
+signature RAN_register_handoverRequest(in integer targetPointCode, in RAN_ConnHdlr hdlr);
/* procedure based port to register for incoming IMSI/TMSI */
signature RAN_register_imsi(in hexstring imsi, in OCT4 tmsi, in RAN_ConnHdlr hdlr);
+/* If DTAP happens across other channels (e.g. GSUP), provide manual advancing of the n_sd sequence number */
+signature RAN_last_n_sd(in RAN_ConnHdlr hdlr, out N_Sd_Array last_n_sd);
+
+/* Update conn's n_sd sequence nr after the connection was taken over from elsewhere */
+signature RAN_continue_after_n_sd(N_Sd_Array last_n_sd, in RAN_ConnHdlr hdlr);
+
type port RAN_PROC_PT procedure {
- inout RAN_register, RAN_register_imsi;
+ inout RAN_register, RAN_register_imsi, RAN_register_handoverRequest, RAN_last_n_sd, RAN_continue_after_n_sd;
} with { extension "internal" };
#ifdef RAN_EMULATION_BSSAP
@@ -1121,16 +1172,35 @@ function ExpectedCreateCallback(BSSAP_N_CONNECT_ind conn_ind, charstring id)
runs on RAN_Emulation_CT return RAN_ConnHdlr {
var RAN_ConnHdlr ret := null;
var octetstring l3_info;
+ var boolean handoverRequest := false;
+ var integer handoverRequestPointCode;
var integer i;
- if (not ischosen(conn_ind.userData.pdu.bssmap.completeLayer3Information)) {
- setverdict(fail, "N-CONNECT.ind with L3 != COMPLETE L3");
+ if (ischosen(conn_ind.userData.pdu.bssmap.completeLayer3Information)) {
+ l3_info := conn_ind.userData.pdu.bssmap.completeLayer3Information.layer3Information.layer3info;
+ log("ExpectedCreateCallback completeLayer3Information");
+ } else if (ischosen(conn_ind.userData.pdu.bssmap.handoverRequest)) {
+ handoverRequest := true;
+ handoverRequestPointCode := bit2int(conn_ind.calledAddress.signPointCode);
+ log("ExpectedCreateCallback handoverRequest ", handoverRequestPointCode);
+ } else {
+ setverdict(fail, "N-CONNECT.ind with L3 != COMPLETE L3 nor a Handover Request");
mtc.stop;
return ret;
}
- l3_info := conn_ind.userData.pdu.bssmap.completeLayer3Information.layer3Information.layer3info;
for (i := 0; i < sizeof(ExpectTable); i:= i+1) {
+ if (handoverRequest) {
+ log("ExpectTable[", i, "].handoverRequestPointCode = ", ExpectTable[i].handoverRequestPointCode,
+ " ==? ", handoverRequestPointCode);
+ if (ExpectTable[i].handoverRequestPointCode == handoverRequestPointCode) {
+ ret := ExpectTable[i].vc_conn;
+ log("Found Expect[", i, "] for handoverRequest handled at ", ret);
+ return ret;
+ } else {
+ continue;
+ }
+ }
if (not ispresent(ExpectTable[i].l3_payload)) {
continue;
}
@@ -1185,14 +1255,26 @@ runs on RAN_Emulation_CT return RAN_ConnHdlr {
}
#endif
-private function f_create_expect(octetstring l3, RAN_ConnHdlr hdlr)
+private function f_create_expect(template octetstring l3, RAN_ConnHdlr hdlr,
+ template integer handoverRequestPointCode := omit)
runs on RAN_Emulation_CT {
var integer i;
+ log("f_create_expect(l3 := ", l3, ", handoverRequest := ", handoverRequestPointCode);
for (i := 0; i < sizeof(ExpectTable); i := i+1) {
- if (not ispresent(ExpectTable[i].l3_payload)) {
- ExpectTable[i].l3_payload := l3;
+ if (not ispresent(ExpectTable[i].l3_payload)
+ and not ispresent(ExpectTable[i].handoverRequestPointCode)) {
+ if (ispresent(l3)) {
+ ExpectTable[i].l3_payload := valueof(l3);
+ }
+ if (ispresent(handoverRequestPointCode)) {
+ ExpectTable[i].handoverRequestPointCode := valueof(handoverRequestPointCode);
+ }
ExpectTable[i].vc_conn := hdlr;
- log("Created Expect[", i, "] for ", l3, " to be handled at ", hdlr);
+ if (ispresent(handoverRequestPointCode)) {
+ log("Created Expect[", i, "] for handoverRequest to be handled at ", hdlr);
+ } else {
+ log("Created Expect[", i, "] for ", l3, " to be handled at ", hdlr);
+ }
return;
}
}
@@ -1218,6 +1300,7 @@ private function f_expect_table_init()
runs on RAN_Emulation_CT {
for (var integer i := 0; i < sizeof(ExpectTable); i := i+1) {
ExpectTable[i].l3_payload := omit;
+ ExpectTable[i].handoverRequestPointCode := omit;
}
}
diff --git a/msc/BSC_ConnectionHandler.ttcn b/msc/BSC_ConnectionHandler.ttcn
index 44d3c6da..1cec69c3 100644
--- a/msc/BSC_ConnectionHandler.ttcn
+++ b/msc/BSC_ConnectionHandler.ttcn
@@ -1133,6 +1133,27 @@ function f_expect_clear(float t := 5.0) runs on BSC_ConnHdlr {
}
}
+function f_create_bssmap_exp_handoverRequest(integer targetPointCode) runs on BSC_ConnHdlr {
+ BSSAP_PROC.call(RAN_register_handoverRequest:{targetPointCode, self}) {
+ [] BSSAP_PROC.getreply(RAN_register_handoverRequest:{?, ?}) {};
+ }
+}
+
+function f_bssmap_last_n_sd() runs on BSC_ConnHdlr return N_Sd_Array {
+ var N_Sd_Array last_n_sd;
+ BSSAP_PROC.call(RAN_last_n_sd:{self, -}) {
+ [] BSSAP_PROC.getreply(RAN_last_n_sd:{self, ?}) -> param(last_n_sd) {
+ return last_n_sd;
+ };
+ }
+}
+
+function f_bssmap_continue_after_n_sd(N_Sd_Array last_n_sd) runs on BSC_ConnHdlr {
+ BSSAP_PROC.call(RAN_continue_after_n_sd:{last_n_sd, self}) {
+ [] BSSAP_PROC.getreply(RAN_continue_after_n_sd:{last_n_sd, self});
+ }
+}
+
type record SmsParametersTp {
OCT1 msg_ref,
TP_DA da,
diff --git a/msc/MSC_Tests.ttcn b/msc/MSC_Tests.ttcn
index 709a73cb..3a6711b0 100644
--- a/msc/MSC_Tests.ttcn
+++ b/msc/MSC_Tests.ttcn
@@ -468,31 +468,6 @@ modifies ts_BSSAP_BSSMAP := {
}
}
-template PDU_BSSAP ts_BSSMAP_HandoReq(BssmapCause cause, BSSMAP_IE_CellIdentifierList cid_list)
-modifies ts_BSSAP_BSSMAP := {
- pdu := {
- bssmap := {
- handoverRequired := {
- messageType := '11'O,
- cause := ts_BSSMAP_IE_Cause(cause),
- responseRequest := omit,
- cellIdentifierList := cid_list,
- circuitPoolList := omit,
- currentChannelType1 := omit,
- speechVersion := omit,
- queueingIndicator := omit,
- oldToNewBSSInfo := omit,
- sourceToTargetRNCTransparentInfo := omit,
- sourceToTargetRNCTransparentInfoCDMA := omit,
- gERANClassmark := omit,
- talkerPriority := omit,
- speechCodec := omit,
- cSG_Identifier := omit
- }
- }
- }
-}
-
type function void_fn(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr;
/* FIXME: move into BSC_ConnectionHandler? */
@@ -536,14 +511,14 @@ runs on MTC_CT return BSC_ConnHdlrPars {
return pars;
}
-function f_start_handler_with_pars(void_fn fn, BSC_ConnHdlrPars pars) runs on MTC_CT return BSC_ConnHdlr {
+function f_start_handler_with_pars(void_fn fn, BSC_ConnHdlrPars pars, integer bssap_idx := 0) runs on MTC_CT return BSC_ConnHdlr {
var BSC_ConnHdlr vc_conn;
- var charstring id := testcasename();
+ var charstring id := testcasename() & int2str(bssap_idx);
vc_conn := BSC_ConnHdlr.create(id);
/* BSSMAP part / A interface */
- connect(vc_conn:BSSAP, g_bssap[pars.ran_idx].vc_RAN:CLIENT);
- connect(vc_conn:BSSAP_PROC, g_bssap[pars.ran_idx].vc_RAN:PROC);
+ connect(vc_conn:BSSAP, g_bssap[pars.ran_idx + bssap_idx].vc_RAN:CLIENT);
+ connect(vc_conn:BSSAP_PROC, g_bssap[pars.ran_idx + bssap_idx].vc_RAN:PROC);
/* MNCC part */
connect(vc_conn:MNCC, vc_MNCC:MNCC_CLIENT);
connect(vc_conn:MNCC_PROC, vc_MNCC:MNCC_PROC);
@@ -4776,6 +4751,464 @@ testcase TC_sgsap_vlr_failure() runs on MTC_CT {
*
*/
+private function f_tc_ho_inter_bsc_unknown_cell(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
+ f_init_handler(pars);
+ var CallParameters cpars := valueof(t_CallParams('12345'H, 0));
+ cpars.bss_rtp_port := 1110;
+ cpars.mgcp_connection_id_bss := '22222'H;
+ cpars.mgcp_connection_id_mss := '33333'H;
+ cpars.mgcp_ep := "rtpbridge/1@mgw";
+ cpars.mo_call := true;
+
+ f_perform_lu();
+ f_mo_call_establish(cpars);
+
+ f_sleep(1.0);
+
+ var myBSSMAP_Cause cause_val := GSM0808_CAUSE_BETTER_CELL;
+ var BssmapCause cause := enum2int(cause_val);
+
+ var template BSSMAP_FIELD_CellIdentificationList cil;
+ cil := { cIl_LAI := { ts_BSSMAP_CI_LAI('023'H, '42'H, 999) } };
+
+ BSSAP.send(ts_BSSMAP_HandoverRequired(cause, cil));
+ BSSAP.receive(tr_BSSMAP_HandoverRequiredReject);
+
+ f_call_hangup(cpars, true);
+}
+testcase TC_ho_inter_bsc_unknown_cell() runs on MTC_CT {
+ var BSC_ConnHdlr vc_conn;
+ f_init();
+
+ vc_conn := f_start_handler(refers(f_tc_ho_inter_bsc_unknown_cell), 53);
+ vc_conn.done;
+}
+
+private altstep as_mgcp_ack_all_mdcx(CallParameters cpars) runs on BSC_ConnHdlr {
+ var MgcpCommand mgcp_cmd;
+ [] MGCP.receive(tr_MDCX) -> value mgcp_cmd {
+ var SDP_Message sdp := valueof(ts_SDP(cpars.mgw_rtp_ip_mss, cpars.mgw_rtp_ip_mss,
+ hex2str(cpars.mgcp_call_id), "42",
+ cpars.mgw_rtp_port_mss,
+ { int2str(cpars.rtp_payload_type) },
+ { valueof(ts_SDP_rtpmap(cpars.rtp_payload_type,
+ cpars.rtp_sdp_format)),
+ valueof(ts_SDP_ptime(20)) }));
+ MGCP.send(ts_MDCX_ACK(mgcp_cmd.line.trans_id, cpars.mgcp_connection_id_mss, sdp));
+ repeat;
+ }
+}
+
+private function f_tc_ho_inter_bsc0(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
+ var CallParameters cpars := valueof(t_CallParams('12345'H, 0));
+ cpars.bss_rtp_port := 1110;
+ cpars.mgcp_connection_id_bss := '22222'H;
+ cpars.mgcp_connection_id_mss := '33333'H;
+ cpars.mgcp_ep := "rtpbridge/1@mgw";
+ cpars.mo_call := true;
+
+ f_init_handler(pars);
+
+ f_vty_transceive(MSCVTY, "configure terminal");
+ f_vty_transceive(MSCVTY, "msc");
+ f_vty_transceive(MSCVTY, "neighbor a cgi 262 42 23 42 ran-pc 0.24.1");
+ f_vty_transceive(MSCVTY, "neighbor a lac 5 ran-pc 0.24.2");
+ f_vty_transceive(MSCVTY, "exit");
+ f_vty_transceive(MSCVTY, "exit");
+
+ f_perform_lu();
+ f_mo_call_establish(cpars);
+
+ f_sleep(1.0);
+
+ var default ack_mdcx := activate(as_mgcp_ack_all_mdcx(cpars));
+
+ var myBSSMAP_Cause cause_val := GSM0808_CAUSE_BETTER_CELL;
+ var BssmapCause cause := enum2int(cause_val);
+
+ var template BSSMAP_FIELD_CellIdentificationList cil;
+ cil := { cIl_LAI := { ts_BSSMAP_CI_LAI('023'H, '42'H, 5) } };
+
+ /* old BSS sends Handover Required */
+ BSSAP.send(ts_BSSMAP_HandoverRequired(cause, cil));
+
+ /* Now the action goes on in f_tc_ho_inter_bsc1() */
+
+ /* MSC forwards the RR Handover Command to old BSS */
+ var PDU_BSSAP ho_command;
+ BSSAP.receive(tr_BSSMAP_HandoverCommand) -> value ho_command;
+
+ log("GOT HandoverCommand", ho_command);
+
+ BSSAP.receive(tr_BSSMAP_HandoverSucceeded);
+
+ /* f_tc_ho_inter_bsc1() completes Handover, then expecting a Clear here. */
+ f_expect_clear();
+
+ log("FIRST inter-BSC Handover done");
+
+
+ /* ------------------------ */
+
+ /* Ok, that went well, now the other BSC is handovering back here --
+ * from now on this here is the new BSS. */
+ f_create_bssmap_exp_handoverRequest(193);
+
+ var PDU_BSSAP ho_request;
+ BSSAP.receive(tr_BSSMAP_HandoverRequest) -> value ho_request;
+
+ /* new BSS composes a RR Handover Command */
+ var PDU_ML3_NW_MS rr_ho_cmd := valueof(ts_RR_HandoverCommand);
+ var octetstring rr_ho_cmd_enc := enc_PDU_ML3_NW_MS(rr_ho_cmd);
+ var BSSMAP_IE_AoIP_TransportLayerAddress tla := valueof(ts_BSSMAP_IE_AoIP_TLA4('01020304'O, 2342));
+ BSSAP.send(ts_BSSMAP_HandoverRequestAcknowledge(rr_ho_cmd_enc, lengthof(rr_ho_cmd_enc),
+ tla, ts_BSSMAP_IE_SpeechCodec({ts_CodecFR})));
+
+ /* Now f_tc_ho_inter_bsc1() expects HandoverCommand */
+
+ f_sleep(0.5);
+
+ /* Notify that the MS is now over here */
+
+ BSSAP.send(ts_BSSMAP_HandoverDetect);
+ f_sleep(0.1);
+ BSSAP.send(ts_BSSMAP_HandoverComplete);
+
+ f_sleep(3.0);
+
+ deactivate(ack_mdcx);
+
+ var default ccrel := activate(as_optional_cc_rel(cpars, true));
+
+ /* blatant cheating */
+ var N_Sd_Array last_n_sd := f_bssmap_last_n_sd();
+ last_n_sd[0] := 3;
+ f_bssmap_continue_after_n_sd(last_n_sd);
+
+ f_call_hangup(cpars, true);
+ f_sleep(1.0);
+ deactivate(ccrel);
+
+ setverdict(pass);
+}
+private function f_tc_ho_inter_bsc1(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
+ f_init_handler(pars);
+ f_create_bssmap_exp_handoverRequest(194);
+
+ var PDU_BSSAP ho_request;
+ BSSAP.receive(tr_BSSMAP_HandoverRequest) -> value ho_request;
+
+ /* new BSS composes a RR Handover Command */
+ var PDU_ML3_NW_MS rr_ho_cmd := valueof(ts_RR_HandoverCommand);
+ var octetstring rr_ho_cmd_enc := enc_PDU_ML3_NW_MS(rr_ho_cmd);
+ var BSSMAP_IE_AoIP_TransportLayerAddress tla := valueof(ts_BSSMAP_IE_AoIP_TLA4('01020304'O, 2342));
+ BSSAP.send(ts_BSSMAP_HandoverRequestAcknowledge(rr_ho_cmd_enc, lengthof(rr_ho_cmd_enc),
+ tla, ts_BSSMAP_IE_SpeechCodec({ts_CodecFR})));
+
+ /* Now f_tc_ho_inter_bsc0() expects HandoverCommand */
+
+ f_sleep(0.5);
+
+ /* Notify that the MS is now over here */
+
+ BSSAP.send(ts_BSSMAP_HandoverDetect);
+ f_sleep(0.1);
+ BSSAP.send(ts_BSSMAP_HandoverComplete);
+
+ f_sleep(3.0);
+
+ /* Now I'd like to f_call_hangup() but we don't know any cpars here. So
+ * ... handover back to the first BSC :P */
+
+ var myBSSMAP_Cause cause_val := GSM0808_CAUSE_BETTER_CELL;
+ var BssmapCause cause := enum2int(cause_val);
+
+ var template BSSMAP_FIELD_CellIdentificationList cil;
+ cil := { cIl_LAI := { ts_BSSMAP_CI_LAI('262'H, '42'H, 23) } };
+
+ /* old BSS sends Handover Required */
+ BSSAP.send(ts_BSSMAP_HandoverRequired(cause, cil));
+
+ /* Now the action goes on in f_tc_ho_inter_bsc0() */
+
+ /* MSC forwards the RR Handover Command to old BSS */
+ var PDU_BSSAP ho_command;
+ BSSAP.receive(tr_BSSMAP_HandoverCommand) -> value ho_command;
+
+ log("GOT HandoverCommand", ho_command);
+
+ BSSAP.receive(tr_BSSMAP_HandoverSucceeded);
+
+ /* f_tc_ho_inter_bsc1() completes Handover, then expecting a Clear here. */
+ f_expect_clear();
+ setverdict(pass);
+}
+testcase TC_ho_inter_bsc() runs on MTC_CT {
+ var BSC_ConnHdlr vc_conn0;
+ var BSC_ConnHdlr vc_conn1;
+ f_init(2);
+
+ var BSC_ConnHdlrPars pars0 := f_init_pars(53);
+ var BSC_ConnHdlrPars pars1 := f_init_pars(53);
+
+ vc_conn0 := f_start_handler_with_pars(refers(f_tc_ho_inter_bsc0), pars0, 0);
+ vc_conn1 := f_start_handler_with_pars(refers(f_tc_ho_inter_bsc1), pars1, 1);
+ vc_conn0.done;
+ vc_conn1.done;
+}
+
+function f_ML3_patch_seq_nr_MS_NW(in uint2_t seq_nr, inout octetstring enc_l3) {
+ log("MS_NW patching N(SD)=", seq_nr, " into dtap ", enc_l3);
+ enc_l3[2] := (enc_l3[2] and4b '3f'O) or4b bit2oct(int2bit(seq_nr, 8) << 6);
+ log("MS_NW patched enc_l3: ", enc_l3);
+}
+
+private function f_tc_ho_inter_msc_out(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
+ var CallParameters cpars := valueof(t_CallParams('12345'H, 0));
+ cpars.bss_rtp_port := 1110;
+ cpars.mgcp_connection_id_bss := '22222'H;
+ cpars.mgcp_connection_id_mss := '33333'H;
+ cpars.mgcp_ep := "rtpbridge/1@mgw";
+ cpars.mo_call := true;
+ var hexstring ho_number := f_gen_msisdn(99999);
+
+ f_init_handler(pars);
+
+ f_create_mncc_expect(hex2str(ho_number));
+
+ f_vty_transceive(MSCVTY, "configure terminal");
+ f_vty_transceive(MSCVTY, "msc");
+ f_vty_transceive(MSCVTY, "neighbor a cgi 017 017 1 1 msc-ipa-name msc-017-017-1");
+ f_vty_transceive(MSCVTY, "exit");
+ f_vty_transceive(MSCVTY, "exit");
+
+ f_perform_lu();
+ f_mo_call_establish(cpars);
+
+ f_sleep(1.0);
+
+ var default ack_mdcx := activate(as_mgcp_ack_all_mdcx(cpars));
+
+ var myBSSMAP_Cause cause_val := GSM0808_CAUSE_BETTER_CELL;
+ var BssmapCause cause := enum2int(cause_val);
+
+ var template BSSMAP_FIELD_CellIdentificationList cil;
+ cil := { cIl_LAI := { ts_BSSMAP_CI_LAI('017'H, '017'H, 1) } };
+
+ /* old BSS sends Handover Required */
+ BSSAP.send(ts_BSSMAP_HandoverRequired(cause, cil));
+
+ /* The target cell 017-017 LAC 1 is configured to be a remote MSC of name "msc-017-017-1".
+ * This MSC tries to reach the other MSC via GSUP. */
+
+ var octetstring remote_msc_name := '6D73632D3031372D3031372D3100'O; /* "msc-017-017-1\0" as octetstring */
+ var GSUP_PDU prep_ho_req;
+ GSUP.receive(tr_GSUP_E_AN_APDU(OSMO_GSUP_MSGT_E_PREPARE_HANDOVER_REQUEST,
+ pars.imsi, destination_name := remote_msc_name)) -> value prep_ho_req;
+
+ var GSUP_IeValue source_name_ie;
+ f_gsup_find_ie(prep_ho_req, OSMO_GSUP_SOURCE_NAME_IE, source_name_ie);
+ var octetstring local_msc_name := source_name_ie.source_name;
+
+ /* Remote MSC has figured out its BSC and signals success */
+ var PDU_ML3_NW_MS rr_ho_cmd := valueof(ts_RR_HandoverCommand);
+ var octetstring rr_ho_cmd_enc := enc_PDU_ML3_NW_MS(rr_ho_cmd);
+ var PDU_BSSAP ho_req_ack := valueof(ts_BSSMAP_HandoverRequestAcknowledge(rr_ho_cmd_enc, lengthof(rr_ho_cmd_enc),
+ aoIPTransportLayer := omit,
+ speechCodec := ts_BSSMAP_IE_SpeechCodec({ts_CodecFR})));
+ GSUP.send(ts_GSUP_E_PrepareHandoverResult(
+ pars.imsi,
+ ho_number,
+ remote_msc_name, local_msc_name,
+ valueof(t_GSUP_AN_APDU(OSMO_GSUP_AN_PROTO_48006, enc_PDU_BSSAP(ho_req_ack)))));
+
+ /* MSC forwards the RR Handover Command to old BSS */
+ BSSAP.receive(tr_BSSMAP_HandoverCommand);
+
+ /* The MS shows up at remote new BSS */
+
+ GSUP.send(ts_GSUP_E_AN_APDU(OSMO_GSUP_MSGT_E_PROCESS_ACCESS_SIGNALLING_REQUEST,
+ pars.imsi, remote_msc_name, local_msc_name,
+ valueof(t_GSUP_AN_APDU(OSMO_GSUP_AN_PROTO_48006,
+ enc_PDU_BSSAP(valueof(ts_BSSMAP_HandoverDetect))))));
+ BSSAP.receive(tr_BSSMAP_HandoverSucceeded);
+ f_sleep(0.1);
+
+ /* Save the MS sequence counters for use on the other connection */
+ var N_Sd_Array last_n_sd := f_bssmap_last_n_sd();
+
+ GSUP.send(ts_GSUP_E_AN_APDU(OSMO_GSUP_MSGT_E_SEND_END_SIGNAL_REQUEST,
+ pars.imsi, remote_msc_name, local_msc_name,
+ valueof(t_GSUP_AN_APDU(OSMO_GSUP_AN_PROTO_48006,
+ enc_PDU_BSSAP(valueof(ts_BSSMAP_HandoverComplete))))));
+
+ /* The local BSS conn clears, all communication goes via remote MSC now */
+ f_expect_clear();
+
+ /**********************************/
+ /* Play through some signalling across the inter-MSC link.
+ * This is a copy of f_tc_lu_and_mo_ussd_single_request() translated into GSUP AN-APDUs. */
+
+ if (false) {
+ var template OCTN facility_req := f_USSD_FACILITY_IE_INVOKE(
+ invoke_id := 5, /* Phone may not start from 0 or 1 */
+ op_code := SS_OP_CODE_PROCESS_USS_REQ,
+ ussd_string := "*#100#"
+ );
+
+ var template OCTN facility_rsp := f_USSD_FACILITY_IE_RETURN_RESULT(
+ invoke_id := 5, /* InvokeID shall be the same for both REQ and RSP */
+ op_code := SS_OP_CODE_PROCESS_USS_REQ,
+ ussd_string := "Your extension is " & hex2str(g_pars.msisdn) & "\r"
+ )
+
+ /* Compose a new SS/REGISTER message with request */
+ var template (value) PDU_ML3_MS_NW ussd_req := ts_ML3_MO_SS_REGISTER(
+ tid := 1, /* We just need a single transaction */
+ ti_flag := c_TIF_ORIG, /* Sent from the side that originates the TI */
+ facility := valueof(facility_req)
+ );
+ var PDU_ML3_MS_NW ussd_req_v := valueof(ussd_req);
+
+ /* Compose SS/RELEASE_COMPLETE template with expected response */
+ var template PDU_ML3_NW_MS ussd_rsp := tr_ML3_MT_SS_RELEASE_COMPLETE(
+ tid := 1, /* Response should arrive within the same transaction */
+ ti_flag := c_TIF_REPL, /* Sent to the side that originates the TI */
+ facility := valueof(facility_rsp)
+ );
+
+ /* Compose expected MSC -> HLR message */
+ var template GSUP_PDU gsup_req := tr_GSUP_PROC_SS_REQ(
+ imsi := g_pars.imsi,
+ state := OSMO_GSUP_SESSION_STATE_BEGIN,
+ ss := valueof(facility_req)
+ );
+
+ /* To be used for sending response with correct session ID */
+ var GSUP_PDU gsup_req_complete;
+
+ /* Request own number */
+ /* From remote MSC instead of BSSAP directly */
+ /* Patch the correct N_SD value into the message. */
+ var octetstring l3_enc := enc_PDU_ML3_MS_NW(ussd_req_v);
+ var RAN_Emulation.ConnectionData cd;
+ f_ML3_patch_seq_nr_MS_NW(f_next_n_sd(last_n_sd, f_ML3_n_sd_idx(ussd_req_v)), l3_enc);
+ GSUP.send(ts_GSUP_E_AN_APDU(OSMO_GSUP_MSGT_E_PROCESS_ACCESS_SIGNALLING_REQUEST,
+ pars.imsi, remote_msc_name, local_msc_name,
+ valueof(t_GSUP_AN_APDU(OSMO_GSUP_AN_PROTO_48006,
+ enc_PDU_BSSAP(valueof(ts_BSSAP_DTAP(l3_enc)))
+ ))
+ ));
+
+ /* Expect GSUP message containing the SS payload */
+ gsup_req_complete := f_expect_gsup_msg(gsup_req);
+
+ /* Compose the response from HLR using received session ID */
+ var template GSUP_PDU gsup_rsp := ts_GSUP_PROC_SS_REQ(
+ imsi := g_pars.imsi,
+ sid := gsup_req_complete.ies[1].val.session_id,
+ state := OSMO_GSUP_SESSION_STATE_END,
+ ss := valueof(facility_rsp)
+ );
+
+ /* Finally, HLR terminates the session */
+ GSUP.send(gsup_rsp);
+
+ /* The USSD response goes out to remote MSC, on GSUP E instead of BSSAP */
+ var GSUP_PDU gsup_ussd_rsp;
+ GSUP.receive(tr_GSUP_E_AN_APDU(OSMO_GSUP_MSGT_E_FORWARD_ACCESS_SIGNALLING_REQUEST,
+ pars.imsi, destination_name := remote_msc_name)) -> value gsup_ussd_rsp;
+
+ var GSUP_IeValue an_apdu;
+ if (not f_gsup_find_ie(gsup_ussd_rsp, OSMO_GSUP_AN_APDU_IE, an_apdu)) {
+ setverdict(fail, "No AN-APDU in received GSUP message. Expected USSD response in DTAP, got", gsup_ussd_rsp);
+ mtc.stop;
+ }
+ var PDU_BSSAP bssap_dtap_mt := dec_PDU_BSSAP(an_apdu.an_apdu.pdu);
+ var PDU_ML3_NW_MS dtap_mt := dec_PDU_ML3_NW_MS(bssap_dtap_mt.pdu.dtap);
+ log("Expecting", ussd_rsp);
+ log("Got", dtap_mt);
+ if (not match(dtap_mt, ussd_rsp)) {
+ setverdict(fail, "Unexpected GSUP message. Expected USSD response in DTAP, got", gsup_ussd_rsp);
+ mtc.stop;
+ }
+ }
+ /**********************************/
+
+
+ /* inter-MSC handover back to the first MSC */
+ f_create_bssmap_exp_handoverRequest(193);
+ cil := { cIl_CGI := { ts_BSSMAP_CI_CGI('262'H, '42'H, 23, 42) } };
+
+ /* old BSS sends Handover Required, via inter-MSC E link: like
+ * BSSAP.send(ts_BSSMAP_HandoverRequired(cause, cil));
+ * but via GSUP */
+ GSUP.send(ts_GSUP_E_AN_APDU(OSMO_GSUP_MSGT_E_PREPARE_SUBSEQUENT_HANDOVER_REQUEST,
+ pars.imsi, remote_msc_name, local_msc_name,
+ valueof(t_GSUP_AN_APDU(OSMO_GSUP_AN_PROTO_48006,
+ enc_PDU_BSSAP(valueof(ts_BSSMAP_HandoverRequired(cause, cil)))
+ ))
+ ));
+
+ /* MSC asks local BSS to prepare Handover to it */
+ BSSAP.receive(tr_BSSMAP_HandoverRequest);
+
+ /* Make sure the new BSSAP conn continues with the correct N_SD sequence numbers */
+ f_bssmap_continue_after_n_sd(last_n_sd);
+
+ /* new BSS composes a RR Handover Command */
+ rr_ho_cmd := valueof(ts_RR_HandoverCommand);
+ rr_ho_cmd_enc := enc_PDU_ML3_NW_MS(rr_ho_cmd);
+ var BSSMAP_IE_AoIP_TransportLayerAddress tla := valueof(ts_BSSMAP_IE_AoIP_TLA4('01020304'O, 2342));
+ BSSAP.send(ts_BSSMAP_HandoverRequestAcknowledge(rr_ho_cmd_enc, lengthof(rr_ho_cmd_enc),
+ tla, ts_BSSMAP_IE_SpeechCodec({ts_CodecFR})));
+
+ /* HandoverCommand goes out via remote MSC-I */
+ var GSUP_PDU prep_subsq_ho_res;
+ GSUP.receive(tr_GSUP_E_AN_APDU(OSMO_GSUP_MSGT_E_PREPARE_SUBSEQUENT_HANDOVER_RESULT,
+ pars.imsi, destination_name := remote_msc_name)) -> value prep_subsq_ho_res;
+
+ /* MS shows up at the local BSS */
+ BSSAP.send(ts_BSSMAP_HandoverDetect);
+ f_sleep(0.1);
+ BSSAP.send(ts_BSSMAP_HandoverComplete);
+
+ /* Handover Succeeded message */
+ GSUP.receive(tr_GSUP_E_AN_APDU(OSMO_GSUP_MSGT_E_FORWARD_ACCESS_SIGNALLING_REQUEST,
+ pars.imsi, destination_name := remote_msc_name));
+
+ /* MS has handovered to here, Clear Command goes out via remote MSC-I -- in form of a GSUP Close. */
+ GSUP.receive(tr_GSUP_E_NO_PDU(OSMO_GSUP_MSGT_E_CLOSE,
+ pars.imsi, destination_name := remote_msc_name));
+
+ /* Handover ends successfully. Call goes on for a little longer and then we hang up. */
+
+ f_sleep(1.0);
+ deactivate(ack_mdcx);
+
+ /* FIXME: the inter-MSC call has put a number of MNCC messages in the queue, which above code should expect and
+ * clear out. The f_call_hangup() expects an MNCC_REL_IND, so, for the time being, just clear the MNCC messages
+ * before starting the call hangup. Instead of this, the individual messages should be tested for above. */
+ MNCC.clear;
+
+ var default ccrel := activate(as_optional_cc_rel(cpars, true));
+ f_call_hangup(cpars, true);
+ f_sleep(1.0);
+ deactivate(ccrel);
+
+ setverdict(pass);
+}
+testcase TC_ho_inter_msc_out() runs on MTC_CT {
+ var BSC_ConnHdlr vc_conn;
+ f_init(1);
+
+ var BSC_ConnHdlrPars pars := f_init_pars(54);
+
+ vc_conn := f_start_handler_with_pars(refers(f_tc_ho_inter_msc_out), pars, 0);
+ vc_conn.done;
+}
+
+
control {
execute( TC_cr_before_reset() );
execute( TC_lu_imsi_noauth_tmsi() );
@@ -4870,6 +5303,11 @@ control {
execute( TC_sgsap_lu_and_mt_call() );
execute( TC_sgsap_vlr_failure() );
+ execute( TC_ho_inter_bsc_unknown_cell() );
+ execute( TC_ho_inter_bsc() );
+
+ execute( TC_ho_inter_msc_out() );
+
/* 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() );
execute( TC_gsup_mt_multi_part_sms() );