blob: 1bb2bb24561ef4e2732711c0b26290d7a82c9c17 [file] [log] [blame]
Harald Weltec676c682017-12-24 20:38:20 +01001module IuUP_Emulation {
2
Harald Welte35bb7162018-01-03 21:07:52 +01003/* IuUP emulation, uses the encoding/decoding from IuUP_Types.
4 *
5 * rather than running in a separate component with related primitives,
6 * we just implement a set of functions and data types which can be used
7 * by other code (such as an RTP endpoint) to implement IuUP support.
8 *
9 * (C) 2017 by Harald Welte <laforge@gnumonks.org>
10 * All rights reserved.
11 *
12 * Released under the terms of GNU General Public License, Version 2 or
13 * (at your option) any later version.
Harald Welte34b5a952019-05-27 11:54:11 +020014 *
15 * SPDX-License-Identifier: GPL-2.0-or-later
Harald Welte35bb7162018-01-03 21:07:52 +010016 */
17
Harald Weltec676c682017-12-24 20:38:20 +010018import from Osmocom_Types all;
19import from IuUP_Types all;
20
21
22type record IuUP_RabFlowCombination {
23 IuUP_RFCI rfci,
24 /* number of bits per sub-flow */
25 RecOfU8 sub_flow_bits,
26 /* IPTI value in number of ITIs for the corresponding RFCI */
27 uint8_t ipti
28};
29
30template (value) IuUP_RabFlowCombination t_IuUP_RFC(IuUP_RFCI rfci, RecOfU8 subflow_bits, uint8_t ipti) := {
31 rfci := rfci,
32 sub_flow_bits := subflow_bits,
33 ipti := ipti
34}
35
36template (value) IuUP_RabFlowCombination t_IuUP_RFC_AMR_12_2(IuUP_RFCI rfci) := t_IuUP_RFC(rfci, {81, 103, 60}, 1);
37template (value) IuUP_RabFlowCombination t_IuUP_RFC_AMR_SID(IuUP_RFCI rfci) := t_IuUP_RFC(rfci, {34, 0, 0}, 7);
Pau Espin Pedrol52ee5182022-05-25 17:34:44 +020038template (value) IuUP_RabFlowCombination t_IuUP_RFC_AMR_NO_DATA(IuUP_RFCI rfci) := t_IuUP_RFC(rfci, {0, 0, 0}, 1);
Harald Weltec676c682017-12-24 20:38:20 +010039
40type record IuUP_Config {
41 /* actively send INIT (true) or only passively respond (false) */
42 boolean active_init,
43 boolean data_pdu_type_0,
44 /* RAB Flow Combinations */
45 record of IuUP_RabFlowCombination rab_flow_combs
46};
47
48type enumerated IuUP_Em_State {
49 ST_INIT,
50 ST_DATA_TRANSFER_READY
51};
52
53
54
55type record IuUP_Entity {
56 IuUP_Config cfg,
57 IuUP_Em_State state,
58 IuUP_FrameNr tx_next_frame_nr,
59 IuUP_FrameNr rx_last_frame_nr optional,
60 IuUP_PDU pending_tx_pdu optional
61};
62
63template (value) IuUP_Entity t_IuUP_Entity(boolean act_init) := {
64 cfg := {
65 active_init := act_init,
66 data_pdu_type_0 := true,
Pau Espin Pedrol52ee5182022-05-25 17:34:44 +020067 rab_flow_combs := { t_IuUP_RFC_AMR_12_2(0), t_IuUP_RFC_AMR_SID(1), t_IuUP_RFC_AMR_NO_DATA(2) }
Harald Weltec676c682017-12-24 20:38:20 +010068 },
69 state := ST_INIT,
70 tx_next_frame_nr := 0,
71 rx_last_frame_nr := omit,
72 pending_tx_pdu := omit
73}
74
75
76function f_IuUP_Em_rx_decaps(inout IuUP_Entity st, octetstring inp) return octetstring {
77 var IuUP_PDU pdu := dec_IuUP_PDU(inp);
78 if (ischosen(pdu.type_0)) {
79 if (st.cfg.data_pdu_type_0) {
80 /* FIXME: check header / CRC */
81 st.rx_last_frame_nr := pdu.type_0.frame_nr;
82 return pdu.type_0.payload;
83 } else {
84 setverdict(fail, "PDU Type 0 received but 1 configured");
Daniel Willmanne4ff5372018-07-05 17:35:03 +020085 mtc.stop;
Harald Weltec676c682017-12-24 20:38:20 +010086 }
87 } else if (ischosen(pdu.type_1)) {
88 if (st.cfg.data_pdu_type_0 == false) {
89 /* FIXME: check header / CRC */
90 st.rx_last_frame_nr := pdu.type_1.frame_nr;
91 return pdu.type_1.payload;
92 } else {
93 setverdict(fail, "PDU Type 1 received but 0 configured");
Daniel Willmanne4ff5372018-07-05 17:35:03 +020094 mtc.stop;
Harald Weltec676c682017-12-24 20:38:20 +010095 }
96 } else if (ischosen(pdu.type_14)) {
97 if (match(pdu, tr_IuUP_INIT)) {
98 if (st.cfg.active_init == true) {
99 setverdict(fail, "INIT received in ACTIVE role");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200100 mtc.stop;
Harald Weltec676c682017-12-24 20:38:20 +0100101 } else {
102 /* store an INIT_ACK to be transmitted later */
103 st.pending_tx_pdu := valueof(ts_IuUP_INIT_ACK(pdu.type_14.frame_nr,
Pau Espin Pedrol5b4f2c62022-05-25 17:07:17 +0200104 pdu.type_14.u.proc.hdr.iuup_version));
Harald Weltec676c682017-12-24 20:38:20 +0100105 }
106 } else if (match(pdu, tr_IuUP_INIT_ACK)) {
107 if (st.cfg.active_init == true) {
108 log("IuUP INIT_ACK Received");
Pau Espin Pedrolb204a4e2021-12-24 14:18:39 +0100109 st.pending_tx_pdu := omit; /* Drop pending Init retrans */
Harald Weltec676c682017-12-24 20:38:20 +0100110 st.state := ST_DATA_TRANSFER_READY;
111 } else {
112 setverdict(fail, "INIT_ACK received in PASSIVE role");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200113 mtc.stop;
Harald Weltec676c682017-12-24 20:38:20 +0100114 }
115 }
116 return ''O;
117 } else {
118 setverdict(fail, "Impossible IuUP PDU decoded from ", inp);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200119 mtc.stop;
Harald Weltec676c682017-12-24 20:38:20 +0100120 }
121 self.stop;
122}
123
Pau Espin Pedrol52ee5182022-05-25 17:34:44 +0200124private function f_ts_IuUP_INIT(inout IuUP_Entity st) return IuUP_PDU
125{
126 var IuUP_PDU pdu;
127 var uint4_t data_pdu_type;
128 var template (omit) IuUP_InitRfci rfci := omit;
129 var IuUP_IPTI_List IPTIs := {};
130 var uint4_t num_rfci := lengthof(st.cfg.rab_flow_combs);
131
132 if (st.cfg.data_pdu_type_0 == true) {
133 data_pdu_type := 0;
134 } else {
135 data_pdu_type := 1;
136 }
137
138 /* Build RFCI list: */
139 for (var integer remain := num_rfci; remain > 0; remain := remain - 1) {
140 var IuUP_RabFlowCombination comb := st.cfg.rab_flow_combs[remain - 1];
141 var boolean lri := false;
142 if (remain == num_rfci) {
143 lri := true;
144 }
145 rfci := ts_IuUP_InitRfci(lri, false, comb.rfci, comb.sub_flow_bits, omit, rfci)
146 }
147
148 /* Build IPTI list: */
149 for (var integer i := 0; i < num_rfci; i := i + 1) {
150 IPTIs := IPTIs & { st.cfg.rab_flow_combs[i].ipti };
151 }
152
153 template (value) IuUP_PDU14_ProcSending_INIT tpl := ts_IuUP_PDU14_ProcSending_INIT(
154 ti := true,
155 subflows_per_rfci := num_rfci,
156 chain_ind := false,
157 rfci := rfci,
158 IPTIs := IPTIs,
159 versions_supported := '0000000000000001'B,
160 data_pdu_type := data_pdu_type
161 );
162 pdu := valueof(ts_IuUP_INIT(tpl));
163 return pdu;
164}
165
Harald Weltec676c682017-12-24 20:38:20 +0100166function f_IuUP_Em_tx_encap(inout IuUP_Entity st, in octetstring payload) return octetstring {
167 var IuUP_PDU pdu;
168 select (st.state) {
169 case (ST_INIT) {
170 if (st.cfg.active_init) {
Pau Espin Pedrolb204a4e2021-12-24 14:18:39 +0100171 if (not isvalue(st.pending_tx_pdu)) {
172 /* send INIT */
Pau Espin Pedrol52ee5182022-05-25 17:34:44 +0200173 pdu := f_ts_IuUP_INIT(st);
Pau Espin Pedrolb204a4e2021-12-24 14:18:39 +0100174 st.pending_tx_pdu := pdu;
175 } /* else: wait for INIT-ACK return ''O at the end */
176
Harald Weltec676c682017-12-24 20:38:20 +0100177 } else {
178 /* wait for INIT */
179 if (isvalue(st.pending_tx_pdu)) {
180 /* we're waiting to transmit the INIT_ACK in response to an
181 * init (passive) */
182 pdu := st.pending_tx_pdu;
183 st.pending_tx_pdu := omit;
184 st.state := ST_DATA_TRANSFER_READY;
185 }
186 }
187 }
188 case (ST_DATA_TRANSFER_READY) {
189 if (st.cfg.data_pdu_type_0) {
190 pdu := valueof(ts_IuUP_Type0(st.tx_next_frame_nr, 0, payload));
191 } else {
192 pdu := valueof(ts_IuUP_Type1(st.tx_next_frame_nr, 0, payload));
193 }
Pau Espin Pedrol64fd02b2021-12-21 18:19:42 +0100194 st.tx_next_frame_nr := (st.tx_next_frame_nr + 1) mod 16;
Harald Weltec676c682017-12-24 20:38:20 +0100195 }
196 }
197 if (isvalue(pdu)) {
198 return f_enc_IuUP_PDU(pdu);
199 } else {
200 return ''O;
201 }
202}
203
204
205}