blob: 3b4c41d95f4ddbdb2c993ee4ad3c61eb402f83bc [file] [log] [blame]
Harald Welte3e6376d2010-12-22 23:54:51 +01001/* mncc.c - utility routines for the MNCC API between the 04.08
2 * message parsing and the actual Call Control logic */
Harald Welte7ce5e252010-12-22 02:02:48 +01003
Harald Welte57184292018-01-22 01:49:02 +01004/* (C) 2008-2018 by Harald Welte <laforge@gnumonks.org>
Harald Welte4bfdfe72009-06-10 23:11:52 +08005 * (C) 2009 by Andreas Eversberg <Andreas.Eversberg@versatel.de>
6 * All Rights Reserved
7 *
8 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01009 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
Harald Welte4bfdfe72009-06-10 23:11:52 +080011 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * GNU Affero General Public License for more details.
Harald Welte4bfdfe72009-06-10 23:11:52 +080017 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010018 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Harald Welte4bfdfe72009-06-10 23:11:52 +080020 *
21 */
22
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
Harald Welte09b7e7f2009-12-12 21:36:53 +010027#include <errno.h>
Harald Welte4bfdfe72009-06-10 23:11:52 +080028
Harald Welteda8a19f2015-12-03 14:35:05 +010029#include <osmocom/core/talloc.h>
30#include <osmocom/core/utils.h>
31
Neels Hofmeyr90843962017-09-04 15:04:35 +020032#include <osmocom/msc/gsm_04_08.h>
33#include <osmocom/msc/debug.h>
34#include <osmocom/msc/mncc.h>
35#include <osmocom/msc/gsm_data.h>
36#include <osmocom/msc/transaction.h>
37#include <osmocom/msc/rtp_proxy.h>
Harald Welte2cf161b2009-06-20 22:36:41 +020038
Harald Welte4bfdfe72009-06-10 23:11:52 +080039
Harald Welteda8a19f2015-12-03 14:35:05 +010040static const struct value_string mncc_names[] = {
41 { MNCC_SETUP_REQ, "MNCC_SETUP_REQ" },
42 { MNCC_SETUP_IND, "MNCC_SETUP_IND" },
43 { MNCC_SETUP_RSP, "MNCC_SETUP_RSP" },
44 { MNCC_SETUP_CNF, "MNCC_SETUP_CNF" },
45 { MNCC_SETUP_COMPL_REQ, "MNCC_SETUP_COMPL_REQ" },
46 { MNCC_SETUP_COMPL_IND, "MNCC_SETUP_COMPL_IND" },
47 { MNCC_CALL_CONF_IND, "MNCC_CALL_CONF_IND" },
48 { MNCC_CALL_PROC_REQ, "MNCC_CALL_PROC_REQ" },
49 { MNCC_PROGRESS_REQ, "MNCC_PROGRESS_REQ" },
50 { MNCC_ALERT_REQ, "MNCC_ALERT_REQ" },
51 { MNCC_ALERT_IND, "MNCC_ALERT_IND" },
52 { MNCC_NOTIFY_REQ, "MNCC_NOTIFY_REQ" },
53 { MNCC_NOTIFY_IND, "MNCC_NOTIFY_IND" },
54 { MNCC_DISC_REQ, "MNCC_DISC_REQ" },
55 { MNCC_DISC_IND, "MNCC_DISC_IND" },
56 { MNCC_REL_REQ, "MNCC_REL_REQ" },
57 { MNCC_REL_IND, "MNCC_REL_IND" },
58 { MNCC_REL_CNF, "MNCC_REL_CNF" },
59 { MNCC_FACILITY_REQ, "MNCC_FACILITY_REQ" },
60 { MNCC_FACILITY_IND, "MNCC_FACILITY_IND" },
61 { MNCC_START_DTMF_IND, "MNCC_START_DTMF_IND" },
62 { MNCC_START_DTMF_RSP, "MNCC_START_DTMF_RSP" },
63 { MNCC_START_DTMF_REJ, "MNCC_START_DTMF_REJ" },
64 { MNCC_STOP_DTMF_IND, "MNCC_STOP_DTMF_IND" },
65 { MNCC_STOP_DTMF_RSP, "MNCC_STOP_DTMF_RSP" },
66 { MNCC_MODIFY_REQ, "MNCC_MODIFY_REQ" },
67 { MNCC_MODIFY_IND, "MNCC_MODIFY_IND" },
68 { MNCC_MODIFY_RSP, "MNCC_MODIFY_RSP" },
69 { MNCC_MODIFY_CNF, "MNCC_MODIFY_CNF" },
70 { MNCC_MODIFY_REJ, "MNCC_MODIFY_REJ" },
71 { MNCC_HOLD_IND, "MNCC_HOLD_IND" },
72 { MNCC_HOLD_CNF, "MNCC_HOLD_CNF" },
73 { MNCC_HOLD_REJ, "MNCC_HOLD_REJ" },
74 { MNCC_RETRIEVE_IND, "MNCC_RETRIEVE_IND" },
75 { MNCC_RETRIEVE_CNF, "MNCC_RETRIEVE_CNF" },
76 { MNCC_RETRIEVE_REJ, "MNCC_RETRIEVE_REJ" },
77 { MNCC_USERINFO_REQ, "MNCC_USERINFO_REQ" },
78 { MNCC_USERINFO_IND, "MNCC_USERINFO_IND" },
79 { MNCC_REJ_REQ, "MNCC_REJ_REQ" },
80 { MNCC_REJ_IND, "MNCC_REJ_IND" },
81 { MNCC_BRIDGE, "MNCC_BRIDGE" },
82 { MNCC_FRAME_RECV, "MNCC_FRAME_RECV" },
83 { MNCC_FRAME_DROP, "MNCC_FRAME_DROP" },
84 { MNCC_LCHAN_MODIFY, "MNCC_LCHAN_MODIFY" },
85 { MNCC_RTP_CREATE, "MNCC_RTP_CREATE" },
86 { MNCC_RTP_CONNECT, "MNCC_RTP_CONNECT" },
87 { MNCC_RTP_FREE, "MNCC_RTP_FREE" },
88 { GSM_TCHF_FRAME, "GSM_TCHF_FRAME" },
89 { GSM_TCHF_FRAME_EFR, "GSM_TCHF_FRAME_EFR" },
90 { GSM_TCHH_FRAME, "GSM_TCHH_FRAME" },
91 { GSM_TCH_FRAME_AMR, "GSM_TCH_FRAME_AMR" },
92 { GSM_BAD_FRAME, "GSM_BAD_FRAME" },
93 { 0, NULL },
94};
Harald Welte4bfdfe72009-06-10 23:11:52 +080095
Harald Welteda8a19f2015-12-03 14:35:05 +010096const char *get_mncc_name(int value)
Harald Welte4bfdfe72009-06-10 23:11:52 +080097{
Harald Welteda8a19f2015-12-03 14:35:05 +010098 return get_value_string(mncc_names, value);
Harald Welte4bfdfe72009-06-10 23:11:52 +080099}
100
Harald Welte4bfdfe72009-06-10 23:11:52 +0800101void mncc_set_cause(struct gsm_mncc *data, int loc, int val)
102{
103 data->fields |= MNCC_F_CAUSE;
104 data->cause.location = loc;
105 data->cause.value = val;
106}
Harald Weltefea236e2010-12-23 00:13:47 +0100107
Harald Welte57184292018-01-22 01:49:02 +0100108
109/***********************************************************************
110 * MNCC validation code. Move to libosmocore once headers are merged
111 ************************************************************************/
112
113#define MNCC_F_ALL 0x3fff
114
115static int check_string_terminated(const char *str, unsigned int size)
116{
117 int i;
118 for (i = 0; i < size; i++) {
119 if (str[i] == 0)
120 return 0;
121 }
122 return -EINVAL;
123}
124
125static int mncc_check_number(const struct gsm_mncc_number *num, const char *str)
126{
127 int rc;
128 rc = check_string_terminated(num->number, ARRAY_SIZE(num->number));
129 if (rc < 0)
130 LOGP(DMNCC, LOGL_ERROR, "MNCC %s number not terminated\n", str);
131 return rc;
132}
133
134static int mncc_check_cause(const struct gsm_mncc_cause *cause)
135{
136 if (cause->diag_len > sizeof(cause->diag))
137 return -EINVAL;
138 return 0;
139}
140
141static int mncc_check_useruser(const struct gsm_mncc_useruser *uu)
142{
143 return check_string_terminated(uu->info, ARRAY_SIZE(uu->info));
144}
145
146static int mncc_check_facility(const struct gsm_mncc_facility *fac)
147{
148 return check_string_terminated(fac->info, ARRAY_SIZE(fac->info));
149}
150
151static int mncc_check_ssversion(const struct gsm_mncc_ssversion *ssv)
152{
153 return check_string_terminated(ssv->info, ARRAY_SIZE(ssv->info));
154}
155
156static int mncc_prim_check_sign(const struct gsm_mncc *mncc_prim)
157{
158 int rc;
159
160 if (mncc_prim->fields & ~ MNCC_F_ALL) {
161 LOGP(DMNCC, LOGL_ERROR, "Unknown MNCC field mask 0x%x\n", mncc_prim->fields);
162 return -EINVAL;
163 }
164
165 rc = check_string_terminated(mncc_prim->imsi, sizeof(mncc_prim->imsi));
166 if (rc < 0) {
167 LOGP(DMNCC, LOGL_ERROR, "MNCC IMSI not terminated\n");
168 return rc;
169 }
170
171 if (mncc_prim->fields & MNCC_F_CALLED) {
172 rc = mncc_check_number(&mncc_prim->called, "called");
173 if (rc < 0)
174 return rc;
175 }
176
177 if (mncc_prim->fields & MNCC_F_CALLING) {
178 rc = mncc_check_number(&mncc_prim->calling, "calling");
179 if (rc < 0)
180 return rc;
181 }
182
183 if (mncc_prim->fields & MNCC_F_REDIRECTING) {
184 rc = mncc_check_number(&mncc_prim->redirecting, "redirecting");
185 if (rc < 0)
186 return rc;
187 }
188
189 if (mncc_prim->fields & MNCC_F_CONNECTED) {
190 rc = mncc_check_number(&mncc_prim->connected, "connected");
191 if (rc < 0)
192 return rc;
193 }
194
195 if (mncc_prim->fields & MNCC_F_CAUSE) {
196 rc = mncc_check_cause(&mncc_prim->cause);
197 if (rc < 0)
198 return rc;
199 }
200
201 if (mncc_prim->fields & MNCC_F_USERUSER) {
202 rc = mncc_check_useruser(&mncc_prim->useruser);
203 if (rc < 0)
204 return rc;
205 }
206
207 if (mncc_prim->fields & MNCC_F_FACILITY) {
208 rc = mncc_check_facility(&mncc_prim->facility);
209 if (rc < 0)
210 return rc;
211 }
212
213 if (mncc_prim->fields & MNCC_F_SSVERSION) {
214 rc = mncc_check_ssversion(&mncc_prim->ssversion);
215 if (rc < 0)
216 return rc;
217 }
218
219 if (mncc_prim->fields & MNCC_F_BEARER_CAP) {
220 bool m1_found = false;
221 int i;
222
223 for (i = 0; i < ARRAY_SIZE(mncc_prim->bearer_cap.speech_ver); i++) {
224 if (mncc_prim->bearer_cap.speech_ver[i] == -1) {
225 m1_found = true;
226 break;
227 }
228 }
229 if (!m1_found) {
230 LOGP(DMNCC, LOGL_ERROR, "Unterminated MNCC bearer capability\n");
231 return -EINVAL;
232 }
233 }
234
235 return 0;
236}
237
238int mncc_prim_check(const struct gsm_mncc *mncc_prim, unsigned int len)
239{
240 if (len < sizeof(mncc_prim->msg_type)) {
241 LOGP(DMNCC, LOGL_ERROR, "Short MNCC Header\n");
242 return -EINVAL;
243 }
244
245 switch (mncc_prim->msg_type) {
246 case MNCC_SOCKET_HELLO:
247 if (len < sizeof(struct gsm_mncc_hello)) {
248 LOGP(DMNCC, LOGL_ERROR, "Short MNCC Hello\n");
249 return -EINVAL;
250 }
251 break;
252 case GSM_BAD_FRAME:
253 case GSM_TCH_FRAME_AMR:
254 case GSM_TCHH_FRAME:
255 case GSM_TCHF_FRAME_EFR:
256 case GSM_TCHF_FRAME:
257 if (len < sizeof(struct gsm_data_frame)) {
258 LOGP(DMNCC, LOGL_ERROR, "Short MNCC TCH\n");
259 return -EINVAL;
260 }
261 break;
262 case MNCC_RTP_FREE:
263 case MNCC_RTP_CONNECT:
264 case MNCC_RTP_CREATE:
265 if (len < sizeof(struct gsm_mncc_rtp)) {
266 LOGP(DMNCC, LOGL_ERROR, "Short MNCC RTP\n");
267 return -EINVAL;
268 }
269 break;
270 case MNCC_LCHAN_MODIFY:
271 case MNCC_FRAME_DROP:
272 case MNCC_FRAME_RECV:
273 /* FIXME */
274 break;
275 case MNCC_BRIDGE:
276 if (len < sizeof(struct gsm_mncc_bridge)) {
277 LOGP(DMNCC, LOGL_ERROR, "Short MNCC BRIDGE\n");
278 return -EINVAL;
279 }
280 break;
281 default:
282 if (len < sizeof(struct gsm_mncc)) {
283 LOGP(DMNCC, LOGL_ERROR, "Short MNCC Signalling\n");
284 return -EINVAL;
285 }
286 return mncc_prim_check_sign(mncc_prim);
287 }
288 return 0;
289}