diff options
Diffstat (limited to 'lib/hipe/test/bs_SUITE_data/bs_decode.erl')
-rw-r--r-- | lib/hipe/test/bs_SUITE_data/bs_decode.erl | 980 |
1 files changed, 980 insertions, 0 deletions
diff --git a/lib/hipe/test/bs_SUITE_data/bs_decode.erl b/lib/hipe/test/bs_SUITE_data/bs_decode.erl new file mode 100644 index 0000000000..d12654a1e3 --- /dev/null +++ b/lib/hipe/test/bs_SUITE_data/bs_decode.erl @@ -0,0 +1,980 @@ +%% -*- erlang-indent-level: 2 -*- + +-module(bs_decode). + +-export([test/0]). + +-include("bs_decode_extract.hrl"). + +-define(PDU, <<30,16,0,90,0,1,0,0,255,255,255,255,81,67,101,7,0,0,0,96, + 6,12,146,18,14,0,15,252,16,0,0,17,0,0,128,0,2,241,33,131, + 0,20,7,97,112,110,48,49,51,97,8,101,114,105,99,115,115, + 111,110,2,115,101,132,0,20,128,192,35,16,1,5,0,16,5,117, + 115,101,114,53,5,112,97,115,115,53,133,0,4,172,28,12,1, + 133,0,4,172,28,12,3,134,0,8,145,148,113,129,0,0,0,0>>). + +-define(RES, {ok,{sesT_createReqV0, + {mvsgT_tid,{mvsgT_imsi,<<81,67,101,7,0,0,0,240>>},6}, + [81,67,101,7,0,0,0,96], + {sesT_qualityOfServiceV0,1,4,9,2,18}, + 0,subscribed,0,0, + {mvsgT_pdpAddressType,ietf_ipv4,[]}, + [<<"apn013a">>,<<"ericsson">>,<<"se">>], + {masT_protocolConfigOptions,[], + {masT_pap,true,1,5,"user5","pass5"}, + []}, + {mvsgT_ipAddress,ipv4,172,28,12,1,0,0,0,0}, + {mvsgT_ipAddress,ipv4,172,28,12,3,0,0,0,0}, + {mvsT_msisdn,<<145,148,113,129,0,0,0,0>>}}, + 1}). + +test() -> + ?RES = decode_v0_opt(42, ?PDU), + ok. + +decode_v0_opt(0, Pdu) -> + decode_gtpc_msg(Pdu); +decode_v0_opt(N, Pdu) -> + decode_gtpc_msg(Pdu), + decode_v0_opt(N-1, Pdu). + +%%% -------------------------------------------------------------- +%%% #3.1.2 DECODE GTP-C MESSAGE +%%% -------------------------------------------------------------- + +%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +%%% Function : decode_gtpc_msg(GTP_C_Message)-> +%%% {ok,Request,ControlDataUs} | +%%% {fault,Cause,Request,ControlDataUs} +%%% +%%% Types : GTP_C_Message = binary(), GTP-C message from SGSN +%%% Request = record(), Containing decoded request +%%% ControlDataUS = record(), Containing header info +%%% Cause = integer(), Error code +%%% +%%% Description: This function decodes a binary GTP-C message and +%%% stores it in a record. Different records are used +%%% for different message types. +%%% +%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +%%% Create PDP Context Request +%%% GTP97, SNN=0 +%%% (No SNDCP N-PDU number) +decode_gtpc_msg(<<0:3,_:4,0:1,16:8,_Length:16,SequenceNumber:16, + _FlowLabel:16,_SNDCP_N_PDU_Number:8,_:3/binary-unit:8, + TID:8/binary-unit:8,InformationElements/binary>>) -> + Errors = #protocolErrors{}, + {ok,TID2} = tid_internal_storage(TID,[]), + EmptyCreateReq = #sesT_createReqV0{tid = TID2, + tidRaw = binary_to_list(TID)}, + case catch decode_ie_create(InformationElements,0,Errors,EmptyCreateReq) of + {ok,CreateReq} -> + {ok,CreateReq,SequenceNumber}; + {fault,Cause,CreateReq} -> + {fault,Cause,CreateReq,SequenceNumber}; + {'EXIT',_Reason} -> + {fault,193,EmptyCreateReq,SequenceNumber} + end; + +%%% Update PDP Context Request +%%% GTP97, SNN=0 +%%% (No SNDCP N-PDU number) +decode_gtpc_msg(<<0:3,_:4,0:1,18:8,_Length:16,SequenceNumber:16, + _FlowLabel:16,_SNDCP_N_PDU_Number:8,_:3/binary-unit:8, + TID:8/binary-unit:8,InformationElements/binary>>) -> + io:format("hej", []), + Errors = #protocolErrors{}, + {ok,TID2}=tid_internal_storage(TID,[]), + EmptyUpdateReq=#sesT_updateReqV0{tid=TID2, + tidRaw=binary_to_list(TID)}, + case catch decode_ie_update(InformationElements,0,Errors, + EmptyUpdateReq) of + {ok,UpdateReq} -> + {ok,UpdateReq,SequenceNumber}; + {fault,Cause,UpdateReq} -> + {fault,Cause,UpdateReq,SequenceNumber}; + {'EXIT',Reason} -> + io:format("hej", []), + {fault,193,EmptyUpdateReq,SequenceNumber, Reason} + end; + +%%% Delete PDP Context Request +%%% GTP97, SNN=0 +%%% (No SNDCP N-PDU number) +decode_gtpc_msg(<<0:3,_:4,0:1,20:8,_Length:16,SequenceNumber:16, + _FlowLabel:16,_SNDCP_N_PDU_Number:8,_:3/binary-unit:8, + TID:8/binary-unit:8,_InformationElements/binary>>) -> + {ok,TID2} = tid_internal_storage(TID,[]), + DeleteReq = #sesT_deleteReqV0{tid=TID2}, + {ok,DeleteReq,SequenceNumber}; + +%%% Delete PDP Context Response +%%% GTP97, SNN=0 +%%% (No SNDCP N-PDU number) +decode_gtpc_msg(<<0:3,_:4,0:1,21:8,_Length:16,SequenceNumber:16, + _FlowLabel:16,_SNDCP_N_PDU_Number:8,_:3/binary-unit:8, + TID:8/binary-unit:8,InformationElements/binary>>) -> + {ok,TID2} = tid_internal_storage(TID,[]), + EmptyDeleteRes = #sesT_deleteResV0{tid=TID2}, + case catch decode_ie_delete_res(InformationElements,0,EmptyDeleteRes) of + {ok, DeleteRes} -> + {ok,DeleteRes,SequenceNumber}; + {fault,Cause,DeleteRes} -> + {fault,Cause,DeleteRes,SequenceNumber}; + {'EXIT',_Reason} -> + {fault,193,EmptyDeleteRes,SequenceNumber} + end; + +%%% Error handling +decode_gtpc_msg(_GTP_C_Message) -> + {fault}. + +%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +%%% decode_ie_create/4 +%%% Decode information elements for Create PDP Context Request + +%%% All elements decoded +decode_ie_create(<<>>,PresentIEs,Errors,CreateReq) -> + %% Check mandatory IE's + if + (PresentIEs band 16#77D) =/= 16#77D -> + {fault,202,CreateReq}; %Mandatory IE missing + true -> %OK + %% Check errors during decoding + case Errors of + #protocolErrors{invalidManIE=true} -> %Invalid mandatory IE + {fault,201,CreateReq}; %Mandatory IE incorrect + #protocolErrors{outOfSequence=true} -> %Out of sequence + {fault,193,CreateReq}; %Invalid message format + #protocolErrors{incorrectOptIE=true} -> %Incorrect optional IE + {fault,203,CreateReq}; %Optional IE incorrect + _ -> %OK + {ok,CreateReq} + end + end; + +%%% Quality of Service Profile, Mandatory +decode_ie_create(<<6:8,QoSElement:3/binary-unit:8,Rest/binary>>,PresentIEs, + Errors,CreateReq) -> + if + (PresentIEs band 16#00000001) =:= 16#00000001 -> %Repeated IE's, ignore + decode_ie_create(Rest,PresentIEs,Errors,CreateReq); + PresentIEs > 16#00000001 -> %Out of sequence + UpdatedErrors=Errors#protocolErrors{outOfSequence=true}, + <<_:2,DelayClass:3,ReliabilityClass:3, + PeakThroughput:4,_:1,PrecedenceClass:3, + _:3,MeanThroughput:5>> = QoSElement, + QoS=#sesT_qualityOfServiceV0{delayClass=DelayClass, + reliabilityClass=ReliabilityClass, + peakThroughput=PeakThroughput, + precedenceClass=PrecedenceClass, + meanThroughput=MeanThroughput}, + UpdatedCreateReq=CreateReq#sesT_createReqV0{qos=QoS}, + decode_ie_create(Rest,(PresentIEs bor 16#00000001), + UpdatedErrors,UpdatedCreateReq); + true -> %OK + <<_:2,DelayClass:3,ReliabilityClass:3, + PeakThroughput:4,_:1,PrecedenceClass:3, + _:3,MeanThroughput:5>> = QoSElement, + QoS=#sesT_qualityOfServiceV0{delayClass=DelayClass, + reliabilityClass=ReliabilityClass, + peakThroughput=PeakThroughput, + precedenceClass=PrecedenceClass, + meanThroughput=MeanThroughput}, + UpdatedCreateReq=CreateReq#sesT_createReqV0{qos=QoS}, + decode_ie_create(Rest,(PresentIEs bor 16#00000001), + Errors,UpdatedCreateReq) + end; + +%%% Recovery, Optional +decode_ie_create(<<14:8,Recovery:8,Rest/binary>>, + PresentIEs,Errors,CreateReq) -> + if + (PresentIEs band 16#00000002) =:= 16#00000002 -> %Repeated IE, ignored + decode_ie_create(Rest,PresentIEs,Errors,CreateReq); + PresentIEs > 16#00000002 -> %Out of sequence + UpdatedErrors=Errors#protocolErrors{outOfSequence=true}, + UpdatedCreateReq=CreateReq#sesT_createReqV0{recovery=Recovery}, + decode_ie_create(Rest,(PresentIEs bor 16#00000002), + UpdatedErrors,UpdatedCreateReq); + true -> %OK + UpdatedCreateReq=CreateReq#sesT_createReqV0{recovery=Recovery}, + decode_ie_create(Rest,(PresentIEs bor 16#00000002),Errors, + UpdatedCreateReq) + end; + +%%% Selection mode, Mandatory +decode_ie_create(<<15:8,_:6,SelectionMode:2,Rest/binary>>,PresentIEs, + Errors,CreateReq) -> + if + (PresentIEs band 16#00000004) =:= 16#00000004 -> %Repeated IE, ignored + decode_ie_create(Rest,PresentIEs,Errors,CreateReq); + PresentIEs > 16#00000004 -> %Out of sequence + UpdatedErrors=Errors#protocolErrors{outOfSequence=true}, + UpdatedCreateReq=CreateReq#sesT_createReqV0{ + selMode=selection_mode_internal_storage(SelectionMode)}, + decode_ie_create(Rest,(PresentIEs bor 16#00000004), + UpdatedErrors,UpdatedCreateReq); + true -> %OK + UpdatedCreateReq=CreateReq#sesT_createReqV0{ + selMode=selection_mode_internal_storage(SelectionMode)}, + decode_ie_create(Rest,(PresentIEs bor 16#00000004),Errors, + UpdatedCreateReq) + end; + +%%% Flow Label Data I, Mandatory +decode_ie_create(<<16:8,FlowLabel:16,Rest/binary>>,PresentIEs,Errors,CreateReq) -> + if + (PresentIEs band 16#00000008) =:= 16#00000008 -> %Repeated IE, ignored + decode_ie_create(Rest,PresentIEs,Errors,CreateReq); + PresentIEs > 16#00000008 -> %Out of sequence + UpdatedErrors=Errors#protocolErrors{outOfSequence=true}, + UpdatedCreateReq=CreateReq#sesT_createReqV0{flowLblData=FlowLabel}, + decode_ie_create(Rest,(PresentIEs bor 16#00000008), + UpdatedErrors,UpdatedCreateReq); + true -> %OK + UpdatedCreateReq=CreateReq#sesT_createReqV0{flowLblData=FlowLabel}, + decode_ie_create(Rest,(PresentIEs bor 16#00000008),Errors, + UpdatedCreateReq) + end; + +%%% Flow Label Signalling, Mandatory +decode_ie_create(<<17:8,FlowLabel:16,Rest/binary>>,PresentIEs,Errors,CreateReq) -> + if + (PresentIEs band 16#00000010) =:= 16#00000010 -> %Repeated IE, ignored + decode_ie_create(Rest,PresentIEs,Errors,CreateReq); + PresentIEs > 16#00000010 -> %Out of sequence + UpdatedErrors=Errors#protocolErrors{outOfSequence=true}, + UpdatedCreateReq=CreateReq#sesT_createReqV0{flowLblSig=FlowLabel}, + decode_ie_create(Rest,(PresentIEs bor 16#00000010), + UpdatedErrors,UpdatedCreateReq); + true -> %OK + UpdatedCreateReq=CreateReq#sesT_createReqV0{flowLblSig=FlowLabel}, + decode_ie_create(Rest,(PresentIEs bor 16#00000010),Errors, + UpdatedCreateReq) + end; + +%%% End User Address, Mandatory +decode_ie_create(<<128:8,Length:16,More/binary>>,PresentIEs, + Errors,CreateReq) -> + <<PDPElement:Length/binary-unit:8,Rest/binary>> = More, + if + (PresentIEs band 16#00000020) =:= 16#00000020 -> %Repeated IE, ignore + decode_ie_create(Rest,PresentIEs,Errors,CreateReq); + PresentIEs > 16#00000020 -> %Out of sequence + case pdp_addr_internal_storage(PDPElement) of + {ok,PDPAddress} -> + UpdatedErrors=Errors#protocolErrors{outOfSequence=true}, + UpdatedCreateReq=CreateReq#sesT_createReqV0{endUserAdd=PDPAddress}, + decode_ie_create(Rest,(PresentIEs bor 16#00000020), + UpdatedErrors,UpdatedCreateReq); + {fault} -> + UpdatedErrors=Errors#protocolErrors{invalidManIE=true, + outOfSequence=true}, + decode_ie_create(Rest,(PresentIEs bor 16#00000020), + UpdatedErrors,CreateReq) + end; + true -> %OK + case pdp_addr_internal_storage(PDPElement) of + {ok,PDPAddress} -> + UpdatedCreateReq=CreateReq#sesT_createReqV0{endUserAdd=PDPAddress}, + decode_ie_create(Rest,(PresentIEs bor 16#00000020), + Errors,UpdatedCreateReq); + {fault} -> + UpdatedErrors=Errors#protocolErrors{invalidManIE=true}, + decode_ie_create(Rest,(PresentIEs bor 16#00000020), + UpdatedErrors,CreateReq) + end + end; + +%%% Access Point Name, Mandatory +decode_ie_create(<<131:8,Length:16,More/binary>>,PresentIEs, + Errors,CreateReq) -> + <<APNElement:Length/binary-unit:8,Rest/binary>> = More, + if + (PresentIEs band 16#00000040) =:= 16#00000040 -> %Repeated IE, ignore + decode_ie_create(Rest,PresentIEs,Errors,CreateReq); + PresentIEs > 16#00000040 -> %Out of sequence + case catch apn_internal_storage(APNElement,[]) of + {ok,APN} -> + UpdatedErrors=Errors#protocolErrors{outOfSequence=true}, + UpdatedCreateReq=CreateReq#sesT_createReqV0{accPointName=APN}, + decode_ie_create(Rest,(PresentIEs bor 16#00000040), + UpdatedErrors,UpdatedCreateReq); + _ -> + UpdatedErrors=Errors#protocolErrors{outOfSequence=true, + invalidManIE=true}, + decode_ie_create(Rest,(PresentIEs bor 16#00000040), + UpdatedErrors,CreateReq) + end; + true -> %OK + case catch apn_internal_storage(APNElement,[]) of + {ok,APN} -> + UpdatedCreateReq=CreateReq#sesT_createReqV0{accPointName=APN}, + decode_ie_create(Rest,(PresentIEs bor 16#00000040), + Errors,UpdatedCreateReq); + _ -> + UpdatedErrors=Errors#protocolErrors{invalidManIE=true}, + decode_ie_create(Rest,(PresentIEs bor 16#00000040), + UpdatedErrors,CreateReq) + end + end; + +%%% Protocol Configuration Options, Optional +decode_ie_create(<<132:8,Length:16,More/binary>>,PresentIEs,Errors,CreateReq) -> + <<ConfigurationElement:Length/binary-unit:8,Rest/binary>> = More, + if + (PresentIEs band 16#00000080) =:= 16#00000080 -> %Repeated IE, ignore + decode_ie_create(Rest,PresentIEs,Errors,CreateReq); + PresentIEs > 16#00000080 -> %Out of sequence + case catch pco_internal_storage(ConfigurationElement) of + {ok,PCO} -> + UpdatedErrors=Errors#protocolErrors{outOfSequence=true}, + UpdatedCreateReq=CreateReq#sesT_createReqV0{protConOpt=PCO}, + decode_ie_create(Rest,(PresentIEs bor 16#00000080), + UpdatedErrors,UpdatedCreateReq); + _ -> + UpdatedErrors=Errors#protocolErrors{outOfSequence=true, + incorrectOptIE=true}, + decode_ie_create(Rest,(PresentIEs bor 16#00000080), + UpdatedErrors,CreateReq) + end; + true -> %OK + case catch pco_internal_storage(ConfigurationElement) of + {ok,PCO} -> + UpdatedCreateReq=CreateReq#sesT_createReqV0{protConOpt=PCO}, + decode_ie_create(Rest,(PresentIEs bor 16#00000080), + Errors,UpdatedCreateReq); + _ -> + UpdatedErrors=Errors#protocolErrors{incorrectOptIE=true}, + decode_ie_create(Rest,(PresentIEs bor 16#00000080), + UpdatedErrors,CreateReq) + end + end; + +%%% SGSN Address for signalling, Mandatory OR SGSN Address for user traffic, Mandatory +decode_ie_create(<<133:8,Length:16,More/binary>>,PresentIEs, + Errors,CreateReq) -> + <<AddressElement:Length/binary-unit:8,Rest/binary>> = More, + if + (PresentIEs band 16#00000300) =:= 16#00000300 -> %Repeated IE, ignore + decode_ie_create(Rest,PresentIEs,Errors,CreateReq); + PresentIEs > 16#00000200 -> %Out of sequence + if + (PresentIEs band 16#00000100) =:= 16#00000000 -> %Signalling + case gsn_addr_internal_storage(AddressElement) of + {ok,GSNAddr} -> + UpdatedErrors=Errors#protocolErrors{outOfSequence=true}, + UpdatedCreateReq=CreateReq#sesT_createReqV0{sgsnAddSig=GSNAddr}, + decode_ie_create(Rest,(PresentIEs bor 16#00000100), + UpdatedErrors,UpdatedCreateReq); + {fault} -> + UpdatedErrors=Errors#protocolErrors{invalidManIE=true, + outOfSequence=true}, + decode_ie_create(Rest,(PresentIEs bor 16#00000100), + UpdatedErrors,CreateReq) + end; + true -> % User traffic + case gsn_addr_internal_storage(AddressElement) of + {ok,GSNAddr} -> + UpdatedErrors=Errors#protocolErrors{outOfSequence=true}, + UpdatedCreateReq=CreateReq#sesT_createReqV0{sgsnAddUser=GSNAddr}, + decode_ie_create(Rest,(PresentIEs bor 16#00000200), + UpdatedErrors,UpdatedCreateReq); + {fault} -> + UpdatedErrors=Errors#protocolErrors{invalidManIE=true, + outOfSequence=true}, + decode_ie_create(Rest,(PresentIEs bor 16#00000200), + UpdatedErrors,CreateReq) + end + end; + PresentIEs < 16#00000100 -> %OK, SGSN Address for signalling + case gsn_addr_internal_storage(AddressElement) of + {ok,GSNAddr} -> + UpdatedCreateReq=CreateReq#sesT_createReqV0{sgsnAddSig=GSNAddr}, + decode_ie_create(Rest,(PresentIEs bor 16#00000100), + Errors,UpdatedCreateReq); + {fault} -> + UpdatedErrors=Errors#protocolErrors{invalidManIE=true}, + decode_ie_create(Rest,(PresentIEs bor 16#00000100), + UpdatedErrors,CreateReq) + end; + true -> %OK, SGSN Address for user traffic + case gsn_addr_internal_storage(AddressElement) of + {ok,GSNAddr} -> + UpdatedCreateReq=CreateReq#sesT_createReqV0{sgsnAddUser=GSNAddr}, + decode_ie_create(Rest,(PresentIEs bor 16#00000200), + Errors,UpdatedCreateReq); + {fault} -> + UpdatedErrors=Errors#protocolErrors{invalidManIE=true}, + decode_ie_create(Rest,(PresentIEs bor 16#00000200), + UpdatedErrors,CreateReq) + end + end; + +%%% MSISDN, Mandatory +decode_ie_create(<<134:8,Length:16,More/binary>>,PresentIEs, + Errors,CreateReq) -> + <<MSISDNElement:Length/binary-unit:8,Rest/binary>> = More, + if + (PresentIEs band 16#00000400) =:= 16#00000400 -> %Repeated IE, ignore + decode_ie_create(Rest,PresentIEs,Errors,CreateReq); + PresentIEs > 16#00000400 -> %Out of sequence + case msisdn_internal_storage(MSISDNElement,[]) of + {ok,MSISDN} -> + UpdatedErrors=Errors#protocolErrors{outOfSequence=true}, + UpdatedCreateReq=CreateReq#sesT_createReqV0{msisdn=MSISDN}, + decode_ie_create(Rest,(PresentIEs bor 16#00000400), + UpdatedErrors,UpdatedCreateReq); + {fault} -> + UpdatedErrors=Errors#protocolErrors{outOfSequence=true,invalidManIE=true}, + decode_ie_create(Rest,(PresentIEs bor 16#00000400), + UpdatedErrors,CreateReq) + end; + true -> %OK + UpdatedCreateReq=CreateReq#sesT_createReqV0{msisdn=#mvsT_msisdn{value=MSISDNElement}}, + decode_ie_create(Rest,(PresentIEs bor 16#00000400), + Errors,UpdatedCreateReq) + + end; + +%%% Private Extension, Optional +%%% Not implemented + +%%% Error handling, Unexpected or unknown IE +decode_ie_create(UnexpectedIE,PresentIEs,Errors,CreateReq) -> + case check_ie(UnexpectedIE) of + {defined_ie,Rest} -> %OK, ignored + decode_ie_create(Rest,PresentIEs,Errors,CreateReq); + {handled_ie,Rest} -> %OK, ignored + decode_ie_create(Rest,PresentIEs,Errors,CreateReq); + {unhandled_ie} -> %Error, abort decoding + {fault,193,CreateReq} %Invalid message format + end. + +%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +%%% decode_ie_update/4 +%%% Decode information elements for Update PDP Context Request + +%%% All elements decoded +decode_ie_update(<<>>,PresentIEs,Errors,UpdateReq) -> + %% Check mandatory IE's + if + (PresentIEs band 16#3D) =/= 16#3D -> + {fault,202,UpdateReq}; %Mandatory IE missing + true -> %OK + %% Check errors during decoding + case Errors of + #protocolErrors{invalidManIE=true} -> %Invalid mandatory IE + {fault,201,UpdateReq}; %Mandatory IE incorrect + #protocolErrors{outOfSequence=true} -> %Out of sequence + {fault,193,UpdateReq}; %Invalid message format + _ -> %OK + {ok,UpdateReq} + end + end; + +%%% Quality of Service Profile, Mandatory +decode_ie_update(<<6:8,QoSElement:3/binary-unit:8,Rest/binary>>,PresentIEs, + Errors,UpdateReq) -> + if + (PresentIEs band 16#00000001) =:= 16#00000001 -> %Repeated IE's, ignore + decode_ie_update(Rest,PresentIEs,Errors,UpdateReq); + PresentIEs > 16#00000001 -> %Out of sequence + UpdatedErrors=Errors#protocolErrors{outOfSequence=true}, + <<_:2,DelayClass:3,ReliabilityClass:3, + PeakThroughput:4,_:1,PrecedenceClass:3, + _:3,MeanThroughput:5>> = QoSElement, + QoS=#sesT_qualityOfServiceV0{delayClass=DelayClass, + reliabilityClass=ReliabilityClass, + peakThroughput=PeakThroughput, + precedenceClass=PrecedenceClass, + meanThroughput=MeanThroughput}, + UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{qos=QoS}, + decode_ie_update(Rest,(PresentIEs bor 16#00000001), + UpdatedErrors,UpdatedUpdateReq); + true -> %OK + <<_:2,DelayClass:3,ReliabilityClass:3, + PeakThroughput:4,_:1,PrecedenceClass:3, + _:3,MeanThroughput:5>> = QoSElement, + QoS=#sesT_qualityOfServiceV0{delayClass=DelayClass, + reliabilityClass=ReliabilityClass, + peakThroughput=PeakThroughput, + precedenceClass=PrecedenceClass, + meanThroughput=MeanThroughput}, + UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{qos=QoS}, + decode_ie_update(Rest,(PresentIEs bor 16#00000001), + Errors,UpdatedUpdateReq) + end; + +%%% Recovery, Optional +decode_ie_update(<<14:8,Recovery:8,Rest/binary>>,PresentIEs,Errors,UpdateReq) -> + if + (PresentIEs band 16#00000002) =:= 16#00000002 -> %Repeated IE, ignored + decode_ie_update(Rest,PresentIEs,Errors,UpdateReq); + PresentIEs > 16#00000002 -> %Out of sequence + UpdatedErrors=Errors#protocolErrors{outOfSequence=true}, + UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{recovery=Recovery}, + decode_ie_update(Rest,(PresentIEs bor 16#00000002), + UpdatedErrors,UpdatedUpdateReq); + true -> %OK + UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{recovery=Recovery}, + decode_ie_update(Rest,(PresentIEs bor 16#00000002),Errors, + UpdatedUpdateReq) + end; + +%%% Flow Label Data I, Mandatory +decode_ie_update(<<16:8,FlowLabel:16,Rest/binary>>,PresentIEs,Errors,UpdateReq) -> + if + (PresentIEs band 16#00000004) =:= 16#00000004 -> %Repeated IE, ignored + decode_ie_update(Rest,PresentIEs,Errors,UpdateReq); + PresentIEs > 16#00000004 -> %Out of sequence + UpdatedErrors=Errors#protocolErrors{outOfSequence=true}, + UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{flowLblData=FlowLabel}, + decode_ie_update(Rest,(PresentIEs bor 16#00000004), + UpdatedErrors,UpdatedUpdateReq); + true -> %OK + UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{flowLblData=FlowLabel}, + decode_ie_update(Rest,(PresentIEs bor 16#00000004),Errors, + UpdatedUpdateReq) + end; + +%%% Flow Label Signalling, Mandatory +decode_ie_update(<<17:8,FlowLabel:16,Rest/binary>>,PresentIEs,Errors,UpdateReq) -> + if + (PresentIEs band 16#00000008) =:= 16#00000008 -> %Repeated IE, ignored + decode_ie_update(Rest,PresentIEs,Errors,UpdateReq); + PresentIEs > 16#00000008 -> %Out of sequence + UpdatedErrors=Errors#protocolErrors{outOfSequence=true}, + UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{flowLblSig=FlowLabel}, + decode_ie_update(Rest,(PresentIEs bor 16#00000008), + UpdatedErrors,UpdatedUpdateReq); + true -> %OK + UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{flowLblSig=FlowLabel}, + decode_ie_update(Rest,(PresentIEs bor 16#00000008),Errors, + UpdatedUpdateReq) + end; + +%%% SGSN Address for signalling, Mandatory OR SGSN Address for user traffic, Mandatory +decode_ie_update(<<133:8,Length:16,More/binary>>,PresentIEs, + Errors,UpdateReq) -> + <<AddressElement:Length/binary-unit:8,Rest/binary>> = More, + if + (PresentIEs band 16#00000030) =:= 16#00000030 -> %Repeated IE, ignore + decode_ie_update(Rest,PresentIEs,Errors,UpdateReq); + PresentIEs > 16#00000020 -> %Out of sequence + if + (PresentIEs band 16#00000010) =:= 16#00000000 -> %Signalling + case gsn_addr_internal_storage(AddressElement) of + {ok,GSNAddr} -> + UpdatedErrors=Errors#protocolErrors{outOfSequence=true}, + UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{sgsnAddSig=GSNAddr}, + decode_ie_update(Rest,(PresentIEs bor 16#00000010), + UpdatedErrors,UpdatedUpdateReq); + {fault} -> + UpdatedErrors=Errors#protocolErrors{invalidManIE=true, + outOfSequence=true}, + decode_ie_update(Rest,(PresentIEs bor 16#00000010), + UpdatedErrors,UpdateReq) + end; + true -> % User traffic + case gsn_addr_internal_storage(AddressElement) of + {ok,GSNAddr} -> + UpdatedErrors=Errors#protocolErrors{outOfSequence=true}, + UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{sgsnAddUser=GSNAddr}, + decode_ie_update(Rest,(PresentIEs bor 16#00000020), + UpdatedErrors,UpdatedUpdateReq); + {fault} -> + UpdatedErrors=Errors#protocolErrors{invalidManIE=true, + outOfSequence=true}, + decode_ie_update(Rest,(PresentIEs bor 16#00000020), + UpdatedErrors,UpdateReq) + end + end; + PresentIEs < 16#00000010 -> %OK, SGSN Address for signalling + case gsn_addr_internal_storage(AddressElement) of + {ok,GSNAddr} -> + UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{sgsnAddSig=GSNAddr}, + decode_ie_update(Rest,(PresentIEs bor 16#00000010), + Errors,UpdatedUpdateReq); + {fault} -> + UpdatedErrors=Errors#protocolErrors{invalidManIE=true}, + decode_ie_update(Rest,(PresentIEs bor 16#00000010), + UpdatedErrors,UpdateReq) + end; + true -> %OK, SGSN Address for user traffic + case gsn_addr_internal_storage(AddressElement) of + {ok,GSNAddr} -> + UpdatedUpdateReq=UpdateReq#sesT_updateReqV0{sgsnAddUser=GSNAddr}, + decode_ie_update(Rest,(PresentIEs bor 16#00000020), + Errors,UpdatedUpdateReq); + {fault} -> + UpdatedErrors=Errors#protocolErrors{invalidManIE=true}, + decode_ie_update(Rest,(PresentIEs bor 16#00000020), + UpdatedErrors,UpdateReq) + end + end; + +%%% Private Extension, Optional +%%% Not implemented + +%%% Error handling, Unexpected or unknown IE +decode_ie_update(UnexpectedIE,PresentIEs,Errors,UpdateReq) -> + case check_ie(UnexpectedIE) of + {defined_ie,Rest} -> %OK, ignored + decode_ie_update(Rest,PresentIEs,Errors,UpdateReq); + {handled_ie,Rest} -> %OK, ignored + decode_ie_update(Rest,PresentIEs,Errors,UpdateReq); + {unhandled_ie} -> %Error, abort decoding + {fault,193,UpdateReq} %Invalid message format + end. + + +%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +%%% decode_ie_delete_req/4 +%%% Decode information elements for Delete PDP Context Request + +%%% Private Extension, Optional +%%% Not implemented + + +%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +%%% decode_ie_delete_res/4 +%%% Decode information elements for Delete PDP Context Response + +%%% All elements decoded +decode_ie_delete_res(<<>>,PresentIEs,DeleteRes) -> + %% Check mandatory IE's + if + (PresentIEs band 16#0001) =/= 16#0001 -> + {fault,202,DeleteRes}; %Mandatory IE missing + true -> %OK + {ok,DeleteRes} + end; + +%%% Cause, Mandatory +decode_ie_delete_res(<<1:8,Cause:8,Rest/binary>>,PresentIEs,DeleteRes) -> + if + (PresentIEs band 16#00000001) =:= 16#00000001 -> %Repeated IE, ignored + decode_ie_delete_res(Rest,PresentIEs,DeleteRes); + true -> %OK + UpdatedDeleteRes=DeleteRes#sesT_deleteResV0{cause=Cause}, + decode_ie_delete_res(Rest,(PresentIEs bor 16#00000001), + UpdatedDeleteRes) + end; + +%%% Private Extension, Optional +%%% Not implemented + +%%% Error handling, Unexpected or unknown IE +decode_ie_delete_res(UnexpectedIE,PresentIEs,DeleteRes) -> + case check_ie(UnexpectedIE) of + {defined_ie,Rest} -> %OK, ignored + decode_ie_delete_res(Rest,PresentIEs,DeleteRes); + {handled_ie,Rest} -> %OK, ignored + decode_ie_delete_res(Rest,PresentIEs,DeleteRes); + {unhandled_ie} -> %Error, abort decoding + {fault,193,DeleteRes} %Invalid message format + end. + +%%% -------------------------------------------------------------- +%%% #3.2 COMMON INTERNAL FUNCTIONS +%%% -------------------------------------------------------------- + +%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +%%% check_ie/1 +%%% Check Information Element, Unexpected or Unknown +check_ie(<<1:8,_:8,Rest/binary>>) -> + {defined_ie,Rest}; +%%% IMSI +check_ie(<<2:8,_:8/binary-unit:8,Rest/binary>>) -> + {defined_ie,Rest}; +%%% RAI +check_ie(<<3:8,_:6/binary-unit:8,Rest/binary>>) -> + {defined_ie,Rest}; +%%% TTLI +check_ie(<<4:8,_:4/binary-unit:8,Rest/binary>>) -> + {defined_ie,Rest}; +%%% P-TMSI +check_ie(<<5:8,_:4/binary-unit:8,Rest/binary>>) -> + {defined_ie,Rest}; +%%% Quality of Service Profile +check_ie(<<6:8,_:3/binary-unit:8,Rest/binary>>) -> + {defined_ie,Rest}; +%%% Reordering Required +check_ie(<<8:8,_:8,Rest/binary>>) -> + {defined_ie,Rest}; +%%% Authentication Triplet +check_ie(<<9:8,_:28/binary-unit:8,Rest/binary>>) -> + {defined_ie,Rest}; +%%% MAP Cause +check_ie(<<11:8,_:8,Rest/binary>>) -> + {defined_ie,Rest}; +%%% P-TMSI Signature +check_ie(<<12:8,_:3/binary-unit:8,Rest/binary>>) -> + {defined_ie,Rest}; +%%% MS Validated +check_ie(<<13:8,_:8,Rest/binary>>) -> + {defined_ie,Rest}; +%%% Recovery +check_ie(<<14:8,_:8,Rest/binary>>) -> + {defined_ie,Rest}; +%%% Selection Mode +check_ie(<<15:8,_:8,Rest/binary>>) -> + {defined_ie,Rest}; +%%% Flow Label Data I +check_ie(<<16:8,_:16,Rest/binary>>) -> + {defined_ie,Rest}; +%%% Flow Label Signalling +check_ie(<<17:8,_:16,Rest/binary>>) -> + {defined_ie,Rest}; +%%% Flow Label Data II +check_ie(<<18:8,_:32,Rest/binary>>) -> + {defined_ie,Rest}; +%%% MS Not Reachable Reason +check_ie(<<19:8,_:8,Rest/binary>>) -> + {defined_ie,Rest}; +%%% Charging ID +check_ie(<<127:8,_:4/binary-unit:8,Rest/binary>>) -> + {defined_ie,Rest}; +%%% TLV element, skipped using Length +check_ie(<<1:1,_:7,Length:16,More/binary>>) -> + if + Length > byte_size(More) -> + {unhandled_ie}; + true -> + <<_:Length/binary-unit:8,Rest/binary>> = More, + {handled_ie,Rest} + end; +%%% TV element, unknown size. Can not be handled. +check_ie(_UnhandledIE) -> + {unhandled_ie}. + +%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +%%% tid_internal_storage/3 +%%% Convert TID binary to internal datatype +tid_internal_storage(Bin,_) -> + Size = byte_size(Bin) - 1, + <<Front:Size/binary,NSAPI:4,DigitN:4>> = Bin, + Result = + case DigitN of + 2#1111 -> + #mvsgT_tid{imsi = #mvsgT_imsi{value = Front}, nsapi = NSAPI}; + _ -> + Value = <<Front/binary,2#1111:4,DigitN:4>>, + #mvsgT_tid{imsi = #mvsgT_imsi{value = Value}, nsapi = NSAPI} + end, + {ok,Result}. +%% tid_internal_storage(<<NSAPI:4,2#1111:4>>,IMSI) -> +%% {ok,#mvsgT_tid{imsi=#mvsgT_imsi{value=lists:reverse(IMSI)}, +%% nsapi=NSAPI}}; +%% tid_internal_storage(<<NSAPI:4,DigitN:4>>,IMSI) when +%% DigitN < 10 -> +%% {ok,#mvsgT_tid{imsi=#mvsgT_imsi{value=lists:reverse([(DigitN bor 2#11110000)|IMSI])}, +%% nsapi=NSAPI}}; +%% tid_internal_storage(<<2#11111111:8,Rest/binary>>,IMSI) -> +%% tid_internal_storage(Rest,IMSI); +%% tid_internal_storage(<<2#1111:4,DigitN:4,Rest/binary>>,IMSI) when +%% DigitN < 10 -> +%% tid_internal_storage(Rest,[(DigitN bor 2#11110000)|IMSI]); +%% tid_internal_storage(<<DigitNplus1:4,DigitN:4,Rest/binary>>,IMSI) when +%% DigitNplus1 < 10, +%% DigitN < 10 -> +%% tid_internal_storage(Rest,[((DigitNplus1 bsl 4) bor DigitN)|IMSI]); +%% tid_internal_storage(_Rest,_IMSI) -> +%% {fault}. %% Mandatory IE incorrect + +%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +%%% selection_mode_internal_storage/1 +%%% Convert Selection Mode integer to internal datatype (enum) +selection_mode_internal_storage(0) -> + subscribed; +selection_mode_internal_storage(1) -> + msRequested; +selection_mode_internal_storage(2) -> + sgsnSelected; +selection_mode_internal_storage(3) -> + sgsnSelected. + +%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +%%% pdp_addr_internal_storage/1 +%%% Convert PDP address to internal datatype (record containing +%%% addresstype and value) +pdp_addr_internal_storage(<<_:4,0:4,1:8>>) -> + {ok,#mvsgT_pdpAddressType{pdpTypeNbr=etsi_ppp,address=[]}}; +pdp_addr_internal_storage(<<_:4,0:4,2:8>>) -> + {ok,#mvsgT_pdpAddressType{pdpTypeNbr=etsi_osp_ihoss,address=[]}}; +pdp_addr_internal_storage(<<_:4,1:4,16#21:8>>) -> + {ok,#mvsgT_pdpAddressType{pdpTypeNbr=ietf_ipv4,address=[]}}; +pdp_addr_internal_storage(<<_:4,1:4,16#21:8,IP_A:8,IP_B:8,IP_C:8,IP_D:8>>) -> + {ok,#mvsgT_pdpAddressType{pdpTypeNbr=ietf_ipv4, + address=[IP_A,IP_B,IP_C,IP_D]}}; +pdp_addr_internal_storage(<<_:4,1:4,16#57:8,IP_A:16,IP_B:16,IP_C:16,IP_D:16, + IP_E:16,IP_F:16,IP_G:16,IP_H:16>>) -> + {ok,#mvsgT_pdpAddressType{pdpTypeNbr=ietf_ipv6, + address=[IP_A,IP_B,IP_C,IP_D,IP_E,IP_F,IP_G,IP_H]}}; +pdp_addr_internal_storage(_PDP_ADDR) -> + {fault}. + +%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +%%% apn_internal_storage/2 +%%% Convert APN to internal datatype (List containing APN labels) +apn_internal_storage(<<>>,APN) -> + {ok,lists:reverse(APN)}; +apn_internal_storage(<<Length:8,Rest/binary>>,APN) -> + <<Label:Length/binary-unit:8,MoreAPNLabels/binary>> = Rest, + apn_internal_storage(MoreAPNLabels,[Label|APN]). + +%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +%%% pco_internal_storage/1 +%%% Convert Protocol Configuration Options to internal datatype. +%%% Implemented configuration options: +%%% For PPP: +%%% LCP - Not implemented +%%% PAP - Authenticate request +%%% CHAP - Challenge +%%% - Response +%%% IPCP - IP-Address +%%% For OSP:IHOSS +%%% Nothing implemented +pco_internal_storage(<<1:1,_:4,0:3,PPPConfigurationOptions/binary>>) -> + case ppp_configuration_options(PPPConfigurationOptions, + #masT_pap{exists=false},[],[]) of + {ok,PAP,CHAP,IPCP} -> + {ok,#masT_protocolConfigOptions{pap=PAP,chap=CHAP,ipcp=IPCP}}; + {fault} -> + {fault} + end; +pco_internal_storage(<<1:1,_:4,1:3,_OSP_IHOSSConfigurationOptions/binary>>) -> + {ok,osp_ihoss}; +pco_internal_storage(_UnknownConfigurationOptions) -> + {fault}. %% Optional IE incorrect + +ppp_configuration_options(<<>>,PAP,CHAP,IPCP) -> + {ok,PAP,CHAP,IPCP}; +ppp_configuration_options(<<16#C021:16,Length:8,More/binary>>,PAP,CHAP,IPCP) -> + %% LCP - Not implemented + <<_LCP:Length/binary-unit:8,Rest/binary>> = More, + ppp_configuration_options(Rest,PAP,CHAP,IPCP); +ppp_configuration_options(<<16#C023:16,_Length:8,1:8,Identifier:8,DataLength:16, + More/binary>>,_PAP,CHAP,IPCP) -> + %% PAP - Authenticate request + ActualDataLength=DataLength-4, %% DataLength includes Code, Identifier and itself + <<Data:ActualDataLength/binary-unit:8,Rest/binary>> = More, + <<PeerIDLength:8,PeerData/binary>> = Data, + <<PeerID:PeerIDLength/binary-unit:8,PasswdLength:8,PasswordData/binary>> = PeerData, + <<Password:PasswdLength/binary,_Padding/binary>> = PasswordData, + ppp_configuration_options(Rest,#masT_pap{exists=true,code=1,id=Identifier, + username=binary_to_list(PeerID), + password=binary_to_list(Password)},CHAP,IPCP); + +ppp_configuration_options(<<16#C023:16,Length:8,More/binary>>,PAP,CHAP,IPCP) -> + %% PAP - Other, not implemented + <<_PAP:Length/binary-unit:8,Rest/binary>> = More, + ppp_configuration_options(Rest,PAP,CHAP,IPCP); +ppp_configuration_options(<<16#C223:16,_Length:8,1:8,Identifier:8,DataLength:16, + More/binary>>,PAP,CHAP,IPCP) -> + %% CHAP - Challenge + ActualDataLength=DataLength-4, %% DataLength includes Code, Identifier and itself + <<Data:ActualDataLength/binary-unit:8,Rest/binary>> = More, + <<ValueSize:8,ValueAndName/binary>> = Data, + <<Value:ValueSize/binary-unit:8,Name/binary>> = ValueAndName, + ppp_configuration_options(Rest,PAP,[#masT_chap{code=1,id=Identifier, + value=binary_to_list(Value), + name=binary_to_list(Name)}|CHAP], + IPCP); +ppp_configuration_options(<<16#C223:16,_Length:8,2:8,Identifier:8,DataLength:16, + More/binary>>,PAP,CHAP,IPCP) -> + %% CHAP - Response + ActualDataLength=DataLength-4, %% DataLength includes Code, Identifier and itself + <<Data:ActualDataLength/binary-unit:8,Rest/binary>> = More, + <<ValueSize:8,ValueAndName/binary>> = Data, + <<Value:ValueSize/binary-unit:8,Name/binary>> = ValueAndName, + ppp_configuration_options(Rest,PAP,[#masT_chap{code=2,id=Identifier, + value=binary_to_list(Value), + name=binary_to_list(Name)}|CHAP], + IPCP); +ppp_configuration_options(<<16#C223:16,Length:8,More/binary>>,PAP,CHAP,IPCP) -> + %% CHAP - Other, not implemented + <<_CHAP:Length/binary-unit:8,Rest/binary>> = More, + ppp_configuration_options(Rest,PAP,CHAP,IPCP); +ppp_configuration_options(<<16#8021:16,_Length:8,1:8,Identifier:8,OptionsLength:16, + More/binary>>,PAP,CHAP,IPCP) -> + %% IPCP - Configure request + ActualOptionsLength=OptionsLength-4, %% OptionsLength includes Code, Identifier and itself + <<Options:ActualOptionsLength/binary-unit:8,Rest/binary>> = More, + case Options of + <<3:8,6:8,A1:8,A2:8,A3:8,A4:8>> -> + %% IP Address, version 4 + ppp_configuration_options(Rest,PAP,CHAP, + [#masT_ipcp{exists=true,code=1, + id=Identifier, + ipcpList=[#masT_ipcpData{type=3,ipAddress= + #mvsgT_ipAddress{version=ipv4, + a1=A1,a2=A2, + a3=A3,a4=A4, + a5=0,a6=0, + a7=0,a8=0}, + rawMessage=binary_to_list(Options)}]}|IPCP]); + <<129:8,6:8,B1:8,B2:8,B3:8,B4:8>> -> + %% IP Address, version 4 + ppp_configuration_options(Rest,PAP,CHAP, + [#masT_ipcp{exists=true,code=1, + id=Identifier, + ipcpList=[#masT_ipcpData{type=129,ipAddress= + #mvsgT_ipAddress{version=ipv4, + a1=B1,a2=B2, + a3=B3,a4=B4}, + rawMessage=binary_to_list(Options)}]}|IPCP]); + + <<131:8,6:8,C1:8,C2:8,C3:8,C4:8>> -> + %% IP Address, version 4 + ppp_configuration_options(Rest,PAP,CHAP, + [#masT_ipcp{exists=true,code=1, + id=Identifier, + ipcpList=[#masT_ipcpData{type=131,ipAddress= + #mvsgT_ipAddress{version=ipv4, + a1=C1,a2=C2, + a3=C3,a4=C4}, + rawMessage=binary_to_list(Options)}]}|IPCP]); + _ -> + ppp_configuration_options(Rest,PAP,CHAP,IPCP) + end; +ppp_configuration_options(<<_UnknownProtocolID:16,Length:8,More/binary>>, + PAP,CHAP,IPCP) -> + <<_Skipped:Length/binary-unit:8,Rest/binary>> = More, + ppp_configuration_options(Rest,PAP,CHAP,IPCP); +ppp_configuration_options(_Unhandled,_PAP,_CHAP,_IPCP) -> + {fault}. + +%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +%%% gsn_addr_internal_storage/1 +%%% Convert GSN Address to internal datatype +gsn_addr_internal_storage(<<IP_A:8,IP_B:8,IP_C:8,IP_D:8>>) -> + {ok,#mvsgT_ipAddress{version=ipv4,a1=IP_A,a2=IP_B,a3=IP_C,a4=IP_D,a5=0,a6=0,a7=0,a8=0}}; +gsn_addr_internal_storage(<<IP_A:16,IP_B:16,IP_C:16,IP_D:16, + IP_E:16,IP_F:16,IP_G:16,IP_H:16>>) -> + {ok,#mvsgT_ipAddress{version=ipv6,a1=IP_A,a2=IP_B,a3=IP_C,a4=IP_D, + a5=IP_E,a6=IP_F,a7=IP_G,a8=IP_H}}; +gsn_addr_internal_storage(_GSN_ADDR) -> + {fault}. + +%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +%%% msisdn_internal_storage/3 +%%% Convert MSISDN binary to internal datatype (TBCD-octet list) + +msisdn_internal_storage(<<>>,MSISDN) -> + {ok,#mvsT_msisdn{value=lists:reverse(MSISDN)}}; +msisdn_internal_storage(<<2#11111111:8,_Rest/binary>>,MSISDN) -> + {ok,#mvsT_msisdn{value=lists:reverse(MSISDN)}}; +msisdn_internal_storage(<<2#1111:4,DigitN:4,_Rest/binary>>,MSISDN) when + DigitN < 10 -> + {ok,#mvsT_msisdn{value=lists:reverse([(DigitN bor 2#11110000)|MSISDN])}}; +msisdn_internal_storage(<<DigitNplus1:4,DigitN:4,Rest/binary>>,MSISDN) when + DigitNplus1 < 10, + DigitN < 10 -> + NewMSISDN=[((DigitNplus1 bsl 4) bor DigitN)|MSISDN], + msisdn_internal_storage(Rest,NewMSISDN); +msisdn_internal_storage(_Rest,_MSISDN) -> + {fault}. %% Mandatory IE incorrect |