sccp codec: correctly parse and encode CR message variable/optional part

This commit is contained in:
Harald Welte 2012-01-23 16:15:06 +01:00
parent c923a2ab0b
commit 9dda4e179a
1 changed files with 83 additions and 16 deletions

View File

@ -111,8 +111,9 @@ parse_sccp_addr(BinAddr) when is_binary(BinAddr) ->
point_code = OptPC, ssn = OptSSN, global_title = OptGT}.
% parse SCCP Optional Part
parse_sccp_opt(OptType, OptLen, Content) ->
{OptType, {OptLen, Content}}.
parse_sccp_opt(OptType, _OptLen, Content) ->
OptAtom = opt_to_atom(OptType),
{OptAtom, Content}.
parse_sccp_opts(<<>>, OptList) ->
% empty list
@ -125,6 +126,7 @@ parse_sccp_opts(OptBin, OptList) ->
NewOpt = parse_sccp_opt(OptType, OptLen, Content),
parse_sccp_opts(Remain, [NewOpt|OptList]).
% Parse incoming SCCP message, one function for every message type
parse_sccp_msgt(?SCCP_MSGT_CR, DataBin) ->
% first get the fixed part
@ -312,42 +314,59 @@ encode_sccp_addr(#sccp_addr{res_nat_use = ResNatUse,
<<ResNatOut:1, RoutIndOut:1, GTind:4, SSNind:1, PCind:1, PCbin/binary, SSNbin/binary, GTbin/binary>>.
encode_sccp_opt({OptNum, {DataBinLen, DataBin}}) when is_integer(OptNum) ->
DataBinLen8 = DataBinLen*8,
<<OptNum:8, DataBinLen:8, DataBin:DataBinLen8>>;
encode_sccp_opt({OptAtom,_}) when is_atom(OptAtom) ->
<<>>.
encode_sccp_opt({AddrTag, AddrVal}) when AddrTag == ?SCCP_PNC_CALLED_PARTY_ADDRESS;
AddrTag == ?SCCP_PNC_CALLING_PARTY_ADDRESS ->
AddrEnc = encode_sccp_addr(AddrVal),
AddrLen = byte_size(AddrEnc),
<<AddrTag:8, AddrLen:8, AddrEnc/binary>>;
encode_sccp_opt({OptInt, DataBin}) when is_binary(DataBin), is_integer(OptInt) ->
DataBinLen = byte_size(DataBin),
<<OptInt:8, DataBinLen:8, DataBin/binary>>;
encode_sccp_opt({Opt, DataBin}) when is_atom(Opt) ->
OptNum = atom_to_opt(Opt),
encode_sccp_opt({OptNum, DataBin});
encode_sccp_opt({Opt, DataInt}) when is_integer(DataInt), DataInt =< 255 ->
encode_sccp_opt({Opt, <<DataInt:8>>});
encode_sccp_opt({Opt, DataList}) when is_list(DataList) ->
encode_sccp_opt({Opt, list_to_binary(DataList)}).
encode_sccp_opts([], OptEnc) ->
encode_sccp_opts(OptList, Filter) ->
FilteredList = lists:filter(fun({Tag, _Val}) -> proplists:is_defined(opt_to_atom(Tag), Filter) end, OptList),
e_sccp_opts(FilteredList, []).
e_sccp_opts([], OptEnc) ->
% end of options + convert to binary
list_to_binary([OptEnc, ?SCCP_PNC_END_OF_OPTIONAL]);
encode_sccp_opts([CurOpt|OptPropList], OptEnc) ->
e_sccp_opts([CurOpt|OptPropList], OptEnc) ->
CurOptEnc = encode_sccp_opt(CurOpt),
encode_sccp_opts(OptPropList, list_to_binary([OptEnc,CurOptEnc])).
e_sccp_opts(OptPropList, list_to_binary([OptEnc,CurOptEnc])).
encode_sccp_msgt(?SCCP_MSGT_CR, Params) ->
SrcLocalRef = proplists:get_value(src_local_ref, Params),
{ProtoClass, PCOpt} = proplists:get_value(protocol_class, Params),
OptBin = encode_sccp_opts(Params, []),
<<?SCCP_MSGT_CR:8, SrcLocalRef:24/big, PCOpt:4, ProtoClass:4, OptBin/binary>>;
CalledParty = proplists:get_value(called_party_addr, Params),
CalledPartyEnc = encode_sccp_addr(CalledParty),
CalledPartyLen = byte_size(CalledPartyEnc),
PtrOpt = CalledPartyLen+1+1,
OptBin = encode_sccp_opts(Params, [credit, calling_party_addr, user_data, hop_counter, importance]),
<<?SCCP_MSGT_CR:8, SrcLocalRef:24/big, PCOpt:4, ProtoClass:4, 2:8, PtrOpt:8, CalledPartyLen:8, CalledPartyEnc/binary, OptBin/binary>>;
encode_sccp_msgt(?SCCP_MSGT_CC, Params) ->
SrcLocalRef = proplists:get_value(src_local_ref, Params),
DstLocalRef = proplists:get_value(dst_local_ref, Params),
{ProtoClass, PCOpt} = proplists:get_value(protocol_class, Params),
OptBin = encode_sccp_opts(Params, []),
OptBin = encode_sccp_opts(Params, [credit, called_party_addr, user_data, importance]),
<<?SCCP_MSGT_CC:8, DstLocalRef:24/big, SrcLocalRef:24/big, PCOpt:4, ProtoClass:4, OptBin/binary>>;
encode_sccp_msgt(?SCCP_MSGT_CREF, Params) ->
DstLocalRef = proplists:get_value(dst_local_ref, Params),
RefusalCause = proplists:get_value(refusal_cause, Params),
OptBin = encode_sccp_opts(Params, []),
OptBin = encode_sccp_opts(Params, [called_party_addr, user_data, importance]),
<<?SCCP_MSGT_CREF:8, DstLocalRef:24/big, RefusalCause:8, OptBin/binary>>;
encode_sccp_msgt(?SCCP_MSGT_RLSD, Params) ->
SrcLocalRef = proplists:get_value(src_local_ref, Params),
DstLocalRef = proplists:get_value(dst_local_ref, Params),
ReleaseCause = proplists:get_value(release_cause, Params),
OptBin = encode_sccp_opts(Params, []),
OptBin = encode_sccp_opts(Params, [user_data, importance]),
<<?SCCP_MSGT_RLSD:8, DstLocalRef:24/big, SrcLocalRef:24/big, ReleaseCause:8, OptBin/binary>>;
encode_sccp_msgt(?SCCP_MSGT_RLC, Params) ->
SrcLocalRef = proplists:get_value(src_local_ref, Params),
@ -474,3 +493,51 @@ gen_addr_helper(Gt, Pc) when is_record(Gt, global_title) ->
gen_addr_helper(Number, Pc) when is_list(Number) ->
Gt = gen_gt_helper(Number),
gen_addr_helper(Gt, Pc).
opt_to_atom(Num) ->
case Num of
?SCCP_PNC_DESTINATION_LOCAL_REFERENCE -> dst_local_ref;
?SCCP_PNC_SOURCE_LOCAL_REFERENCE -> src_local_ref;
?SCCP_PNC_CALLED_PARTY_ADDRESS -> called_party_addr;
?SCCP_PNC_CALLING_PARTY_ADDRESS -> calling_party_addr;
?SCCP_PNC_PROTOCOL_CLASS -> protocol_class;
?SCCP_PNC_SEGMENTING -> segmenting;
?SCCP_PNC_RECEIVE_SEQ_NUMBER -> rx_seq_number;
?SCCP_PNC_SEQUENCING -> seq_segm;
?SCCP_PNC_CREDIT -> credit;
?SCCP_PNC_RELEASE_CAUSE -> release_cause;
?SCCP_PNC_RETURN_CAUSE -> return_cause;
?SCCP_PNC_RESET_CAUSE -> reset_cause;
?SCCP_PNC_ERROR_CAUSE -> error_cause;
?SCCP_PNC_REFUSAL_CAUSE -> refusal_cause;
?SCCP_PNC_DATA -> user_data;
?SCCP_PNC_SEGMENTATION -> segmentation;
?SCCP_PNC_HOP_COUNTER -> hop_counter;
?SCCP_PNC_IMPORTANCE -> importance;
?SCCP_PNC_LONG_DATA -> long_data;
Foo -> Foo
end.
atom_to_opt(Atom) ->
case Atom of
dst_local_ref -> ?SCCP_PNC_DESTINATION_LOCAL_REFERENCE;
src_local_ref -> ?SCCP_PNC_SOURCE_LOCAL_REFERENCE;
called_party_addr -> ?SCCP_PNC_CALLED_PARTY_ADDRESS;
calling_party_addr -> ?SCCP_PNC_CALLING_PARTY_ADDRESS;
protocol_class -> ?SCCP_PNC_PROTOCOL_CLASS;
segmenting -> ?SCCP_PNC_SEGMENTING;
rx_seq_number -> ?SCCP_PNC_RECEIVE_SEQ_NUMBER;
seq_segm -> ?SCCP_PNC_SEQUENCING;
credit -> ?SCCP_PNC_CREDIT;
release_cause -> ?SCCP_PNC_RELEASE_CAUSE;
return_cause -> ?SCCP_PNC_RETURN_CAUSE;
reset_cause -> ?SCCP_PNC_RESET_CAUSE;
error_cause -> ?SCCP_PNC_ERROR_CAUSE;
refusal_cause -> ?SCCP_PNC_REFUSAL_CAUSE;
user_data -> ?SCCP_PNC_DATA;
segmentation -> ?SCCP_PNC_SEGMENTATION;
hop_counter -> ?SCCP_PNC_HOP_COUNTER;
importance -> ?SCCP_PNC_IMPORTANCE;
long_data -> ?SCCP_PNC_LONG_DATA;
Foo -> Foo
end.