1%% -*- erlang-indent-level: 2 -*-
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%%
4%% Among testing other things, this module shows why performing LCM on
5%% SPARC is currently problematic. SPARC does not mark untagged values
6%% as dead when they are live over function calls which in turn causes
7%% them to be traced by the garbage collector leading to crashes.
8%%
9%% A simple way to get this behaviour is to compile just the function
10%%
11%%            {bsextract,tid_internal_storage,2}
12%%
13%% with the compiler option "rtl_lcm" on and without.
14%%
15%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16
17-module(bs_extract).
18
19-export([test/0]).
20
21-include("bs_decode_extract.hrl").
22
23-define(PDU, <<30,16,0,90,0,1,0,0,255,255,255,255,81,67,101,7,0,0,0,96,
24	       6,12,146,18,14,0,15,252,16,0,0,17,0,0,128,0,2,241,33,131,
25	       0,20,7,97,112,110,48,49,51,97,8,101,114,105,99,115,115,
26	       111,110,2,115,101,132,0,20,128,192,35,16,1,5,0,16,5,117,
27	       115,101,114,53,5,112,97,115,115,53,133,0,4,172,28,12,1,
28	       133,0,4,172,28,12,3,134,0,8,145,148,113,129,0,0,0,0>>).
29
30-define(RES, {ok, {mvsgT_imsi, <<81,67,101,7,0,0,0,240>>}}).
31
32test() ->
33  ?RES = extract_v0_opt(1000, ?PDU),
34  ok.
35
36extract_v0_opt(0, Pdu) ->
37  get_external_id(Pdu);
38extract_v0_opt(N, Pdu) ->
39  {ok,_} = get_external_id(Pdu),
40  extract_v0_opt(N-1, Pdu).
41
42get_external_id(<<0:3,_:4,0:1,1:8,_Length:16,SequenceNumber:16,
43		 _FlowLabel:16,_SNDCP_N_PDU_Number:8,_:3/binary-unit:8,
44		 _TID:8/binary-unit:8,_InformationElements/binary>>) ->
45  {echo,#sesT_echoReqV0{},SequenceNumber};
46%% Create PDP Context Request
47%% GTP97, SNN=0
48%% (No SNDCP N-PDU number)
49get_external_id(<<0:3,_:4,0:1,16:8,_Length:16,_SequenceNumber:16,
50		 _FlowLabel:16,_SNDCP_N_PDU_Number:8,_:3/binary-unit:8,
51		 TID:8/binary-unit:8,_InformationElements/binary>>) ->
52  {ok,_IMSI} = extract_imsi(TID);
53%%% Update PDP Context Request
54%%% GTP97, SNN=0
55%%% (No SNDCP N-PDU number)
56get_external_id(<<0:3,_:4,0:1,18:8,_Length:16,_SequenceNumber:16,
57		 _FlowLabel:16,_SNDCP_N_PDU_Number:8,_:3/binary-unit:8,
58		 TID:8/binary-unit:8,_InformationElements/binary>>) ->
59  {ok,_IMSI} = extract_imsi(TID);
60%%% Delete PDP Context Request
61%%% GTP97, SNN=0
62%%% (No SNDCP N-PDU number)
63get_external_id(<<0:3,_:4,0:1,20:8,_Length:16,_SequenceNumber:16,
64		 _FlowLabel:16,_SNDCP_N_PDU_Number:8,_:3/binary-unit:8,
65		 TID:8/binary-unit:8,_InformationElements/binary>>) ->
66  {ok,_IMSI} = extract_imsi(TID);
67%%% Error handling: GTP Message Too Short
68%%% Error handling: Unknown GTP Signalling message.
69%%% Error handling: Unexpected GTP Signalling message.
70get_external_id(_GTP_Message) ->
71  fault.
72
73%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
74%% extract_imsi/1
75%% Get the IMSI element from TID
76extract_imsi(TID) ->
77  {ok,#mvsgT_tid{imsi=IMSI}} = tid_internal_storage(TID,[]),
78  {ok,IMSI}.
79
80%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
81%%% tid_internal_storage/3
82%%% Convert TID binary to internal datatype
83tid_internal_storage(Bin,_) ->
84  Size = byte_size(Bin) - 1,
85  <<Front:Size/binary,NSAPI:4,DigitN:4>> = Bin,
86  Result =
87    case DigitN of
88      2#1111 ->
89	#mvsgT_tid{imsi = #mvsgT_imsi{value=Front}, nsapi = NSAPI};
90      _ ->
91	Value = <<Front/binary,2#1111:4,DigitN:4>>,
92	#mvsgT_tid{imsi = #mvsgT_imsi{value = Value}, nsapi = NSAPI}
93    end,
94  {ok,Result}.
95