blob: ec25e49ee6be5e1f815ac1b2ecdff683852206ce [file] [log] [blame]
Harald Weltec676c682017-12-24 20:38:20 +01001module IuUP_Emulation {
2
3import from Osmocom_Types all;
4import from IuUP_Types all;
5
6
7type record IuUP_RabFlowCombination {
8 IuUP_RFCI rfci,
9 /* number of bits per sub-flow */
10 RecOfU8 sub_flow_bits,
11 /* IPTI value in number of ITIs for the corresponding RFCI */
12 uint8_t ipti
13};
14
15template (value) IuUP_RabFlowCombination t_IuUP_RFC(IuUP_RFCI rfci, RecOfU8 subflow_bits, uint8_t ipti) := {
16 rfci := rfci,
17 sub_flow_bits := subflow_bits,
18 ipti := ipti
19}
20
21template (value) IuUP_RabFlowCombination t_IuUP_RFC_AMR_12_2(IuUP_RFCI rfci) := t_IuUP_RFC(rfci, {81, 103, 60}, 1);
22template (value) IuUP_RabFlowCombination t_IuUP_RFC_AMR_SID(IuUP_RFCI rfci) := t_IuUP_RFC(rfci, {34, 0, 0}, 7);
23
24type record IuUP_Config {
25 /* actively send INIT (true) or only passively respond (false) */
26 boolean active_init,
27 boolean data_pdu_type_0,
28 /* RAB Flow Combinations */
29 record of IuUP_RabFlowCombination rab_flow_combs
30};
31
32type enumerated IuUP_Em_State {
33 ST_INIT,
34 ST_DATA_TRANSFER_READY
35};
36
37
38
39type record IuUP_Entity {
40 IuUP_Config cfg,
41 IuUP_Em_State state,
42 IuUP_FrameNr tx_next_frame_nr,
43 IuUP_FrameNr rx_last_frame_nr optional,
44 IuUP_PDU pending_tx_pdu optional
45};
46
47template (value) IuUP_Entity t_IuUP_Entity(boolean act_init) := {
48 cfg := {
49 active_init := act_init,
50 data_pdu_type_0 := true,
51 rab_flow_combs := { t_IuUP_RFC_AMR_12_2(0), t_IuUP_RFC_AMR_SID(1) }
52 },
53 state := ST_INIT,
54 tx_next_frame_nr := 0,
55 rx_last_frame_nr := omit,
56 pending_tx_pdu := omit
57}
58
59
60function f_IuUP_Em_rx_decaps(inout IuUP_Entity st, octetstring inp) return octetstring {
61 var IuUP_PDU pdu := dec_IuUP_PDU(inp);
62 if (ischosen(pdu.type_0)) {
63 if (st.cfg.data_pdu_type_0) {
64 /* FIXME: check header / CRC */
65 st.rx_last_frame_nr := pdu.type_0.frame_nr;
66 return pdu.type_0.payload;
67 } else {
68 setverdict(fail, "PDU Type 0 received but 1 configured");
69 }
70 } else if (ischosen(pdu.type_1)) {
71 if (st.cfg.data_pdu_type_0 == false) {
72 /* FIXME: check header / CRC */
73 st.rx_last_frame_nr := pdu.type_1.frame_nr;
74 return pdu.type_1.payload;
75 } else {
76 setverdict(fail, "PDU Type 1 received but 0 configured");
77 }
78 } else if (ischosen(pdu.type_14)) {
79 if (match(pdu, tr_IuUP_INIT)) {
80 if (st.cfg.active_init == true) {
81 setverdict(fail, "INIT received in ACTIVE role");
82 } else {
83 /* store an INIT_ACK to be transmitted later */
84 st.pending_tx_pdu := valueof(ts_IuUP_INIT_ACK(pdu.type_14.frame_nr,
85 pdu.type_14.iuup_version));
86 }
87 } else if (match(pdu, tr_IuUP_INIT_ACK)) {
88 if (st.cfg.active_init == true) {
89 log("IuUP INIT_ACK Received");
90 st.state := ST_DATA_TRANSFER_READY;
91 } else {
92 setverdict(fail, "INIT_ACK received in PASSIVE role");
93 }
94 }
95 return ''O;
96 } else {
97 setverdict(fail, "Impossible IuUP PDU decoded from ", inp);
98 }
99 self.stop;
100}
101
102function f_IuUP_Em_tx_encap(inout IuUP_Entity st, in octetstring payload) return octetstring {
103 var IuUP_PDU pdu;
104 select (st.state) {
105 case (ST_INIT) {
106 if (st.cfg.active_init) {
107 /* send INIT */
108 pdu := valueof(ts_IuUP_INIT('160051673C01270000820000001710000100'O));
109 } else {
110 /* wait for INIT */
111 if (isvalue(st.pending_tx_pdu)) {
112 /* we're waiting to transmit the INIT_ACK in response to an
113 * init (passive) */
114 pdu := st.pending_tx_pdu;
115 st.pending_tx_pdu := omit;
116 st.state := ST_DATA_TRANSFER_READY;
117 }
118 }
119 }
120 case (ST_DATA_TRANSFER_READY) {
121 if (st.cfg.data_pdu_type_0) {
122 pdu := valueof(ts_IuUP_Type0(st.tx_next_frame_nr, 0, payload));
123 } else {
124 pdu := valueof(ts_IuUP_Type1(st.tx_next_frame_nr, 0, payload));
125 }
126 st.tx_next_frame_nr := st.tx_next_frame_nr + 1;
127 }
128 }
129 if (isvalue(pdu)) {
130 return f_enc_IuUP_PDU(pdu);
131 } else {
132 return ''O;
133 }
134}
135
136
137}