blob: 19c2c842a0e9d68462c95ec2ba88bbfc171188d8 [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);
38
39type record IuUP_Config {
40 /* actively send INIT (true) or only passively respond (false) */
41 boolean active_init,
42 boolean data_pdu_type_0,
43 /* RAB Flow Combinations */
44 record of IuUP_RabFlowCombination rab_flow_combs
45};
46
47type enumerated IuUP_Em_State {
48 ST_INIT,
49 ST_DATA_TRANSFER_READY
50};
51
52
53
54type record IuUP_Entity {
55 IuUP_Config cfg,
56 IuUP_Em_State state,
57 IuUP_FrameNr tx_next_frame_nr,
58 IuUP_FrameNr rx_last_frame_nr optional,
59 IuUP_PDU pending_tx_pdu optional
60};
61
62template (value) IuUP_Entity t_IuUP_Entity(boolean act_init) := {
63 cfg := {
64 active_init := act_init,
65 data_pdu_type_0 := true,
66 rab_flow_combs := { t_IuUP_RFC_AMR_12_2(0), t_IuUP_RFC_AMR_SID(1) }
67 },
68 state := ST_INIT,
69 tx_next_frame_nr := 0,
70 rx_last_frame_nr := omit,
71 pending_tx_pdu := omit
72}
73
74
75function f_IuUP_Em_rx_decaps(inout IuUP_Entity st, octetstring inp) return octetstring {
76 var IuUP_PDU pdu := dec_IuUP_PDU(inp);
77 if (ischosen(pdu.type_0)) {
78 if (st.cfg.data_pdu_type_0) {
79 /* FIXME: check header / CRC */
80 st.rx_last_frame_nr := pdu.type_0.frame_nr;
81 return pdu.type_0.payload;
82 } else {
83 setverdict(fail, "PDU Type 0 received but 1 configured");
Daniel Willmanne4ff5372018-07-05 17:35:03 +020084 mtc.stop;
Harald Weltec676c682017-12-24 20:38:20 +010085 }
86 } else if (ischosen(pdu.type_1)) {
87 if (st.cfg.data_pdu_type_0 == false) {
88 /* FIXME: check header / CRC */
89 st.rx_last_frame_nr := pdu.type_1.frame_nr;
90 return pdu.type_1.payload;
91 } else {
92 setverdict(fail, "PDU Type 1 received but 0 configured");
Daniel Willmanne4ff5372018-07-05 17:35:03 +020093 mtc.stop;
Harald Weltec676c682017-12-24 20:38:20 +010094 }
95 } else if (ischosen(pdu.type_14)) {
96 if (match(pdu, tr_IuUP_INIT)) {
97 if (st.cfg.active_init == true) {
98 setverdict(fail, "INIT received in ACTIVE role");
Daniel Willmanne4ff5372018-07-05 17:35:03 +020099 mtc.stop;
Harald Weltec676c682017-12-24 20:38:20 +0100100 } else {
101 /* store an INIT_ACK to be transmitted later */
102 st.pending_tx_pdu := valueof(ts_IuUP_INIT_ACK(pdu.type_14.frame_nr,
103 pdu.type_14.iuup_version));
104 }
105 } else if (match(pdu, tr_IuUP_INIT_ACK)) {
106 if (st.cfg.active_init == true) {
107 log("IuUP INIT_ACK Received");
Pau Espin Pedrolb204a4e2021-12-24 14:18:39 +0100108 st.pending_tx_pdu := omit; /* Drop pending Init retrans */
Harald Weltec676c682017-12-24 20:38:20 +0100109 st.state := ST_DATA_TRANSFER_READY;
110 } else {
111 setverdict(fail, "INIT_ACK received in PASSIVE role");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200112 mtc.stop;
Harald Weltec676c682017-12-24 20:38:20 +0100113 }
114 }
115 return ''O;
116 } else {
117 setverdict(fail, "Impossible IuUP PDU decoded from ", inp);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200118 mtc.stop;
Harald Weltec676c682017-12-24 20:38:20 +0100119 }
120 self.stop;
121}
122
123function f_IuUP_Em_tx_encap(inout IuUP_Entity st, in octetstring payload) return octetstring {
124 var IuUP_PDU pdu;
125 select (st.state) {
126 case (ST_INIT) {
127 if (st.cfg.active_init) {
Pau Espin Pedrolb204a4e2021-12-24 14:18:39 +0100128 if (not isvalue(st.pending_tx_pdu)) {
129 /* send INIT */
130 pdu := valueof(ts_IuUP_INIT('160051673C01270000820000001710000100'O));
131 st.pending_tx_pdu := pdu;
132 } /* else: wait for INIT-ACK return ''O at the end */
133
Harald Weltec676c682017-12-24 20:38:20 +0100134 } else {
135 /* wait for INIT */
136 if (isvalue(st.pending_tx_pdu)) {
137 /* we're waiting to transmit the INIT_ACK in response to an
138 * init (passive) */
139 pdu := st.pending_tx_pdu;
140 st.pending_tx_pdu := omit;
141 st.state := ST_DATA_TRANSFER_READY;
142 }
143 }
144 }
145 case (ST_DATA_TRANSFER_READY) {
146 if (st.cfg.data_pdu_type_0) {
147 pdu := valueof(ts_IuUP_Type0(st.tx_next_frame_nr, 0, payload));
148 } else {
149 pdu := valueof(ts_IuUP_Type1(st.tx_next_frame_nr, 0, payload));
150 }
Pau Espin Pedrol64fd02b2021-12-21 18:19:42 +0100151 st.tx_next_frame_nr := (st.tx_next_frame_nr + 1) mod 16;
Harald Weltec676c682017-12-24 20:38:20 +0100152 }
153 }
154 if (isvalue(pdu)) {
155 return f_enc_IuUP_PDU(pdu);
156 } else {
157 return ''O;
158 }
159}
160
161
162}