aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDaniel <0xc0decafe@users.noreply.github.com>2015-12-15 17:11:26 +0100
committerDaniel <0xc0decafe@users.noreply.github.com>2015-12-15 17:11:26 +0100
commit07769ca8ec29c50cff5b23e34b873411514c7940 (patch)
tree48fb77de9e7918a87f896f59a355c81937418f92 /src
Initial commit, including basic HLR testing functionality.
Diffstat (limited to 'src')
-rw-r--r--src/hex.erl33
-rw-r--r--src/map_msgs.erl590
-rw-r--r--src/sms_7bit_encoding.erl67
-rw-r--r--src/ss7test.app.src12
-rw-r--r--src/ss7test_app.erl544
-rw-r--r--src/ss7test_app.hrl6
-rw-r--r--src/ss7test_helper.erl48
-rw-r--r--src/ss7test_sup.erl27
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}, []} }.
+