blob: 0119863e08bad5ef4f6a971960b9118b4d7da669 [file] [log] [blame]
Harald Welte474fd7d2017-12-29 16:01:39 +01001#include "mncc.h"
2#include "MNCC_Types.hh"
3
4#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
5
6namespace MNCC__Types {
7
Pau Espin Pedrol563b3d02020-09-09 20:19:52 +02008static int mncc_sock_version = MNCC_SOCK_VERSION;
9
10BOOLEAN set__MNCC__version(INTEGER const& version)
11{
Vadim Yanitskiy9ff47802021-10-28 14:55:58 +030012 if (version != 7 && version != 8)
Pau Espin Pedrol563b3d02020-09-09 20:19:52 +020013 return false;
14 mncc_sock_version = version;
15 return true;
16}
17
Harald Welte474fd7d2017-12-29 16:01:39 +010018static void enc_bcap(struct gsm_mncc_bearer_cap *out, const MNCC__bearer__cap& in)
19{
20 out->transfer = in.transfer();
21 out->mode = in.mode();
22 out->coding = in.coding();
23 out->radio = in.radio();
24 out->speech_ctm = in.speech__ctm();
25
26 for (int i = 0; i < in.speech__ver().lengthof(); i++)
27 out->speech_ver[i] = in.speech__ver()[i];
28
29 if (in.data().is_value()) {
30 MNCC__bearer__cap__data data = in.data();
31 out->data.rate_adaption = (gsm48_bcap_ra) (int) data.rate__adaptation();
32 out->data.sig_access = (gsm48_bcap_sig_access) (int) data.sig__access();
33 out->data.async = data.async();
34 out->data.nr_stop_bits = data.nr__stop__bits();
35 out->data.nr_data_bits = data.nr__data__bits();
36 out->data.user_rate = (gsm48_bcap_user_rate) (int) data.user__rate();
37 out->data.parity = (gsm48_bcap_parity) (int) data.parity();
38 out->data.interm_rate = (gsm48_bcap_interm_rate) (int) data.interm__rate();
39 out->data.transp = (gsm48_bcap_transp) (int) data.transp();
40 out->data.modem_type = (gsm48_bcap_modem_type) (int) data.modem__type();
41 }
42
43}
44
45static MNCC__bearer__cap dec_bcap(const struct gsm_mncc_bearer_cap *in)
46{
47 MNCC__bearer__cap__data data;
48 MNCC__speech__vers vers;
49 data = MNCC__bearer__cap__data((GSM48__bcap__ra) in->data.rate_adaption,
50 (GSM48__bcap__sig__access) in->data.sig_access,
51 in->data.async,
52 in->data.nr_stop_bits,
53 in->data.nr_data_bits,
54 (GSM48__bcap__user__rate) in->data.user_rate,
55 (GSM48__bcap__parity) in->data.parity,
56 (GSM48__bcap__interm__rate) in->data.interm_rate,
57 (GSM48__bcap__transp) in->data.transp,
58 (GSM48__bcap__modem__type) in->data.modem_type);
59
Harald Welte05566002018-03-26 20:52:45 +020060 for (unsigned int i = 0; i < ARRAY_SIZE(in->speech_ver); i++) {
61 vers[i] = in->speech_ver[i];
62 if (vers[i] == -1)
63 break;
64 }
Harald Welte474fd7d2017-12-29 16:01:39 +010065
66 return MNCC__bearer__cap(in->transfer, in->mode, in->coding, in->radio, in->speech_ctm,
67 vers, data);
68}
69
70
71static void enc_number(struct gsm_mncc_number *num, const MNCC__number& in)
72{
73 num->type = in.number__type();
74 num->plan = in.plan();
75 num->present = in.presence();
76 num->screen = in.screen();
77 strncpy(num->number, in.number(), sizeof(num->number));
78}
79
80static MNCC__number dec_number(const struct gsm_mncc_number *num)
81{
82 return MNCC__number(num->type, num->plan,num->present, num->screen, num->number);
83}
84
85OCTETSTRING enc__MNCC__PDU(const MNCC__PDU& in)
86{
Harald Welte474fd7d2017-12-29 16:01:39 +010087 struct gsm_mncc mncc;
88 OCTETSTRING ret_val;
Pau Espin Pedrol563b3d02020-09-09 20:19:52 +020089 TTCN_Buffer ttcn_buffer;
Harald Welte474fd7d2017-12-29 16:01:39 +010090
91 memset(&mncc, 0, sizeof(mncc));
92 mncc.msg_type = in.msg__type();
93
Harald Welte1823cb12018-02-11 11:39:29 +010094 switch (in.u().get_selection()) {
95 case MNCC__MsgUnion::ALT_signal: {
96 const MNCC__PDU__Signal& in_sig = in.u().signal();
Harald Welte474fd7d2017-12-29 16:01:39 +010097 mncc.callref = in_sig.callref();
98 if (in_sig.bearer__cap().is_value()) {
99 enc_bcap(&mncc.bearer_cap, in_sig.bearer__cap());
100 mncc.fields |= MNCC_F_BEARER_CAP;
101 }
102 if (in_sig.called().is_value()) {
103 enc_number(&mncc.called, in_sig.called());
104 mncc.fields |= MNCC_F_CALLED;
105 }
106 if (in_sig.calling().is_value()) {
107 enc_number(&mncc.calling, in_sig.calling());
108 mncc.fields |= MNCC_F_CALLING;
109 }
110 if (in_sig.redirecting().is_value()) {
111 enc_number(&mncc.redirecting, in_sig.redirecting());
112 mncc.fields |= MNCC_F_REDIRECTING;
113 }
114 if (in_sig.connected().is_value()) {
115 enc_number(&mncc.connected, in_sig.connected());
116 mncc.fields |= MNCC_F_CONNECTED;
117 }
118 if (in_sig.cause().is_value()) {
119 const MNCC__cause &cause = in_sig.cause();
120 TTCN_Buffer ttcn_buffer(cause.diag());
121 mncc.cause.location = cause.location();
122 mncc.cause.coding = cause.coding();
123 mncc.cause.rec = cause.rec();
124 mncc.cause.rec_val = cause.rec__val();
125 mncc.cause.value = cause.val();
126 mncc.cause.diag_len = ttcn_buffer.get_len();
127 if (mncc.cause.diag_len > (int) sizeof(mncc.cause.diag)) {
128 TTCN_error("MNCC diagnostics length %u too long", mncc.cause.diag_len);
129 mncc.cause.diag_len = sizeof(mncc.cause.diag);
130 }
131 memcpy(mncc.cause.diag, ttcn_buffer.get_data(), ttcn_buffer.get_len());
132 mncc.fields |= MNCC_F_CAUSE;
133 }
134 if (in_sig.progress().is_value()) {
135 const MNCC__progress &progress = in_sig.progress();
136 mncc.progress.coding = progress.coding();
137 mncc.progress.location = progress.location();
138 mncc.progress.descr = progress.descr();
139 mncc.fields |= MNCC_F_PROGRESS;
140 }
141 if (in_sig.useruser().is_value()) {
142 const MNCC__useruser &useruser = in_sig.useruser();
143 mncc.useruser.proto = useruser.proto();
144 strncpy(mncc.useruser.info, useruser.info(), sizeof(mncc.useruser.info));
145 mncc.fields |= MNCC_F_USERUSER;
146 }
147 if (in_sig.facility().is_value()) {
148 const CHARSTRING &fac = in_sig.facility();
149 strncpy(mncc.facility.info, fac, sizeof(mncc.facility.info));
150 mncc.facility.len = strlen(mncc.facility.info);
151 mncc.fields |= MNCC_F_FACILITY;
152 }
153 if (in_sig.cccap().is_value()) {
154 const MNCC__cccap &cccap = in_sig.cccap();
155 mncc.cccap.dtmf = cccap.dtmf();
156 mncc.cccap.pcp = cccap.pcp();
157 mncc.fields |= MNCC_F_CCCAP;
158 }
159 if (in_sig.ssversion().is_value()) {
160 const CHARSTRING &ssv = in_sig.ssversion();
161 strncpy(mncc.ssversion.info, ssv, sizeof(mncc.ssversion.info));
162 mncc.ssversion.len = strlen(mncc.ssversion.info);
163 mncc.fields |= MNCC_F_SSVERSION;
164 }
165 mncc.clir.sup = in_sig.clir__sup();
166 mncc.clir.inv = in_sig.clir__inv();
167 if (in_sig.signal().is_value()) {
168 const INTEGER &sig = in_sig.signal();
169 mncc.signal = sig;
170 mncc.fields |= MNCC_F_SIGNAL;
171 }
172 if (in_sig.keypad().is_value()) {
Harald Welted13700d2018-02-02 20:06:52 +0100173 const CHARSTRING &kpd = in_sig.keypad();
174 mncc.signal = (int) kpd[0].get_char();
Harald Welte474fd7d2017-12-29 16:01:39 +0100175 mncc.fields |= MNCC_F_KEYPAD;
176 }
177 mncc.more = in_sig.more();
178 mncc.notify = in_sig.notify();
179 if (in_sig.emergency().is_value()) {
180 const INTEGER &emerg = in_sig.emergency();
181 mncc.emergency = emerg;
182 mncc.fields |= MNCC_F_EMERGENCY;
183 }
184 strncpy(mncc.imsi, in_sig.imsi(), sizeof(mncc.imsi));
185 mncc.lchan_type = in_sig.lchan__type();
186 mncc.lchan_mode = in_sig.lchan__mode();
Vadim Yanitskiy9ff47802021-10-28 14:55:58 +0300187 if (in_sig.gcr().is_value()) {
188 const OCTETSTRING &gcr = in_sig.gcr();
189 if (mncc_sock_version < 8)
190 TTCN_error("GCR is only available since MNCCv8");
191 memcpy(&mncc.v8.gcr[0], gcr, sizeof(mncc.v8.gcr));
192 mncc.fields |= MNCC_F_GCR;
193 }
Vadim Yanitskiyd3760632021-10-28 14:41:41 +0300194 if (in_sig.sdp().is_value()) {
195 const CHARSTRING &sdp = in_sig.sdp();
Vadim Yanitskiy9ff47802021-10-28 14:55:58 +0300196 if (mncc_sock_version > 7)
197 strncpy(&mncc.v8.sdp[0], sdp, sizeof(mncc.v8.sdp));
198 else
199 strncpy(&mncc.v7.sdp[0], sdp, sizeof(mncc.v7.sdp));
Vadim Yanitskiyd3760632021-10-28 14:41:41 +0300200 }
Harald Welte474fd7d2017-12-29 16:01:39 +0100201 ret_val = OCTETSTRING(sizeof(mncc), (uint8_t *)&mncc);
Harald Welte1823cb12018-02-11 11:39:29 +0100202 }
203 break;
204 case MNCC__MsgUnion::ALT_data:
Harald Welte474fd7d2017-12-29 16:01:39 +0100205 struct gsm_data_frame data;
206 memset(&data, 0, sizeof(data));
207 data.msg_type = in.msg__type();
208 ret_val = OCTETSTRING(sizeof(data), (uint8_t *)&data);
209 ret_val = ret_val & in.u().data().data();
Harald Welte1823cb12018-02-11 11:39:29 +0100210 break;
211 case MNCC__MsgUnion::ALT_rtp:
Vadim Yanitskiyaff226f2021-10-27 14:34:08 +0300212 struct gsm_mncc_rtp rtp;
213 memset(&rtp, 0, sizeof(rtp));
214 rtp.msg_type = in.msg__type();
215 rtp.callref = in.u().rtp().callref();
216 ttcn_buffer.put_string(in.u().rtp().ip());
217 if (in.u().rtp().is__ipv6()) {
218 // if(in.u().rtp().ip().lengthof() != 16) print error
219 rtp.addr.ss_family = AF_INET6;
220 memcpy(&((struct sockaddr_in6*)&rtp.addr)->sin6_addr, ttcn_buffer.get_data(),
221 sizeof(struct in6_addr));
222 ((struct sockaddr_in6*)&rtp.addr)->sin6_port = htons(in.u().rtp().rtp__port());
223 } else {
224 // if(in.u().rtp().ip().lengthof() != 4) print error
225 rtp.addr.ss_family = AF_INET;
226 memcpy(&((struct sockaddr_in*)&rtp.addr)->sin_addr, ttcn_buffer.get_data(),
227 sizeof(struct in_addr));
228 ((struct sockaddr_in*)&rtp.addr)->sin_port = htons(in.u().rtp().rtp__port());
Pau Espin Pedrol563b3d02020-09-09 20:19:52 +0200229 }
Vadim Yanitskiyaff226f2021-10-27 14:34:08 +0300230 rtp.payload_type = in.u().rtp().payload__type();
231 rtp.payload_msg_type = in.u().rtp().payload__msg__type();
Neels Hofmeyr932f6132023-09-07 05:08:09 +0200232 if (in.u().rtp().sdp().is_value()) {
233 const CHARSTRING &sdp = in.u().rtp().sdp();
234 strncpy(rtp.sdp, sdp, sizeof(rtp.sdp));
235 }
Vadim Yanitskiyaff226f2021-10-27 14:34:08 +0300236 ret_val = OCTETSTRING(sizeof(rtp), (uint8_t *) &rtp);
Harald Welte1823cb12018-02-11 11:39:29 +0100237 break;
238 case MNCC__MsgUnion::ALT_hello:
Harald Welte474fd7d2017-12-29 16:01:39 +0100239 struct gsm_mncc_hello hello;
240 memset(&hello, 0, sizeof(hello));
241 hello.msg_type = in.msg__type();
242 hello.version = in.u().hello().version();
243 hello.mncc_size = in.u().hello().mncc__size();
244 hello.data_frame_size = in.u().hello().data__frame__size();
245 hello.called_offset = in.u().hello().called__offset();
246 hello.signal_offset = in.u().hello().signal__offset();
247 hello.emergency_offset = in.u().hello().emergency__offset();
248 hello.lchan_type_offset = in.u().hello().lchan__type__offset();
249 ret_val = OCTETSTRING(sizeof(hello), (uint8_t *) &hello);
Harald Welte1823cb12018-02-11 11:39:29 +0100250 break;
Harald Welte474fd7d2017-12-29 16:01:39 +0100251 }
252
253 return ret_val;
254}
255
256MNCC__PDU dec__MNCC__PDU(const OCTETSTRING& in)
257{
258 TTCN_Buffer ttcn_buffer(in);
259 const struct gsm_mncc *in_mncc;
260 MNCC__PDU__Signal sign;
261 const struct gsm_mncc_hello *in_hello;
262 MNCC__PDU__Hello hello;
263 const struct gsm_data_frame *in_data;
264 MNCC__PDU__Data data;
265 const struct gsm_mncc_rtp *in_rtp;
266 MNCC__PDU__Rtp rtp;
267 MNCC__MsgUnion u;
Pau Espin Pedrol563b3d02020-09-09 20:19:52 +0200268 bool is_ipv6;
269 OCTETSTRING ip;
270 uint16_t port;
Harald Welte474fd7d2017-12-29 16:01:39 +0100271
272 in_mncc = (struct gsm_mncc *) ttcn_buffer.get_read_data();
273
Harald Welte8a10e862018-01-17 13:58:26 +0100274 sign.set_implicit_omit();
275 hello.set_implicit_omit();
276 data.set_implicit_omit();
277 rtp.set_implicit_omit();
278
Harald Welte474fd7d2017-12-29 16:01:39 +0100279 switch (in_mncc->msg_type) {
280 case MNCC_SOCKET_HELLO:
281 in_hello = (const struct gsm_mncc_hello *) in_mncc;
282 hello = MNCC__PDU__Hello(in_hello->version,
283 in_hello->mncc_size,
284 in_hello->data_frame_size,
285 in_hello->called_offset,
286 in_hello->signal_offset,
287 in_hello->emergency_offset,
288 in_hello->lchan_type_offset);
289 u.hello() = hello;
290 break;
291 case GSM_TCHF_FRAME:
292 case GSM_TCHF_FRAME_EFR:
293 case GSM_TCHH_FRAME:
294 case GSM_TCH_FRAME_AMR:
295 case GSM_BAD_FRAME:
296 in_data = (const struct gsm_data_frame *) in_mncc;
297 u.data() = MNCC__PDU__Data(in_data->callref,
298 substr(in, offsetof(struct gsm_data_frame, data),
299 in.lengthof() - offsetof(struct gsm_data_frame, data)));
300 break;
301 case MNCC_RTP_CREATE:
302 case MNCC_RTP_CONNECT:
303 case MNCC_RTP_FREE:
Vadim Yanitskiyaff226f2021-10-27 14:34:08 +0300304 in_rtp = (const struct gsm_mncc_rtp *) in_mncc;
305 switch (in_rtp->addr.ss_family) {
306 case AF_INET6:
307 is_ipv6 = true;
308 port = ntohs(((struct sockaddr_in6*)&in_rtp->addr)->sin6_port);
309 ip = OCTETSTRING(sizeof(struct in6_addr),
310 (const unsigned char*)&((struct sockaddr_in6*)&in_rtp->addr)->sin6_addr);
Pau Espin Pedrol563b3d02020-09-09 20:19:52 +0200311
312 break;
Vadim Yanitskiyaff226f2021-10-27 14:34:08 +0300313 case AF_UNSPEC: //RTP_CREATE and RTP_FREE can contain fully zeroed addr
314 case AF_INET:
315 is_ipv6 = false;
316 port = ntohs(((struct sockaddr_in*)&in_rtp->addr)->sin_port);
317 ip = OCTETSTRING(sizeof(struct in_addr),
318 (const unsigned char*)&((struct sockaddr_in*)&in_rtp->addr)->sin_addr);
Pau Espin Pedrol563b3d02020-09-09 20:19:52 +0200319 break;
320 }
Vadim Yanitskiyaff226f2021-10-27 14:34:08 +0300321 rtp = MNCC__PDU__Rtp(in_rtp->callref, is_ipv6, ip, port, in_rtp->payload_type,
322 in_rtp->payload_msg_type, in_rtp->sdp);
323 u.rtp() = rtp;
Harald Welte474fd7d2017-12-29 16:01:39 +0100324 break;
325 default:
326 sign.callref() = in_mncc->callref;
327 if (in_mncc->fields & MNCC_F_BEARER_CAP) {
328 sign.bearer__cap() = dec_bcap(&in_mncc->bearer_cap);
329 }
330 if (in_mncc->fields & MNCC_F_CALLED)
331 sign.called() = dec_number(&in_mncc->called);
332 if (in_mncc->fields & MNCC_F_CALLING)
333 sign.calling() = dec_number(&in_mncc->calling);
334 if (in_mncc->fields & MNCC_F_REDIRECTING)
335 sign.redirecting() = dec_number(&in_mncc->redirecting);
336 if (in_mncc->fields & MNCC_F_CONNECTED)
337 sign.connected() = dec_number(&in_mncc->connected);
338 if (in_mncc->fields & MNCC_F_CAUSE) {
339 sign.cause() = MNCC__cause(in_mncc->cause.location,
340 in_mncc->cause.coding,
341 in_mncc->cause.rec,
342 in_mncc->cause.rec_val,
343 in_mncc->cause.value,
344 OCTETSTRING(in_mncc->cause.diag_len,
345 (const uint8_t *)in_mncc->cause.diag));
346 }
347 if (in_mncc->fields & MNCC_F_USERUSER) {
348 sign.useruser() = MNCC__useruser(in_mncc->useruser.proto,
349 CHARSTRING(in_mncc->useruser.info));
350 }
351 if (in_mncc->fields & MNCC_F_PROGRESS) {
352 sign.progress() = MNCC__progress(in_mncc->progress.coding,
353 in_mncc->progress.location,
354 in_mncc->progress.descr);
355 }
356 if (in_mncc->fields & MNCC_F_EMERGENCY)
357 sign.emergency() = in_mncc->emergency;
358 if (in_mncc->fields & MNCC_F_FACILITY)
359 sign.facility() = CHARSTRING(in_mncc->facility.info);
360 if (in_mncc->fields & MNCC_F_SSVERSION)
361 sign.ssversion() = CHARSTRING(in_mncc->ssversion.info);
362 if (in_mncc->fields & MNCC_F_CCCAP)
363 sign.cccap() = MNCC__cccap(in_mncc->cccap.dtmf, in_mncc->cccap.pcp);
Harald Welted13700d2018-02-02 20:06:52 +0100364 if (in_mncc->fields & MNCC_F_KEYPAD) {
365 char kpd[2] = { (char) in_mncc->keypad, 0 };
366 sign.keypad() = CHARSTRING(kpd);
367 }
Harald Welte474fd7d2017-12-29 16:01:39 +0100368 if (in_mncc->fields & MNCC_F_SIGNAL)
369 sign.signal() = in_mncc->signal;
370
371 sign.clir__sup() = in_mncc->clir.sup;
372 sign.clir__inv() = in_mncc->clir.inv;
373 sign.more() = in_mncc->more;
374 sign.notify() = in_mncc->notify;
375 sign.imsi() = CHARSTRING(in_mncc->imsi);
376 sign.lchan__type() = in_mncc->lchan_type;
377 sign.lchan__mode() = in_mncc->lchan_mode;
Vadim Yanitskiy9ff47802021-10-28 14:55:58 +0300378 if (mncc_sock_version > 7) {
379 if (in_mncc->fields & MNCC_F_GCR)
380 sign.gcr() = OCTETSTRING(sizeof(in_mncc->v8.gcr), in_mncc->v8.gcr);
381 sign.sdp() = in_mncc->v8.sdp;
382 } else {
383 sign.sdp() = in_mncc->v7.sdp;
384 }
Harald Welte474fd7d2017-12-29 16:01:39 +0100385 u.signal() = sign;
386 break;
387 }
388 return MNCC__PDU(in_mncc->msg_type, u);
389}
390
391}