diff options
author | Daniel <0xc0decafe@users.noreply.github.com> | 2015-12-15 17:11:26 +0100 |
---|---|---|
committer | Daniel <0xc0decafe@users.noreply.github.com> | 2015-12-15 17:11:26 +0100 |
commit | 07769ca8ec29c50cff5b23e34b873411514c7940 (patch) | |
tree | 48fb77de9e7918a87f896f59a355c81937418f92 /src |
Initial commit, including basic HLR testing functionality.
Diffstat (limited to 'src')
-rw-r--r-- | src/hex.erl | 33 | ||||
-rw-r--r-- | src/map_msgs.erl | 590 | ||||
-rw-r--r-- | src/sms_7bit_encoding.erl | 67 | ||||
-rw-r--r-- | src/ss7test.app.src | 12 | ||||
-rw-r--r-- | src/ss7test_app.erl | 544 | ||||
-rw-r--r-- | src/ss7test_app.hrl | 6 | ||||
-rw-r--r-- | src/ss7test_helper.erl | 48 | ||||
-rw-r--r-- | src/ss7test_sup.erl | 27 |
8 files changed, 1327 insertions, 0 deletions
diff --git a/src/hex.erl b/src/hex.erl new file mode 100644 index 0000000..8529f95 --- /dev/null +++ b/src/hex.erl @@ -0,0 +1,33 @@ +-module(hex). +-export([bin_to_hexstr/1,hexstr_to_bin/1]). + +hex(N) when N < 10 -> + $0+N; +hex(N) when N >= 10, N < 16 -> + $a+(N-10). + +int(C) when $0 =< C, C =< $9 -> + C - $0; +int(C) when $A =< C, C =< $F -> + C - $A + 10; +int(C) when $a =< C, C =< $f -> + C - $a + 10. + +to_hex(N) when N < 256 -> + [hex(N div 16), hex(N rem 16)]. + +list_to_hexstr([]) -> + []; +list_to_hexstr([H|T]) -> + to_hex(H) ++ list_to_hexstr(T). + +bin_to_hexstr(Bin) -> + list_to_hexstr(binary_to_list(Bin)). + +hexstr_to_bin(S) -> + list_to_binary(hexstr_to_list(S)). + +hexstr_to_list([X,Y|T]) -> + [int(X)*16 + int(Y) | hexstr_to_list(T)]; +hexstr_to_list([]) -> + []. diff --git a/src/map_msgs.erl b/src/map_msgs.erl new file mode 100644 index 0000000..e70b9c7 --- /dev/null +++ b/src/map_msgs.erl @@ -0,0 +1,590 @@ +-module(map_msgs). +-author('Daniel Mende <mail@c0decafe.de>'). + +-include_lib("osmo_map/src/map.hrl"). +-include("ss7test_app.hrl"). + +-compile([export_all]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% default values msgs +%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% SCCP Definitions +-define(LOCAL_GLOBAL_TITLE, [1,2,3,4,5,6,7,8,9]). +-define(REMOTE_GLOBAL_TITLE, [1,2,3,4,5,6,7,8,0]). +-define(NI, 2). + +% MAP Definitions +-define(IMSI, hex:hexstr_to_bin("01020304050607f8")). +-define(IMSI_AS_NR, ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_LAND_MOBILE, + [0,1,0,2,0,3,0,4,0,5,0,6,0,7,8])). +-define(TMSI, hex:hexstr_to_bin("1234")). + +-define(MSISDN, ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_PLAN_ISDN, + [1,2,3,4,5,6,7,8,9,0])). + +-define(SERVICE_CENTER_ADDRESS, hex:hexstr_to_bin("010203040506f1")). +-define(SERVICE_CENTER_ADDRESS_OA, hex:hexstr_to_bin("010203040506f1")). +-define(SERVICE_CENTER_ADDRESS_DA, hex:hexstr_to_bin("010203040506f1")). +-define(GGSN, ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_PLAN_ISDN, + [1,2,3,4,5,6,7,8,9,0])). + + + +% SMS Definitions +-define(ORIGINATING_ADDRESS, hex:hexstr_to_bin("0b9010203040506f1")). +-define(DESTINATION_ADDRESS, ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_PLAN_ISDN, + [1,2,3,4,5,6,7,8,9,0])). +-define(SOURCE_ADDRESS, ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_PLAN_ISDN, + [1,2,3,4,5,6,7,8,9,0])). +-define(SMS_DEST_NR, [1,2,3,4,5,6,7,8,9,0]). +-define(SMS_SRC_NR, [1,2,3,4,5,6,7,8,9,0]). + +-define(IMEI, ss7test_helper:encode_phonenumner([1,2,3,4,5,6,7,8,9,0])). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% helper +%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +get_transactionId() -> + <<1,1,0,0>>. + +build_dialog_request(Context) -> + build_dialog_request(Context, asn1_NOVALUE). +build_dialog_request(Context, Extra) -> + DialoguePDU = {'dialogueRequest', + {'AARQ-apdu', + [version1], + Context, + Extra}}, + {ok, EncDialoguePDU} = map:encode('DialoguePDU', DialoguePDU), + EncDialoguePDU. + +encode_map_pdu(Dialog, Local, MapData) -> + MapPDU = {'begin', + {'MapSpecificPDUs_begin', + get_transactionId(), + {'EXTERNAL', + ?'dialogue-as-id', + asn1_NOVALUE,asn1_NOVALUE, + {'single-ASN1-type', Dialog}}, + [{basicROS, + {invoke, + {'MapSpecificPDUs_begin_components_SEQOF_basicROS_invoke', + {present,1}, + asn1_NOVALUE, + {local,Local}, + MapData}}}]}}, + {ok, EncMapPDU} = map:encode('MapSpecificPDUs', MapPDU), + EncMapPDU. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SMS +%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +create_testSMSPDU_mt() -> + SMSText = "ERNW test SMS 31337", + EncSMSText = 'sms_7bit_encoding':to_7bit(SMSText), + SMSLen = string:len(SMSText), + Timestamp = hex:hexstr_to_bin("51803001258080"), + DA = ss7test_helper:encode_phonenumber(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_PLAN_ISDN, + ?SMS_SRC_NR), + <<0:4, 4:4, DA/binary, 0:8, 0:8, Timestamp/binary, SMSLen:8, EncSMSText/binary>>. + +create_testSMSPDU_mo() -> + SMSText = "ERNW test SMS 31337", + EncSMSText = 'sms_7bit_encoding':to_7bit(SMSText), + SMSLen = string:len(SMSText), + DA = ss7test_helper:encode_phonenumber(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_PLAN_ISDN, + ?SMS_DEST_NR), + <<1:8, 23:8, DA/binary, 0:8, 0:8, SMSLen:8, EncSMSText/binary>>. + +create_mt_forwardSM_v2() -> + create_mt_forwardSM_v2(create_testSMSPDU_mt()). +create_mt_forwardSM_v2(SMSPDU) -> + MapData = { 'ForwardSM-Arg', + {imsi, ?IMSI}, + {serviceCentreAddressOA, ?SERVICE_CENTER_ADDRESS_DA}, + SMSPDU, + asn1_NOVALUE, asn1_NOVALUE}, + Dialog = build_dialog_request({0,4,0,0,1,0,25,2}), + encode_map_pdu(Dialog, 46, MapData). + +create_mt_forwardSM() -> + create_mt_forwardSM(create_testSMSPDU_mt()). +create_mt_forwardSM(SMSPDU) -> + MapData = {'MT-ForwardSM-Arg', + {serviceCentreAddressDA, ?SERVICE_CENTER_ADDRESS_DA}, + {msisdn, ?SOURCE_ADDRESS}, + SMSPDU, + asn1_NOVALUE, %moreMessagesToSend + asn1_NOVALUE %extensionContainer + }, + Dialog = build_dialog_request(?'shortMsgMT-RelayContext-v3'), + encode_map_pdu(Dialog, 44, MapData). + +create_mo_forwardSM_v2() -> + create_mo_forwardSM_v2(create_testSMSPDU_mo()). +create_mo_forwardSM_v2(SMSPDU) -> + MapData = { 'ForwardSM-Arg', + {serviceCentreAddressDA, ?SERVICE_CENTER_ADDRESS_DA}, + {msisdn, ?MSISDN}, + SMSPDU, + asn1_NOVALUE, asn1_NOVALUE}, + Dialog = build_dialog_request({0,4,0,0,1,0,21,2}), + encode_map_pdu(Dialog, 46, MapData). + +create_mo_forwardSM() -> + create_mo_forwardSM(create_testSMSPDU_mo()). +create_mo_forwardSM(SMSPDU) -> + MapData = {'MO-ForwardSM-Arg', + {serviceCentreAddressDA, ?SERVICE_CENTER_ADDRESS_DA}, + {msisdn, ?MSISDN}, + SMSPDU, + asn1_NOVALUE, + asn1_NOVALUE % ?IMSI_FROM + }, + Dialog = build_dialog_request(?'shortMsgMO-RelayContext-v3'), + encode_map_pdu(Dialog, 46, MapData). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% to HLR +%%%%%%%%%%%%%%%%%%%%%%%%%%%% +create_sendRoutingInfoForSM() -> + create_sendRoutingInfoForSM(?MSISDN, ?SERVICE_CENTER_ADDRESS). +create_sendRoutingInfoForSM(Msisdn, Ssaddr) -> + MapData = { 'send-routing-info-for-sm-arg', + Msisdn, + false, + Ssaddr, + asn1_NOVALUE, + asn1_NOVALUE, %true, + asn1_NOVALUE, %0, + asn1_NOVALUE, %hex:hexstr_to_bin("0b912374140404f7"), + asn1_NOVALUE}, + MapPDU = {'begin', + {'MapSpecificPDUs_begin', + get_transactionId(), + {'EXTERNAL', + {0,0,17,773,1,1,1}, + asn1_NOVALUE, + asn1_NOVALUE, + {'single-ASN1-type',<<96,11,161,9,6,7,4,0,0,1,0,20,3>>}}, + [{'basicROS', + {'invoke', + {'MapSpecificPDUs_begin_components_SEQOF_basicROS_invoke', + {'present', 1}, + asn1_NOVALUE, + {'local', 45}, + MapData}}}]}}, + {ok, EncMapPDU} = map:encode('MapSpecificPDUs', MapPDU), + EncMapPDU. + +create_sendRoutingInfo() -> + create_sendRoutingInfo(?MSISDN, ?LOCAL_GLOBAL_TITLE). +create_sendRoutingInfo(Msisdn, OrGsmSCF) -> + MapData = {'SendRoutingInfoArg', + Msisdn, + asn1_NOVALUE, + asn1_NOVALUE, + basicCall, + asn1_NOVALUE, + asn1_NOVALUE, + ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_PLAN_ISDN, + OrGsmSCF), %gsmc-OrGsmSCF-Address + <<7,0,1,68,40,9,150,31>>, %callReferenceNumber + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + {'CamelInfo', + [phase1,phase2,phase3,phase4], + asn1_NOVALUE, + asn1_NOVALUE, + ['o-csi','d-csi','t-csi']}, + asn1_NOVALUE, + {'ExtensionContainer', + [{'PrivateExtension',{1,2,826,0,1249,58,1,0},<<164,5,48,3,129,1,6>>}, %Nokia ExtensionType Extension + {'PrivateExtension',{0,34,5},<<224,2,132,0>>}], %Nokia srbtSupportIndicator + asn1_NOVALUE}, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, %'NULL', + asn1_NOVALUE, + asn1_NOVALUE, %'NULL', + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE}, + MapPDU = {'begin', + {'MapSpecificPDUs_begin', + get_transactionId(), + {'EXTERNAL', + {0,0,17,773,1,1,1}, + asn1_NOVALUE,asn1_NOVALUE, + {'single-ASN1-type', + <<96,15,128,2,7,128,161,9,6,7,4,0,0,1,0,5,3>>}}, + [{basicROS, + {invoke, + {'MapSpecificPDUs_begin_components_SEQOF_basicROS_invoke', + {present,1}, + asn1_NOVALUE, + {local,22}, + MapData}}}]}}, + {ok, EncMapPDU} = map:encode('MapSpecificPDUs', MapPDU), + EncMapPDU. + +%~ create_sendRoutingInfoForGprs() -> + %~ MapData = {'SendRoutingInforForGprsArg', + %~ ?IMSI, + %~ asn1_NOVALUE, + %~ ?GGSN}, + %~ MapPDU = {'begin', + %~ {'MapSpecificPDUs_begin', + %~ get_transactionId(), + %~ {'EXTERNAL', + %~ {0,0,17,773,1,1,1}, + %~ asn1_NOVALUE,asn1_NOVALUE, + %~ {'single-ASN1-type',<<96,15,128,2,7,128,161,9,6,7,4,0,0,1,0,33,4>>}}, + %~ [{basicROS, + %~ {invoke, + %~ {'MapSpecificPDUs_begin_components_SEQOF_basicROS_invoke', + %~ {present,1}, + %~ asn1_NOVALUE, + %~ {local,24}, + %~ MapData}}}]}}, + %~ {ok, EncMapPDU} = map:encode('MapSpecificPDUs', MapPDU), + %~ EncMapPDU. + +%~ create_registerSS() -> + %~ create_registerSS(?IMSI, ?DESTINATION_ADDRESS). +create_registerSS(Imsi, Origin, DestinationNumber) -> + MapDialoguePDU = {'map-open', + {'MAP-OpenInfo', + ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_LAND_MOBILE, + Imsi), %destinationReference + ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_PLAN_ISDN, + Origin), %originationReference + asn1_NOVALUE }}, + {ok, EncMapDialoguePDU} = map:encode('MAP-DialoguePDU', MapDialoguePDU), + DialoguePDU = {'dialogueRequest', + {'AARQ-apdu', + [version1], + ?'networkFunctionalSsContext-v2', %?'ss-InvocationNotificationContext-v3', + [{'EXTERNAL', + ?'map-DialogueAS', + asn1_NOVALUE,asn1_NOVALUE, + {'single-ASN1-type', + EncMapDialoguePDU}}]}}, + {ok, EncDialoguePDU} = map:encode('DialoguePDU', DialoguePDU), + MapData = {'RegisterSS-Arg', + ?allForwardingSS, %ss-Code + asn1_NOVALUE, + DestinationNumber, %forwardedToNumber + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE}, + MapPDU = {'begin', + {'MapSpecificPDUs_begin', + get_transactionId(), + {'EXTERNAL', + ?'dialogue-as-id', + asn1_NOVALUE,asn1_NOVALUE, + {'single-ASN1-type', + EncDialoguePDU + }}, + [{basicROS, + {invoke, + {'MapSpecificPDUs_begin_components_SEQOF_basicROS_invoke', + {present,1}, + asn1_NOVALUE, + {local,10}, + MapData}}}]}}, + {ok, EncMapPDU} = map:encode('MapSpecificPDUs', MapPDU), + EncMapPDU. + +create_eraseSS(Imsi, Origin) -> + MapDialoguePDU = {'map-open', + {'MAP-OpenInfo', + ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_LAND_MOBILE, + Imsi), %destinationReference + ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_PLAN_ISDN, + Origin), %originationReference + asn1_NOVALUE }}, + {ok, EncMapDialoguePDU} = map:encode('MAP-DialoguePDU', MapDialoguePDU), + DialoguePDU = {'dialogueRequest', + {'AARQ-apdu', + [version1], + ?'networkFunctionalSsContext-v2', %?'ss-InvocationNotificationContext-v3', + [{'EXTERNAL', + ?'map-DialogueAS', + asn1_NOVALUE,asn1_NOVALUE, + {'single-ASN1-type', + EncMapDialoguePDU}}]}}, + {ok, EncDialoguePDU} = map:encode('DialoguePDU', DialoguePDU), + MapData = {'SS-ForBS-Code-Arg', + ?allForwardingSS, %ss-Code + asn1_NOVALUE, %basicService + asn1_NOVALUE}, %longFTN-Supported + MapPDU = {'begin', + {'MapSpecificPDUs_begin', + get_transactionId(), + {'EXTERNAL', + ?'dialogue-as-id', + asn1_NOVALUE,asn1_NOVALUE, + {'single-ASN1-type', + EncDialoguePDU + }}, + [{basicROS, + {invoke, + {'MapSpecificPDUs_begin_components_SEQOF_basicROS_invoke', + {present,1}, + asn1_NOVALUE, + {local,11}, + MapData}}}]}}, + {ok, EncMapPDU} = map:encode('MapSpecificPDUs', MapPDU), + EncMapPDU. + +create_updateLocation() -> + create_updateLocation(?IMSI, ?LOCAL_GLOBAL_TITLE, ?LOCAL_GLOBAL_TITLE). +create_updateLocation(Imsi, MscNr, VlrNr) -> + MapData = {'UpdateLocationArg', + Imsi, + ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_PLAN_ISDN, + MscNr), %msc-Number + ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_PLAN_ISDN, + VlrNr), %vlr-Number + asn1_NOVALUE, %<<59,151,2,0>>, %lmsi + asn1_NOVALUE, + {'VLR-Capability', + [phase1,phase2,phase3,phase4], + asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE, + asn1_NOVALUE,'NULL', + [lcsCapabilitySet1,lcsCapabilitySet2], + ['o-csi','d-csi','vt-csi','mt-sms-csi'], + asn1_NOVALUE,asn1_NOVALUE}, + asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE, + asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE, + 'NULL'}, + MapPDU = {'begin', + {'MapSpecificPDUs_begin', + get_transactionId(), + {'EXTERNAL', + ?'dialogue-as-id', + asn1_NOVALUE,asn1_NOVALUE, + {'single-ASN1-type', + <<96,15,128,2,7,128,161,9,6,7,4,0,0,1,0,1,3>>}}, + [{basicROS, + {invoke, + {'MapSpecificPDUs_begin_components_SEQOF_basicROS_invoke', + {present,1}, + asn1_NOVALUE, + {local,2}, + MapData}}}]}}, + {ok, EncMapPDU} = map:encode('MapSpecificPDUs', MapPDU), + EncMapPDU. + +create_anyTimeInerrogation() -> + create_anyTimeInerrogation(?IMSI, ?LOCAL_GLOBAL_TITLE). +create_anyTimeInerrogation(Imsi, GsmSCF) -> + MapData = {'AnyTimeInterrogationArg', + {imsi, Imsi}, %{msisdn,?MSISDN}, + {'RequestedInfoMAP-MS-DataTypes',asn1_NOVALUE, + 'NULL',asn1_NOVALUE,asn1_NOVALUE, + asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE, + asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}, + ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_PLAN_ISDN, + GsmSCF), %gsmSCF-Address + asn1_NOVALUE}, + Dialog = build_dialog_request(?'anyTimeInfoEnquiryContext-v3'), + encode_map_pdu(Dialog, 71, MapData). + +create_sendAuthenticationInfo() -> + create_sendAuthenticationInfo(?IMSI). +create_sendAuthenticationInfo(Imsi) -> + create_sendAuthenticationInfo(Imsi, 5). +create_sendAuthenticationInfo(Imsi, Nr) -> + MapData = { 'SendAuthenticationInfoArg', + Imsi, + Nr, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE}, + MapPDU = {'begin', + {'MapSpecificPDUs_begin', + get_transactionId(), + {'EXTERNAL', + ?'dialogue-as-id', + asn1_NOVALUE,asn1_NOVALUE, + {'single-ASN1-type',<<96,11,161,9,6,7,4,0,0,1,0,14,3>>}}, + [{basicROS, + {invoke, + {'MapSpecificPDUs_begin_components_SEQOF_basicROS_invoke', + {present,1}, + asn1_NOVALUE, + {local,56}, + MapData}}}]}}, + {ok, EncMapPDU} = map:encode('MapSpecificPDUs', MapPDU), + EncMapPDU. + +create_sendImsi() -> + create_sendImsi(?MSISDN). +create_sendImsi(Msisdn) -> + MapData = Msisdn, + Dialog = build_dialog_request(?'imsiRetrievalContext-v2'), + encode_map_pdu(Dialog, 58, MapData). + +create_purgeMs() -> + create_purgeMs(?IMSI, ?LOCAL_GLOBAL_TITLE). +create_purgeMs(Imsi, VlrNr) -> + MapData = {'PurgeMs-Arg', + Imsi, + ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_PLAN_ISDN, + VlrNr), %VLR number + asn1_NOVALUE, %SGSN number + asn1_NOVALUE}, %Last Known Location + Dialog = build_dialog_request(?'msPurgingContext-v3'), + encode_map_pdu(Dialog, 67, MapData). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% to MSC/VLR +%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +create_provideSubscriberInfo() -> + MapData = {'ProvideSubscriberInfoArg', + ?IMSI, + asn1_NOVALUE, + {'RequestedInfoMAP-MS-DataTypes', + 'NULL', %locationInformation + 'NULL', %subscriberState + asn1_NOVALUE, %extensionContainer + 'NULL', %currentLocation + asn1_NOVALUE, %requestedDomain + 'NULL', %imei + asn1_NOVALUE, %ms-classmark + asn1_NOVALUE, %mnpRequestedInfo + asn1_NOVALUE, %t-adsData + asn1_NOVALUE %requestedNodes + }, + asn1_NOVALUE, + asn1_NOVALUE}, + Dialog = build_dialog_request(?'subscriberInfoEnquiryContext-v3'), + encode_map_pdu(Dialog, 70, MapData). + +create_sendIdentification() -> + MapData = { 'SendIdentificationArg', + ?TMSI, + 5, %NumberOfRequestedVectors + asn1_NOVALUE, %segmentationProhibited + asn1_NOVALUE, %ExtensionContainer + asn1_NOVALUE, %msc-Number + asn1_NOVALUE, %previous-LAI + asn1_NOVALUE %hopCounter + }, + Dialog = build_dialog_request(?'interVlrInfoRetrievalContext-v3'), + encode_map_pdu(Dialog, 55, MapData). + +create_provideRoamingNumber() -> + MapData = {'ProvideRoamingNumberArg', + ?IMSI, + ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_PLAN_ISDN, + [1,2,3,4,5,6,7,8,9]), %msc-Number + ?MSISDN, + asn1_NOVALUE, + {'ExternalSignalInfo','gsm-0408', + <<4,1,160>>, + asn1_NOVALUE}, + asn1_NOVALUE,asn1_NOVALUE, + ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_PLAN_ISDN, + [1,2,3,4,5,6,7,8,9,0]), %gmsc-Address + <<112,4,1,54,22,114,55>>, %callReferenceNumber + asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE, + asn1_NOVALUE, + [phase1,phase2,phase3], + asn1_NOVALUE,'NULL',asn1_NOVALUE,asn1_NOVALUE, + asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE, + asn1_NOVALUE,asn1_NOVALUE}, + Dialog = build_dialog_request(?'roamingNumberEnquiryContext-v3'), + encode_map_pdu(Dialog, 4, MapData). + +create_cancelLocation() -> + MapData = {'CancelLocationArg', + {imsi,?IMSI}, + updateProcedure, + asn1_NOVALUE, + asn1_NOVALUE}, + Dialog = build_dialog_request(?'locationCancellationContext-v3'), %v2: {0,4,0,0,1,0,2,2} + encode_map_pdu(Dialog, 3, MapData). + +create_insertSubscriberData() -> + MapData = {'InsertSubscriberDataArg', + asn1_NOVALUE, %imsi + asn1_NOVALUE, %msisdn + asn1_NOVALUE, %additional msisdn + asn1_NOVALUE, %category + asn1_NOVALUE, %subscriber status + asn1_NOVALUE, %bearer service list + asn1_NOVALUE, %teleservice list + asn1_NOVALUE, %forwarding information list + asn1_NOVALUE, %call barring information list + asn1_NOVALUE, %CUG information list + asn1_NOVALUE, %SS-Data list + asn1_NOVALUE, %eMLPP subscription data + asn1_NOVALUE, %MC-subscription data + asn1_NOVALUE, % + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE, + asn1_NOVALUE + }, + Dialog = build_dialog_request('subscriberDataMngtContext-v3'), + encode_map_pdu(Dialog, 7, MapData). + diff --git a/src/sms_7bit_encoding.erl b/src/sms_7bit_encoding.erl new file mode 100644 index 0000000..4c39b78 --- /dev/null +++ b/src/sms_7bit_encoding.erl @@ -0,0 +1,67 @@ +-module(sms_7bit_encoding). + +-author("dawid.figiel@gmail.com"). +-compile(export_all). + +%% 7-bit encoding +%% --------------------------------------------------------------------- +%% Function for converting string to 7-bit encoding according to: +%% GSM 03.38 Version 5.3.0 +%% --------------------------------------------------------------------- +%% Initial Function call: to_7bit(String). +%% --------------------------------------------------------------------- +%% Input: String containing only ASCII characters +%% --------------------------------------------------------------------- +%% Output: Binary encoded String +%% --------------------------------------------------------------------- +to_7bit([]) -> <<>>; +to_7bit(String) -> to_7bit(list_to_binary(String),<<>>,1). + +to_7bit(<<Char1:8>>,<<>>,_Cntr) -> <<<<Char1>>/binary>>; +to_7bit(<<_Char1:8>>,Out,8) -> Out; +to_7bit(<< Char1:8>>,Out,7) -> +%% << Out/binary,<<((Char1 bsr 6) bor 26)>>/binary >>; + << Out/binary,<<((Char1 bsr 6) bor 64)>>/binary >>; +to_7bit(<<Char1:8>>,Out,Cntr) -> + << Out/binary,<<(Char1 bsr (Cntr - 1))>>/binary >>; +to_7bit(<<_Char:8,In/binary>>,Out,8)-> + to_7bit(In,Out,1); +to_7bit(<<Char1:8,Char2:8,In/binary>>,Out,Cntr)-> + SRChar1 = Char1 bsr (Cntr - 1), + NewChar1 = <<Char2:Cntr,SRChar1:(8-Cntr)>>, + to_7bit(<<<<Char2>>/binary,In/binary>>,<<Out/binary,NewChar1/binary>>,Cntr+1). + +%% 7-bit decoding +%% --------------------------------------------------------------------- +%% Function for converting 7-bit encoding to String according to: +%% GSM 03.38 Version 5.3.0 +%% --------------------------------------------------------------------- +%% Initial Function call: from_7bit(SevenBitEncodedBinary). +%% --------------------------------------------------------------------- +%% Input: Binary encoded String +%% --------------------------------------------------------------------- +%% Output: String containing only ASCII characters +%% --------------------------------------------------------------------- +from_7bit(List) when is_list(List) -> from_7bit(list_to_binary(List)); +from_7bit(<<>>) -> []; +from_7bit(Bin) -> + from_7bit(Bin,<<>>,<<>>,1). + +%%from_7bit(<<>>,<<13>>,Out,8) -> +from_7bit(<<>>,<<32>>,Out,8) -> + binary_to_list(Out); +from_7bit(<<>>,<<CharN>>,Out,8) -> + binary_to_list(<<Out/binary,CharN:8>>); +from_7bit(<<>>,<<0>>,Out,_Cntr) -> + binary_to_list(Out); +from_7bit(<<>>,<<CharN>>,Out,Cntr) -> + binary_to_list(<<Out/binary,0:(9-Cntr),CharN:(Cntr-1)>>); +from_7bit(<<CharN:1,CharO:7,In/binary>>,<<CharI>>,Out,8) -> + from_7bit(In,<<CharN>>,<<Out/binary,0:1,CharI:7,0:1,CharO:7>>,2); +from_7bit(<<Byte:8,In/binary>>,<<>>,<<>>,1) -> + CharN = Byte bsr 7, + from_7bit(In,<<CharN>>,<<(Byte band 127)>>,2); +from_7bit(<<Byte:8,In/binary>>,<<CharI>>,Out,Cntr) -> + Char = (Byte bsl (Cntr - 1)) bor CharI, + CharN = Byte bsr (8 - Cntr), + from_7bit(In,<<CharN>>,<<Out/binary,0:1,Char:7>>,Cntr+1). diff --git a/src/ss7test.app.src b/src/ss7test.app.src new file mode 100644 index 0000000..cb8c804 --- /dev/null +++ b/src/ss7test.app.src @@ -0,0 +1,12 @@ +{application, ss7test, + [ + {description, ""}, + {vsn, "1"}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, { ss7test_app, ["./config"]}}, + {env, []} + ]}. diff --git a/src/ss7test_app.erl b/src/ss7test_app.erl new file mode 100644 index 0000000..cc0bb22 --- /dev/null +++ b/src/ss7test_app.erl @@ -0,0 +1,544 @@ +-module(ss7test_app). +-author('Daniel Mende <mail@c0decafe.de>'). + +-behaviour(application). + +%% Application callbacks +-export([start/2, stop/1]). + +-include_lib("osmo_ss7/include/osmo_util.hrl"). +-include_lib("osmo_ss7/include/osmo_ss7.hrl"). +-include_lib("osmo_ss7/include/m3ua.hrl"). +-include_lib("osmo_ss7/include/sccp.hrl"). +-include_lib("osmo_ss7/include/isup.hrl"). +-include_lib("osmo_map/src/tcap_asn.hrl"). +-include("ss7test_app.hrl"). + +-define(TRACE, false). + +-record(loop_dat, { + scrc_pid, + m3ua_pid, + ss7links_pid, + ss7routes_pid, + link, + local_pc, + remote_pc, + gt_local, + gt_hlr, + gt_vlr, + gt_msc, + gt_sgsn, + msisdn, + imsi, + scenter, + fnumber + }). + +%% change routing context in m3ua_code.erl => fixed +%% add pointcode to sccp in sccp_codec.erl +%% change network indicator in sccp_scrc.erl => fixed + + +%% =================================================================== +%% Application callbacks +%% =================================================================== + +start(_, Configfile) -> + LoopDat = init(Configfile), + spawn(ss7test_app, loop, [LoopDat]). + +stop(_State) -> + ok. + +%% =================================================================== + +init(Configfile) -> + Config = case file:consult(Configfile) of + {ok, C} -> + C; + {error, E} -> + io:fwrite("\e[91;1mError reading config file ~p:~n~p~n\e[39;49;0m", [Configfile, E]), + exit(config_error) + end, + {sctp, SCTP_Config} = lists:keyfind(sctp, 1, Config), + {m3ua, M3UA_Config} = lists:keyfind(m3ua, 1, Config), + {sccp, Sccp} = lists:keyfind(sccp, 1, Config), + {target, Target} = lists:keyfind(target, 1, Config), + {gt_local, GT_Local} = lists:keyfind(gt_local, 1, Sccp), + {gt_hlr, GT_Hlr} = lists:keyfind(gt_hlr, 1, Target), + {gt_vlr, GT_Vlr} = lists:keyfind(gt_vlr, 1, Target), + {gt_msc, GT_Msc} = lists:keyfind(gt_msc, 1, Target), + {gt_sgsn, GT_Sgsn} = lists:keyfind(gt_sgsn, 1, Target), + {msisdn, Msisdn} = lists:keyfind(msisdn, 1, Target), + Msisdn_enc = ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_PLAN_ISDN, + Msisdn), + {service_center, SCenter} = lists:keyfind(service_center, 1, Target), + SCenter_enc = ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_PLAN_ISDN, + SCenter), + {forward_number, FNumber} = lists:keyfind(forward_number, 1, Target), + FNumber_enc = ss7test_helper:encode_msisdn(?NUMBER_EXTENSION_NONE, + ?NUMBER_NATURE_INTERNATIONAL, ?NUMBER_PLAN_ISDN, + FNumber), + % start link server and create linkset + {ok, SS7linksPid} = ss7_links:start_link(), + sys:trace(ss7_links, ?TRACE), + {local_pc, Local_PC} = lists:keyfind(local_pc, 1, M3UA_Config), + {remote_pc, Remote_PC} = lists:keyfind(remote_pc, 1, M3UA_Config), + ok = ss7_links:register_linkset(Local_PC, Remote_PC, "test_linkset"), + %start route server and add route + {ok, SS7routesPid} = ss7_routes:start_link(), + ok = ss7_routes:create_route(Remote_PC, 16#ffff, "test_linkset"), + % create m3ua link + {local_ip, Local_IP} = lists:keyfind(local_ip, 1, SCTP_Config), + {local_port, Local_Port} = lists:keyfind(local_port, 1, SCTP_Config), + Local = #sigtran_peer{ip = Local_IP, port = Local_Port}, + {remote_ip, Remote_IP} = lists:keyfind(remote_ip, 1, SCTP_Config), + {remote_port, Remote_Port} = lists:keyfind(remote_port, 1, SCTP_Config), + Remote = #sigtran_peer{ip = Remote_IP, port = Remote_Port}, + {asp_id, Asp_ID} = lists:keyfind(asp_id, 1, M3UA_Config), + {route_ctx, Route_CTX} = lists:keyfind(route_ctx, 1, M3UA_Config), + {net_appearance, Net_Appearance} = lists:keyfind(net_appearance, 1, M3UA_Config), + Link = #sigtran_link{type = m3ua, name = "test_link", linkset_name = "test_linkset", + sls = 0, local = Local, remote = Remote, asp_id = Asp_ID, + route_ctx = Route_CTX, net_app = Net_Appearance}, + {ok, M3uaPid} = ss7_link_m3ua:start_link(Link), + % instantiate SCCP routing instance + {network_ind, Network_Ind} = lists:keyfind(network_ind, 1, M3UA_Config), + {ok, ScrcPid} = sccp_scrc:start_link([{mtp_tx_action, {callback_fn, fun scrc_tx_to_mtp/2, M3uaPid}}, + {ni, Network_Ind}]), + sys:trace(sccp_scrc, ?TRACE), + {ok, _SccpPid} = sccp_user:start_link(), + sys:trace(sccp_user, ?TRACE), + io:format("Waiting for M3UA link comming up...~n"), + wait_for_link(Link), + #loop_dat{m3ua_pid = M3uaPid, scrc_pid = ScrcPid, ss7links_pid = SS7linksPid, ss7routes_pid = SS7routesPid, link = Link, + local_pc = Local_PC, remote_pc = Remote_PC, gt_local = GT_Local, gt_hlr = GT_Hlr, gt_vlr = GT_Vlr, gt_msc = GT_Msc, + gt_sgsn = GT_Sgsn, msisdn = Msisdn_enc, scenter = SCenter_enc, fnumber = FNumber_enc}. + +wait_for_link(Link) -> + case ss7_link_m3ua:get_link_state(Link) of + {ok, down} -> + timer:sleep(100), + wait_for_link(Link); + {ok, active} -> + {ok}; + _ -> + {error} + end. + +loop(L) -> + receive + {sccp, Prim} -> + {primitive, 'N', 'UNITDATA', indication, Data} = Prim, + {sccp_msg, _, ProtData} = Data, + {user_data, _UserData} = lists:keyfind(user_data, 1, ProtData), + %~ io:format("Rx: ~p~n", [map:decode('MapSpecificPDUs', UserData)]), + loop(L); + {send, {Gts, {Lssn, Rssn}}, Data} -> + Tlssn = case Lssn of + hlr -> ?SCCP_SSN_HLR; + vlr -> ?SCCP_SSN_VLR; + msc -> ?SCCP_SSN_MSC; + sgsn -> ?SCCP_SSN_SGSN; + cap -> ?SCCP_SSN_CAP; + _ -> ?SCCP_SSN_UNKNOWN + end, + Trssn = case Rssn of + hlr -> ?SCCP_SSN_HLR; + vlr -> ?SCCP_SSN_VLR; + msc -> ?SCCP_SSN_MSC; + sgsn -> ?SCCP_SSN_SGSN; + cap -> ?SCCP_SSN_CAP; + _ -> ?SCCP_SSN_UNKNOWN + end, + send_tcap(L, Gts, {Tlssn, Trssn}, Data), + loop(L); + {test_hlr} -> + io:format("Testing HLR~n"), + test_hlr(L), + loop(L); + {link_state} -> + io:format("~p~n", [ss7_link_m3ua:get_link_state(L#loop_dat.link)]), + loop(L); + Stop -> + M3uaPid = L#loop_dat.m3ua_pid, + %~ ScrcPid = L#loop_dat.scrc_pid, + SS7linksPid = L#loop_dat.ss7links_pid, + %~ SS7routesPid = L#loop_dat.ss7routes_pid, + io:format("Received ~p~n", [Stop]), + sccp_user:stop(), + sccp_scrc:stop(), + %~ ss7_link_m3ua:stop(), + gen_server:cast(M3uaPid, stop), + ss7_routes:stop(), + %~ ss7_links:stop(), + gen_server:cast(SS7linksPid, stop), + exit(stop_received) + end. + +test_hlr(L) -> + LocalSsn = ?SCCP_SSN_MSC, + ok = sccp_user:bind_ssn(LocalSsn), + Gts = {L#loop_dat.gt_local, L#loop_dat.gt_hlr}, + test_sri(Gts, L), + test_srifs(Gts, L), + L2 = test_si(Gts, L), + test_sai(Gts, L2, 100), + test_sai(Gts, L2, 10), + test_sai(Gts, L2, 5), + test_rss(Gts, L2), + test_ess(Gts, L2), + test_ul(Gts, L2), + test_ati(Gts, L2), + test_pms(Gts, L2), + ok = sccp_user:unbind_ssn(LocalSsn, undefined). + +test_sri(Gts, L) -> + %~ ======== + %~ sendRoutingInfo + %~ ======== + io:format("~n\e[93;1m# Testing sendRoutingInfo...\n\e[39;49;0m"), + send_tcap(L, Gts, {?SCCP_SSN_MSC, ?SCCP_SSN_HLR}, map_msgs:create_sendRoutingInfo(L#loop_dat.msisdn, L#loop_dat.gt_local)), + receive + {sccp, {primitive, 'N', 'UNITDATA', indication, Data}} -> + case decode_tcap(Data) of + {ok, Results} -> + io:format("\e[97;1mGot answer for sendRoutingInfo~n~w~n\e[39;49;0m", [Results]), + case Results of + [{basicROS, {returnError, {_, {present, Present}, {local, Local}, _}}}] -> + io:format("\e[91;1mReceived Error: Present ~w, Local ~w~n\e[39;49;0m", [Present, Local]); + [{basicROS, + {returnResult, + {'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult', + {present,1},{'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult_result', + {local,22},_}}}}|_] -> + io:format("\e[91;1mReceived SendRoutingInfoRes~n\e[39;49;0m"); + _ -> + io:format("\e[92;1mNo Error.~n\e[39;49;0m") + end; + _-> + io:format("\e[91;1mError decoding SendRoutingInfo\n\e[39;49;0m") + end; + _-> + io:format("\e[91;1mError no data received for SendRoutingInfo\n\e[39;49;0m") + after 2000 -> + io:format("\e[91;1mError timeout on receiving SendRoutingInfo\n\e[39;49;0m") + end, + L. + +test_srifs(Gts, L) -> + %~ ======== + %~ sendRoutingInfoForSM + %~ ======== + io:format("~n\e[93;1m# Testing sendRoutingInfoForSM...\n\e[39;49;0m"), + send_tcap(L, Gts, {?SCCP_SSN_MSC, ?SCCP_SSN_HLR}, map_msgs:create_sendRoutingInfoForSM(L#loop_dat.msisdn, L#loop_dat.scenter)), + receive + {sccp, {primitive, 'N', 'UNITDATA', indication, Data}} -> + case decode_tcap(Data) of + {ok, Results} -> + io:format("\e[97;1mGot answer for sendRoutingInfoForSM\n~w\n\e[39;49;0m", [Results]), + case Results of + [{basicROS, {returnError, {_, {present, Present}, {local, Local}, _}}}|_] -> + case {Present, Local} of + {1, 6} -> + io:format("\e[91;1mSubscriber is absent~n\e[39;49;0m"); + _ -> + io:format("\e[92;1mReceived Error: Present ~w, Local ~w~n\e[39;49;0m", [Present, Local]) + end; + _ -> + io:format("\e[92;1mNo Error.~n\e[39;49;0m") + end; + _-> + io:format("\e[91;1mError decoding SendRoutingInfoForSM\n\e[39;49;0m") + end; + _-> + io:format("\e[91;1mError no data received for SendRoutingInfoForSM\n\e[39;49;0m") + after 2000 -> + io:format("\e[91;1mError timeout on receiving SendRoutingInfoForSM\n\e[39;49;0m") + end, + L. + +test_si(Gts, L) -> + %~ ======== + %~ sendImsi + %~ ======== + io:format("~n\e[93;1m# Testing sendImsi...\n\e[39;49;0m"), + send_tcap(L, Gts, {?SCCP_SSN_MSC, ?SCCP_SSN_HLR}, map_msgs:create_sendImsi(L#loop_dat.msisdn)), + receive + {sccp, {primitive, 'N', 'UNITDATA', indication, Data}} -> + case decode_tcap(Data) of + {ok, Results} -> + io:format("\e[97;1mGot answer for sendImsi\n~w\n\e[39;49;0m", [Results]), + case Results of + [{basicROS, {returnError, {_, {present, Present}, {local, Local}, _}}}] -> + io:format("\e[91;1mReceived Error: Present ~w, Local ~w~n\e[39;49;0m", [Present, Local]), + L; + [{basicROS, + {returnResult, + {'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult', + {present,1}, + {'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult_result', + {local,58}, + Imsi }}}}|_] -> + io:format("\e[91;1mReceived IMSI ~w~n\e[39;49;0m", [Imsi]), + L#loop_dat{imsi = Imsi} + end; + _-> + io:format("\e[91;1mError decoding sendImsi\n\e[39;49;0m"), + L + end; + _-> + io:format("\e[91;1mError no data received for sendImsi\n\e[39;49;0m"), + L + after 2000 -> + io:format("\e[91;1mError timeout on receiving sendImsi\n\e[39;49;0m"), + L + end. + +test_sai(Gts, L, Nr) -> + %~ ======== + %~ sendAuthenticationInfo + %~ ======== + io:format("~n\e[93;1m# Testing sendAuthenticationInfo...\n\e[39;49;0m"), + send_tcap(L, Gts, {?SCCP_SSN_MSC, ?SCCP_SSN_HLR}, map_msgs:create_sendAuthenticationInfo(L#loop_dat.imsi, Nr)), + receive + {sccp, {primitive, 'N', 'UNITDATA', indication, Data}} -> + case decode_tcap(Data) of + {ok, Results} -> + io:format("\e[97;1mGot answer for sendAuthenticationInfo\n~w\n\e[39;49;0m", [Results]), + case Results of + [{basicROS, {returnError, {_, {present, Present}, {local, Local}, _}}}] -> + io:format("\e[91;1mReceived Error: Present ~w, Local ~w~n\e[39;49;0m", [Present, Local]); + [{basicROS, {reject, _}}|_] -> + if + Nr>5 -> io:format("\e[92;1mAsked for ~w (>5) vectors, got rejected~n\e[39;49;0m", [Nr]); + Nr<6 -> io:format("\e[91;1mAsked for ~w (<=5) vectors, got rejected~n\e[39;49;0m", [Nr]) + end; + [{basicROS, + {returnResult, + {'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult', + {present,1}, {'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult_result', + {local,56}, {'SendAuthenticationInfoRes', + {quintupletList,ResList},_,_}}}}}|_] -> + NrRes = length(ResList), + if + Nr>5 -> + if + NrRes>5 -> io:format("\e[91;1mAsked for ~w vectors, got ~w (>5) result vectors~n\e[39;49;0m", [Nr,NrRes]) + end; + Nr<6 -> + if + NrRes==Nr -> io:format("\e[92;1mAsked for ~w vectors, got ~w (=~w) result vectors~n\e[39;49;0m", [Nr,NrRes,Nr]); + true -> io:format("\e[93;1mAsked for ~w vectors, got ~w (!=~w) result vectors~n\e[39;49;0m", [Nr,NrRes,Nr]) + end + end; + _ -> + io:format("\e[92;1mNo Error.~n\e[39;49;0m") + end; + _-> + io:format("\e[91;1mError decoding sendAuthenticationInfo\n\e[39;49;0m") + end; + _-> + io:format("\e[91;1mError no data received for sendAuthenticationInfo\n\e[39;49;0m") + after 2000 -> + io:format("\e[91;1mError timeout on receiving sendAuthenticationInfo\n\e[39;49;0m") + end, + L. + +test_rss(Gts, L) -> + %~ ======== + %~ registerSS + %~ ======== + io:format("~n\e[93;1m# Testing registerSS...\n\e[39;49;0m"), + send_tcap(L, Gts, {?SCCP_SSN_MSC, ?SCCP_SSN_HLR}, map_msgs:create_registerSS(ss7test_helper:decode_imsi(L#loop_dat.imsi), L#loop_dat.gt_vlr, L#loop_dat.fnumber)), + receive + {sccp, {primitive, 'N', 'UNITDATA', indication, Data}} -> + case decode_tcap(Data) of + {ok, Results} -> + io:format("\e[97;1mGot answer for registerSS\n~w\n\e[39;49;0m", [Results]), + case Results of + [{basicROS, {returnError, {_, {present, Present}, {local, Local}, _}}}] -> + io:format("\e[91;1mReceived Error: Present ~w, Local ~w~n\e[39;49;0m", [Present, Local]); + [{basicROS, + {returnResult, + {'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult', + {present,1}, {'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult_result', + {local,10},_}}}}|_] -> + io:format("\e[91;1mReceived forwardingInfo, registerSS is working~n\e[39;49;0m"); + _ -> + io:format("\e[92;1mNo Error.~n\e[39;49;0m") + end; + _-> + io:format("\e[91;1mError decoding registerSS\n\e[39;49;0m") + end; + _-> + io:format("\e[91;1mError no data received for registerSS\n\e[39;49;0m") + after 2000 -> + io:format("\e[91;1mError timeout on receiving registerSS\n\e[39;49;0m") + end, + L. + +test_ess(Gts, L) -> + %~ ======== + %~ eraseSS + %~ ======== + io:format("~n\e[93;1m# Testing eraseSS...\n\e[39;49;0m"), + send_tcap(L, Gts, {?SCCP_SSN_MSC, ?SCCP_SSN_HLR}, map_msgs:create_eraseSS(ss7test_helper:decode_imsi(L#loop_dat.imsi), L#loop_dat.gt_vlr)), + receive + {sccp, {primitive, 'N', 'UNITDATA', indication, Data}} -> + case decode_tcap(Data) of + {ok, Results} -> + io:format("\e[97;1mGot answer for eraseSS\n~w\n\e[39;49;0m", [Results]), + case Results of + [{basicROS, {returnError, {_, {present, Present}, {local, Local}, _}}}] -> + io:format("\e[91;1mReceived Error: Present ~w, Local ~w~n\e[39;49;0m", [Present, Local]); + [{basicROS, + {returnResult, + {'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult', + {present,1}, {'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult_result', + {local,11},_}}}}|_] -> + io:format("\e[91;1mReceived forwardingInfo, eraseSS is working~n\e[39;49;0m"); + _ -> + io:format("\e[92;1mNo Error.~n\e[39;49;0m") + end; + _-> + io:format("\e[91;1mError decoding eraseSS\n\e[39;49;0m") + end; + _-> + io:format("\e[91;1mError no data received for eraseSS\n\e[39;49;0m") + after 2000 -> + io:format("\e[91;1mError timeout on receiving eraseSS\n\e[39;49;0m") + end, + L. + +test_ul(Gts, L) -> + %~ ======== + %~ updateLocation + %~ ======== + io:format("~n\e[93;1m# Testing updateLocation...\n\e[39;49;0m"), + send_tcap(L, Gts, {?SCCP_SSN_MSC, ?SCCP_SSN_HLR}, map_msgs:create_updateLocation(L#loop_dat.imsi, L#loop_dat.gt_local, L#loop_dat.gt_local)), + receive + {sccp, {primitive, 'N', 'UNITDATA', indication, Data}} -> + case decode_tcap(Data) of + {ok, Results} -> + io:format("\e[97;1mGot answer for updateLocation\n~w\n\e[39;49;0m", [Results]), + case Results of + [{basicROS, {returnError, {_, {present, Present}, {local, Local}, _}}}] -> + io:format("\e[91;1mReceived Error: Present ~w, Local ~w~n\e[39;49;0m", [Present, Local]); + [{basicROS,{invoke,{'MapSpecificPDUs_continue_components_SEQOF_basicROS_invoke',{present,2},asn1_NOVALUE,{local,7},_}}}|_] -> + io:format("\e[91;1mReceived insertSubscriberData, updateLocation is working~n\e[39;49;0m"); + _ -> + io:format("\e[92;1mNo Error.~n\e[39;49;0m") + end; + _-> + io:format("\e[91;1mError decoding updateLocation\n\e[39;49;0m") + end; + _-> + io:format("\e[91;1mError no data received for updateLocation\n\e[39;49;0m") + after 2000 -> + io:format("\e[91;1mError timeout on receiving updateLocation\n\e[39;49;0m") + end, + L. + +test_ati(Gts, L) -> + %~ ======== + %~ anyTimeInterrogation + %~ ======== + io:format("~n\e[93;1m# Testing anyTimeInterrogation...\n\e[39;49;0m"), + send_tcap(L, Gts, {?SCCP_SSN_MSC, ?SCCP_SSN_HLR}, map_msgs:create_anyTimeInerrogation(L#loop_dat.imsi, L#loop_dat.gt_local)), + receive + {sccp, {primitive, 'N', 'UNITDATA', indication, Data}} -> + case decode_tcap(Data) of + {ok, Results} -> + io:format("\e[97;1mGot answer for anyTimeInerrogation\n~w\n\e[39;49;0m", [Results]), + case Results of + [{basicROS, {returnError, {_, {present, Present}, {local, Local}, _}}}] -> + case {Present, Local} of + {1, 49} -> + io:format("\e[92;1manyTimeInterrogation is forbidden~n\e[39;49;0m"); + _ -> + io:format("\e[91;1mReceived Error: Present ~w, Local ~w~n\e[39;49;0m", [Present, Local]) + end; + _ -> + io:format("\e[92;1mNo Error.~n\e[39;49;0m") + end; + _-> + io:format("\e[91;1mError decoding anyTimeInerrogation\n\e[39;49;0m") + end; + _-> + io:format("\e[91;1mError no data received for anyTimeInerrogation\n\e[39;49;0m") + after 2000 -> + io:format("\e[91;1mError timeout on receiving anyTimeInerrogation\n\e[39;49;0m") + end, + L. + +test_pms(Gts, L) -> + %~ ======== + %~ purgeMS + %~ ======== + io:format("~n\e[93;1m# Testing purgeMS...\n\e[39;49;0m"), + send_tcap(L, Gts, {?SCCP_SSN_MSC, ?SCCP_SSN_HLR}, map_msgs:create_purgeMs(L#loop_dat.imsi, L#loop_dat.gt_local)), + receive + {sccp, {primitive, 'N', 'UNITDATA', indication, Data}} -> + case decode_tcap(Data) of + {ok, Results} -> + io:format("\e[97;1mGot answer for purgeMs\n~w\n\e[39;49;0m", [Results]), + case Results of + [{basicROS, {returnError, {_, {present, Present}, {local, Local}, _}}}] -> + io:format("\e[91;1mReceived Error: Present ~w, Local ~w~n\e[39;49;0m", [Present, Local]); + [{basicROS, + {returnResult, + {'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult', + {present,1},{'MapSpecificPDUs_end_components_SEQOF_basicROS_returnResult_result', + {local,67},_}}}}|_] -> + io:format("\e[91;1mReceived purgeMS-Res, purgeMS is working~n\e[39;49;0m"); + _ -> + io:format("\e[92;1mNo Error.~n\e[39;49;0m") + end; + _-> + io:format("\e[91;1mError decoding purgeMs\n\e[39;49;0m") + end; + _-> + io:format("\e[91;1mError no data received for purgeMs\n\e[39;49;0m") + after 2000 -> + io:format("\e[91;1mError timeout on receiving purgeMs\n\e[39;49;0m") + end, + L. + +scrc_tx_to_mtp(Prim, Args) -> + M3uaPid = Args, + gen_fsm:send_event(M3uaPid, Prim). + +send_tcap(L, {Lgt, Rgt}, {Sssn, Dssn}, PDU) -> + CallingP = #sccp_addr{ssn = Sssn, point_code = L#loop_dat.local_pc, + global_title = #global_title{gti = ?SCCP_GTI_TT_NP_ENC_NAT, trans_type = ?SCCP_GTI_NO_GT, + encoding = 0, numbering_plan = 1, phone_number = Lgt, + nature_of_addr_ind = ?ISUP_ADDR_NAT_INTERNATIONAL}}, + CalledP = #sccp_addr{ssn = Dssn, point_code = L#loop_dat.remote_pc, + global_title = #global_title{gti = ?SCCP_GTI_TT_NP_ENC_NAT, trans_type = ?SCCP_GTI_NO_GT, + encoding = 0, numbering_plan = 1, phone_number = Rgt, + nature_of_addr_ind = ?ISUP_ADDR_NAT_INTERNATIONAL}}, + Opts = [{protocol_class, {1, 8}}, {called_party_addr, CalledP}, + {calling_party_addr, CallingP}, {user_data, PDU}], + gen_fsm:send_event(L#loop_dat.scrc_pid, osmo_util:make_prim('N','UNITDATA',request,Opts)). + +decode_tcap(Data) -> + {sccp_msg, _, ProtData} = Data, + {user_data, UserData} = lists:keyfind(user_data, 1, ProtData), + {ok, TcapData} = map:decode('MapSpecificPDUs', UserData), + case TcapData of + {'end', {'MapSpecificPDUs_end', _Transaction, % <<1,1,0,0>>, + {'EXTERNAL', + {0,0,17,773,1,1,1}, + _,_, %asn1_NOVALUE,asn1_NOVALUE, + _Dialog}, Results}} -> {}; + {continue, {'MapSpecificPDUs_continue', _STransaction, _Transaction, + {'EXTERNAL', + {0,0,17,773,1,1,1}, + _,_, %asn1_NOVALUE,asn1_NOVALUE, + _Dialog}, Results}} -> {} + end, + {ok, Results}. diff --git a/src/ss7test_app.hrl b/src/ss7test_app.hrl new file mode 100644 index 0000000..49703c0 --- /dev/null +++ b/src/ss7test_app.hrl @@ -0,0 +1,6 @@ +% Number encoding Definitions + +-define(NUMBER_EXTENSION_NONE, 1). +-define(NUMBER_NATURE_INTERNATIONAL, 1). +-define(NUMBER_PLAN_ISDN, 1). +-define(NUMBER_LAND_MOBILE, 6). diff --git a/src/ss7test_helper.erl b/src/ss7test_helper.erl new file mode 100644 index 0000000..f6821b0 --- /dev/null +++ b/src/ss7test_helper.erl @@ -0,0 +1,48 @@ +-module(ss7test_helper). +-author('Daniel Mende <mail@c0decafe.de>'). + +-export([encode_phonenumber/4, encode_msisdn/4, + decode_imsi/1, + remove_firstN/2, + tup2bin/1]). + +decode_imsi(<<>>) -> + []; +decode_imsi(Imsi) -> + <<First:4,Second:4,Rest/bits>> = Imsi, + Dec = decode_imsi(Rest), + if + First==15 -> lists:append([Second], Dec); + true -> lists:append([Second,First], Dec) + end. + +%% =================================================================== +%% Phone Number helper +%% =================================================================== + +encode_phonenumber(Extension, NatureOfNumber, NumberPlan, Number) -> + {EncNumber, Digits} = encode_phonenumber(Number), + <<Digits:8, Extension:1, NatureOfNumber:3, NumberPlan:4, EncNumber/binary>>. +encode_phonenumber([First,Second|Tail]) -> + {EncNumber, Digits} = encode_phonenumber(Tail), + {<<Second:4, First:4, EncNumber/binary>>, Digits + 2}; +encode_phonenumber([Last]) -> + {<<15:4, Last:4>>, 1}; +encode_phonenumber([]) -> + {<<>>, 0}. + +encode_msisdn(Extension, NatureOfNumber, NumberPlan, Number) -> + {EncNumber, _} = encode_phonenumber(Number), + <<Extension:1, NatureOfNumber:3, NumberPlan:4, EncNumber/binary>>. + +%% =================================================================== +%% List helper +%% =================================================================== + +remove_firstN(_, []) -> []; +remove_firstN(1, [_|T]) -> T; +remove_firstN(N, [_|T]) -> remove_firstN(N-1, T). + + +tup2bin(Tupel) -> + binary:list_to_bin([element(I,Tupel) || I <- lists:seq(1,tuple_size(Tupel))]). diff --git a/src/ss7test_sup.erl b/src/ss7test_sup.erl new file mode 100644 index 0000000..1b47715 --- /dev/null +++ b/src/ss7test_sup.erl @@ -0,0 +1,27 @@ +-module(ss7test_sup). + +-behaviour(supervisor). + +%% API +-export([start_link/0]). + +%% Supervisor callbacks +-export([init/1]). + +%% Helper macro for declaring children of supervisor +-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}). + +%% =================================================================== +%% API functions +%% =================================================================== + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +%% =================================================================== +%% Supervisor callbacks +%% =================================================================== + +init([]) -> + {ok, { {one_for_one, 5, 10}, []} }. + |