blob: 752b8977b4dd083b4c745f7cb119d51dd8d0c875 [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.
14 */
15
16
Harald Weltec676c682017-12-24 20:38:20 +010017import from Osmocom_Types all;
18import from IuUP_Types all;
19
20
21type record IuUP_RabFlowCombination {
22 IuUP_RFCI rfci,
23 /* number of bits per sub-flow */
24 RecOfU8 sub_flow_bits,
25 /* IPTI value in number of ITIs for the corresponding RFCI */
26 uint8_t ipti
27};
28
29template (value) IuUP_RabFlowCombination t_IuUP_RFC(IuUP_RFCI rfci, RecOfU8 subflow_bits, uint8_t ipti) := {
30 rfci := rfci,
31 sub_flow_bits := subflow_bits,
32 ipti := ipti
33}
34
35template (value) IuUP_RabFlowCombination t_IuUP_RFC_AMR_12_2(IuUP_RFCI rfci) := t_IuUP_RFC(rfci, {81, 103, 60}, 1);
36template (value) IuUP_RabFlowCombination t_IuUP_RFC_AMR_SID(IuUP_RFCI rfci) := t_IuUP_RFC(rfci, {34, 0, 0}, 7);
37
38type record IuUP_Config {
39 /* actively send INIT (true) or only passively respond (false) */
40 boolean active_init,
41 boolean data_pdu_type_0,
42 /* RAB Flow Combinations */
43 record of IuUP_RabFlowCombination rab_flow_combs
44};
45
46type enumerated IuUP_Em_State {
47 ST_INIT,
48 ST_DATA_TRANSFER_READY
49};
50
51
52
53type record IuUP_Entity {
54 IuUP_Config cfg,
55 IuUP_Em_State state,
56 IuUP_FrameNr tx_next_frame_nr,
57 IuUP_FrameNr rx_last_frame_nr optional,
58 IuUP_PDU pending_tx_pdu optional
59};
60
61template (value) IuUP_Entity t_IuUP_Entity(boolean act_init) := {
62 cfg := {
63 active_init := act_init,
64 data_pdu_type_0 := true,
65 rab_flow_combs := { t_IuUP_RFC_AMR_12_2(0), t_IuUP_RFC_AMR_SID(1) }
66 },
67 state := ST_INIT,
68 tx_next_frame_nr := 0,
69 rx_last_frame_nr := omit,
70 pending_tx_pdu := omit
71}
72
73
74function f_IuUP_Em_rx_decaps(inout IuUP_Entity st, octetstring inp) return octetstring {
75 var IuUP_PDU pdu := dec_IuUP_PDU(inp);
76 if (ischosen(pdu.type_0)) {
77 if (st.cfg.data_pdu_type_0) {
78 /* FIXME: check header / CRC */
79 st.rx_last_frame_nr := pdu.type_0.frame_nr;
80 return pdu.type_0.payload;
81 } else {
82 setverdict(fail, "PDU Type 0 received but 1 configured");
Daniel Willmanne4ff5372018-07-05 17:35:03 +020083 mtc.stop;
Harald Weltec676c682017-12-24 20:38:20 +010084 }
85 } else if (ischosen(pdu.type_1)) {
86 if (st.cfg.data_pdu_type_0 == false) {
87 /* FIXME: check header / CRC */
88 st.rx_last_frame_nr := pdu.type_1.frame_nr;
89 return pdu.type_1.payload;
90 } else {
91 setverdict(fail, "PDU Type 1 received but 0 configured");
Daniel Willmanne4ff5372018-07-05 17:35:03 +020092 mtc.stop;
Harald Weltec676c682017-12-24 20:38:20 +010093 }
94 } else if (ischosen(pdu.type_14)) {
95 if (match(pdu, tr_IuUP_INIT)) {
96 if (st.cfg.active_init == true) {
97 setverdict(fail, "INIT received in ACTIVE role");
Daniel Willmanne4ff5372018-07-05 17:35:03 +020098 mtc.stop;
Harald Weltec676c682017-12-24 20:38:20 +010099 } else {
100 /* store an INIT_ACK to be transmitted later */
101 st.pending_tx_pdu := valueof(ts_IuUP_INIT_ACK(pdu.type_14.frame_nr,
102 pdu.type_14.iuup_version));
103 }
104 } else if (match(pdu, tr_IuUP_INIT_ACK)) {
105 if (st.cfg.active_init == true) {
106 log("IuUP INIT_ACK Received");
107 st.state := ST_DATA_TRANSFER_READY;
108 } else {
109 setverdict(fail, "INIT_ACK received in PASSIVE role");
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200110 mtc.stop;
Harald Weltec676c682017-12-24 20:38:20 +0100111 }
112 }
113 return ''O;
114 } else {
115 setverdict(fail, "Impossible IuUP PDU decoded from ", inp);
Daniel Willmanne4ff5372018-07-05 17:35:03 +0200116 mtc.stop;
Harald Weltec676c682017-12-24 20:38:20 +0100117 }
118 self.stop;
119}
120
121function f_IuUP_Em_tx_encap(inout IuUP_Entity st, in octetstring payload) return octetstring {
122 var IuUP_PDU pdu;
123 select (st.state) {
124 case (ST_INIT) {
125 if (st.cfg.active_init) {
126 /* send INIT */
127 pdu := valueof(ts_IuUP_INIT('160051673C01270000820000001710000100'O));
128 } else {
129 /* wait for INIT */
130 if (isvalue(st.pending_tx_pdu)) {
131 /* we're waiting to transmit the INIT_ACK in response to an
132 * init (passive) */
133 pdu := st.pending_tx_pdu;
134 st.pending_tx_pdu := omit;
135 st.state := ST_DATA_TRANSFER_READY;
136 }
137 }
138 }
139 case (ST_DATA_TRANSFER_READY) {
140 if (st.cfg.data_pdu_type_0) {
141 pdu := valueof(ts_IuUP_Type0(st.tx_next_frame_nr, 0, payload));
142 } else {
143 pdu := valueof(ts_IuUP_Type1(st.tx_next_frame_nr, 0, payload));
144 }
145 st.tx_next_frame_nr := st.tx_next_frame_nr + 1;
146 }
147 }
148 if (isvalue(pdu)) {
149 return f_enc_IuUP_PDU(pdu);
150 } else {
151 return ''O;
152 }
153}
154
155
156}