blob: b5e7e7d8e43385946ee9b33ff225ce1135d2672a [file] [log] [blame]
Harald Welte3561bd42018-01-28 03:04:16 +01001/* (C) 2017 by Harald Welte <laforge@gnumonks.org>
2 * All Rights Reserved
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19#include <osmocom/core/fsm.h>
20#include <osmocom/core/logging.h>
21#include <osmocom/gsm/gsm0808.h>
22#include <osmocom/sigtran/sccp_sap.h>
23#include <osmocom/gsm/gsm0808_utils.h>
24
25#include <osmocom/bsc/debug.h>
26#include <osmocom/bsc/bsc_api.h>
27#include <osmocom/bsc/gsm_data.h>
28#include <osmocom/bsc/handover.h>
29#include <osmocom/bsc/chan_alloc.h>
30#include <osmocom/bsc/bsc_subscriber.h>
31#include <osmocom/bsc/osmo_bsc_sigtran.h>
32#include <osmocom/bsc/bsc_subscr_conn_fsm.h>
33#include <osmocom/bsc/osmo_bsc.h>
34#include <osmocom/bsc/penalty_timers.h>
35#include <osmocom/mgcp_client/mgcp_client_fsm.h>
36#include <osmocom/core/byteswap.h>
37
38#define S(x) (1 << (x))
39
40#define MGCP_MGW_TIMEOUT 4 /* in seconds */
41#define MGCP_MGW_TIMEOUT_TIMER_NR 1
42
43#define MGCP_MGW_HO_TIMEOUT 4 /* in seconds */
44#define MGCP_MGW_HO_TIMEOUT_TIMER_NR 2
45
46#define GSM0808_T10_TIMER_NR 10
47#define GSM0808_T10_VALUE 6
48
49#define ENDPOINT_ID "rtpbridge/*@mgw"
50
51enum gscon_fsm_states {
52 ST_INIT,
53 /* waiting for CC from MSC */
54 ST_WAIT_CC,
55 /* active connection */
56 ST_ACTIVE,
57 /* during assignment; waiting for ASS_CMPL */
58 ST_WAIT_ASS_CMPL,
59 /* during assignment; waiting for MODE_MODIFY_ACK */
60 ST_WAIT_MODE_MODIFY_ACK,
61 /* BSSMAP CLEAR has been received */
62 ST_CLEARING,
63
64/* MGW handling */
65 /* during assignment; waiting for MGW response to CRCX for BTS */
66 ST_WAIT_CRCX_BTS,
67 /* during assignment; waiting for MGW response to MDCX for BTS */
68 ST_WAIT_MDCX_BTS,
69 /* during assignment; waiting for MGW response to CRCX for MSC */
70 ST_WAIT_CRCX_MSC,
71
72/* MT (inbound) handover */
73 /* Wait for Handover Access from MS/BTS */
74 ST_WAIT_MT_HO_ACC,
75 /* Wait for RR Handover Complete from MS/BTS */
76 ST_WAIT_MT_HO_COMPL,
77
78/* MO (outbound) handover */
79 /* Wait for Handover Command / Handover Required Reject from MSC */
80 ST_WAIT_MO_HO_CMD,
81 /* Wait for Clear Command from MSC */
82 ST_MO_HO_PROCEEDING,
83
84/* Internal HO handling */
85 /* Wait for the handover logic to complete the handover */
86 ST_WAIT_HO_COMPL,
87 /* during handover; waiting for MGW response to MDCX for BTS */
88 ST_WAIT_MDCX_BTS_HO,
89};
90
91static const struct value_string gscon_fsm_event_names[] = {
92 {GSCON_EV_A_CONN_IND, "MT-CONNECT.ind"},
93 {GSCON_EV_A_CONN_REQ, "MO-CONNECT.req"},
94 {GSCON_EV_A_CONN_CFM, "MO-CONNECT.cfm"},
95 {GSCON_EV_A_ASSIGNMENT_CMD, "ASSIGNMENT_CMD"},
96 {GSCON_EV_A_CLEAR_CMD, "CLEAR_CMD"},
97 {GSCON_EV_A_DISC_IND, "DISCONNET.ind"},
98 {GSCON_EV_A_HO_REQ, "HANDOVER_REQUEST"},
99
100 {GSCON_EV_RR_ASS_COMPL, "RR_ASSIGN_COMPL"},
101 {GSCON_EV_RR_ASS_FAIL, "RR_ASSIGN_FAIL"},
102 {GSCON_EV_RR_MODE_MODIFY_ACK, "RR_MODE_MODIFY_ACK"},
Harald Welte3561bd42018-01-28 03:04:16 +0100103 {GSCON_EV_RLL_REL_IND, "RLL_RELEASE.ind"},
104 {GSCON_EV_RSL_CONN_FAIL, "RSL_CONN_FAIL.ind"},
105 {GSCON_EV_RSL_CLEAR_COMPL, "RSL_CLEAR_COMPLETE"},
106
107 {GSCON_EV_MO_DTAP, "MO-DTAP"},
108 {GSCON_EV_MT_DTAP, "MT-DTAP"},
109 {GSCON_EV_TX_SCCP, "TX_SCCP"},
110
111 {GSCON_EV_MGW_FAIL_BTS, "MGW_FAILURE_BTS"},
112 {GSCON_EV_MGW_FAIL_MSC, "MGW_FAILURE_MSC"},
113 {GSCON_EV_MGW_CRCX_RESP_BTS, "MGW_CRCX_RESPONSE_BTS"},
114 {GSCON_EV_MGW_MDCX_RESP_BTS, "MGW_MDCX_RESPONSE_BTS"},
115 {GSCON_EV_MGW_CRCX_RESP_MSC, "MGW_CRCX_RESPONSE_MSC"},
116
117 {GSCON_EV_HO_START, "HO_START"},
118 {GSCON_EV_HO_TIMEOUT, "HO_TIMEOUT"},
119 {GSCON_EV_HO_FAIL, "HO_FAIL"},
120 {GSCON_EV_HO_COMPL, "HO_COMPL"},
121
122 {0, NULL}
123};
124
125/* Send data SCCP message through SCCP connection. All sigtran messages
126 * that are send from this FSM must use this function. Never use
127 * osmo_bsc_sigtran_send() directly since this would defeat the checks
128 * provided by this function. */
129static void sigtran_send(struct gsm_subscriber_connection *conn, struct msgb *msg, struct osmo_fsm_inst *fi)
130{
131 int rc;
132
133 /* Make sure that we only attempt to send SCCP messages if we have
134 * a life SCCP connection. Otherwise drop the message. */
135 if (fi->state == ST_INIT || fi->state == ST_WAIT_CC) {
136 LOGPFSML(fi, LOGL_ERROR, "No active SCCP connection, dropping message!\n");
137 msgb_free(msg);
138 return;
139 }
140
141 rc = osmo_bsc_sigtran_send(conn, msg);
142 if (rc < 0)
143 LOGPFSML(fi, LOGL_ERROR, "Unable to deliver SCCP message!\n");
144}
145
Harald Welteead291a2018-03-21 22:11:32 +0100146
147/* See TS 48.008 3.2.2.11 Channel Type Octet 5 */
148static int bssap_speech_from_lchan(const struct gsm_lchan *lchan)
149{
150 switch (lchan->type) {
151 case GSM_LCHAN_TCH_H:
152 switch (lchan->tch_mode) {
153 case GSM48_CMODE_SPEECH_V1:
154 return 0x05;
155 case GSM48_CMODE_SPEECH_AMR:
156 return 0x25;
157 default:
158 return -1;
159 }
160 break;
161 case GSM_LCHAN_TCH_F:
162 switch (lchan->tch_mode) {
163 case GSM48_CMODE_SPEECH_V1:
164 return 0x01;
165 case GSM48_CMODE_SPEECH_EFR:
166 return 0x11;
167 case GSM48_CMODE_SPEECH_AMR:
168 return 0x21;
169 default:
170 return -1;
171 }
172 break;
173 default:
174 return -1;
175 }
176}
177
178/* GSM 08.08 3.2.2.33 */
179static uint8_t lchan_to_chosen_channel(struct gsm_lchan *lchan)
180{
181 uint8_t channel_mode = 0, channel = 0;
182
183 switch (lchan->tch_mode) {
184 case GSM48_CMODE_SPEECH_V1:
185 case GSM48_CMODE_SPEECH_EFR:
186 case GSM48_CMODE_SPEECH_AMR:
187 channel_mode = 0x9;
188 break;
189 case GSM48_CMODE_SIGN:
190 channel_mode = 0x8;
191 break;
192 case GSM48_CMODE_DATA_14k5:
193 channel_mode = 0xe;
194 break;
195 case GSM48_CMODE_DATA_12k0:
196 channel_mode = 0xb;
197 break;
198 case GSM48_CMODE_DATA_6k0:
199 channel_mode = 0xc;
200 break;
201 case GSM48_CMODE_DATA_3k6:
202 channel_mode = 0xd;
203 break;
204 }
205
206 switch (lchan->type) {
207 case GSM_LCHAN_NONE:
208 channel = 0x0;
209 break;
210 case GSM_LCHAN_SDCCH:
211 channel = 0x1;
212 break;
213 case GSM_LCHAN_TCH_F:
214 channel = 0x8;
215 break;
216 case GSM_LCHAN_TCH_H:
217 channel = 0x9;
218 break;
219 case GSM_LCHAN_UNKNOWN:
220 default:
221 LOGP(DMSC, LOGL_ERROR, "Unknown lchan type: %p\n", lchan);
222 break;
223 }
224
225 return channel_mode << 4 | channel;
226}
227
Harald Welte3561bd42018-01-28 03:04:16 +0100228/* Generate and send assignment complete message */
Philipp Maier1f4851e2018-04-16 17:24:10 +0200229static void send_ass_compl(struct gsm_lchan *lchan, struct osmo_fsm_inst *fi, bool voice)
Harald Welte3561bd42018-01-28 03:04:16 +0100230{
231 struct msgb *resp;
232 struct gsm0808_speech_codec sc;
Philipp Maier1f4851e2018-04-16 17:24:10 +0200233 struct gsm0808_speech_codec *sc_ptr = NULL;
Harald Welte3561bd42018-01-28 03:04:16 +0100234 struct gsm_subscriber_connection *conn;
Philipp Maier1f4851e2018-04-16 17:24:10 +0200235 struct sockaddr_storage *addr_local = NULL;
236 int perm_spch = 0;
Harald Welte3561bd42018-01-28 03:04:16 +0100237
238 conn = lchan->conn;
Harald Welte3561bd42018-01-28 03:04:16 +0100239 OSMO_ASSERT(conn);
240
241 LOGPFSML(fi, LOGL_DEBUG, "Sending assignment complete message... (id=%i)\n", conn->sccp.conn_id);
242
Philipp Maier1f4851e2018-04-16 17:24:10 +0200243 /* Generate voice related fields */
244 if (voice) {
245 OSMO_ASSERT(lchan->abis_ip.ass_compl.valid);
246 perm_spch = bssap_speech_from_lchan(lchan);
247 addr_local = &conn->user_plane.aoip_rtp_addr_local;
248
249 /* Extrapolate speech codec from speech mode */
250 gsm0808_speech_codec_from_chan_type(&sc, perm_spch);
251 sc_ptr = &sc;
252
253 /* FIXME: AMR codec configuration must be derived from lchan1! */
254 }
Harald Welte3561bd42018-01-28 03:04:16 +0100255
256 /* Generate message */
257 resp = gsm0808_create_ass_compl(lchan->abis_ip.ass_compl.rr_cause,
Harald Welteead291a2018-03-21 22:11:32 +0100258 lchan_to_chosen_channel(lchan),
259 lchan->encr.alg_id, perm_spch,
Philipp Maier1f4851e2018-04-16 17:24:10 +0200260 addr_local, sc_ptr, NULL);
Harald Welte3561bd42018-01-28 03:04:16 +0100261
262 if (!resp) {
263 LOGPFSML(fi, LOGL_ERROR, "Failed to generate assignment completed message! (id=%i)\n",
264 conn->sccp.conn_id);
265 }
266
267 sigtran_send(conn, resp, fi);
268}
269
270/* forward MT DTAP from BSSAP side to RSL side */
271static void submit_dtap(struct gsm_subscriber_connection *conn, struct msgb *msg, struct osmo_fsm_inst *fi)
272{
273 int rc;
274 struct msgb *resp = NULL;
275
276 OSMO_ASSERT(fi);
277 OSMO_ASSERT(msg);
278 OSMO_ASSERT(conn);
279
280 rc = gsm0808_submit_dtap(conn, msg, OBSC_LINKID_CB(msg), 1);
281 if (rc != 0) {
282 LOGPFSML(fi, LOGL_ERROR, "Tx BSSMAP CLEAR REQUEST to MSC\n");
283 resp = gsm0808_create_clear_rqst(GSM0808_CAUSE_EQUIPMENT_FAILURE);
284 sigtran_send(conn, resp, fi);
285 osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0);
286 return;
287 }
288}
289
290/* forward MO DTAP from RSL side to BSSAP side */
Philipp Maier4be98dc2018-03-21 11:07:53 +0100291static void forward_dtap(struct gsm_subscriber_connection *conn, struct msgb *msg, struct osmo_fsm_inst *fi)
Harald Welte3561bd42018-01-28 03:04:16 +0100292{
293 struct msgb *resp = NULL;
294
295 OSMO_ASSERT(msg);
296 OSMO_ASSERT(conn);
297
298 resp = gsm0808_create_dtap(msg, OBSC_LINKID_CB(msg));
299 sigtran_send(conn, resp, fi);
300}
301
302/* In case there are open MGCP connections, toss
303 * those connections */
304static void toss_mgcp_conn(struct gsm_subscriber_connection *conn, struct osmo_fsm_inst *fi)
305{
306 LOGPFSML(fi, LOGL_ERROR, "tossing all MGCP connections...\n");
307
308 if (conn->user_plane.fi_bts) {
309 mgcp_conn_delete(conn->user_plane.fi_bts);
310 conn->user_plane.fi_bts = NULL;
311 }
312
313 if (conn->user_plane.fi_msc) {
314 mgcp_conn_delete(conn->user_plane.fi_msc);
315 conn->user_plane.fi_msc = NULL;
316 }
317
318 if (conn->user_plane.mgw_endpoint) {
319 talloc_free(conn->user_plane.mgw_endpoint);
320 conn->user_plane.mgw_endpoint = NULL;
321 }
322}
323
324static void gscon_fsm_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
325{
326 struct gsm_subscriber_connection *conn = fi->priv;
327 struct osmo_scu_prim *scu_prim = NULL;
328 struct msgb *msg = NULL;
329 int rc;
330
331 switch (event) {
332 case GSCON_EV_A_CONN_REQ:
333 /* RLL ESTABLISH IND with initial L3 Message */
334 msg = data;
335 /* FIXME: Extract Mobile ID and update FSM using osmo_fsm_inst_set_id()
336 * i.e. we will probably extract the mobile identity earlier, where the
337 * imsi filter code is. Then we could just use it here.
338 * related: OS#2969 */
339
340 rc = osmo_bsc_sigtran_open_conn(conn, msg);
341 if (rc < 0) {
342 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
343 } else {
344 /* SCCP T(conn est) is 1-2 minutes, way too long. The MS will timeout
345 * using T3210 (20s), T3220 (5s) or T3230 (10s) */
346 osmo_fsm_inst_state_chg(fi, ST_WAIT_CC, 20, 993210);
347 }
348 break;
349 case GSCON_EV_A_CONN_IND:
350 scu_prim = data;
351 if (!conn->sccp.msc) {
352 LOGPFSML(fi, LOGL_NOTICE, "N-CONNECT.ind from unknown MSC %s\n",
353 osmo_sccp_addr_dump(&scu_prim->u.connect.calling_addr));
354 osmo_sccp_tx_disconn(conn->sccp.msc->a.sccp_user, scu_prim->u.connect.conn_id,
355 &scu_prim->u.connect.called_addr, 0);
356 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
357 }
358 /* FIXME: Extract optional IMSI and update FSM using osmo_fsm_inst_set_id()
359 * related: OS2969 (same as above) */
360
361 LOGPFSML(fi, LOGL_NOTICE, "No support for MSC-originated SCCP Connections yet\n");
362 osmo_sccp_tx_disconn(conn->sccp.msc->a.sccp_user, scu_prim->u.connect.conn_id,
363 &scu_prim->u.connect.called_addr, 0);
364 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
365 break;
366 default:
367 OSMO_ASSERT(false);
368 break;
369 }
370}
371
372/* We've sent the CONNECTION.req to the SCCP provider and are waiting for CC from MSC */
373static void gscon_fsm_wait_cc(struct osmo_fsm_inst *fi, uint32_t event, void *data)
374{
375 switch (event) {
376 case GSCON_EV_A_CONN_CFM:
377 /* MSC has confirmed the connection, we now change into the
378 * active state and wait there for further operations */
379 osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0);
380 /* if there's user payload, forward it just like EV_MT_DTAP */
381 /* FIXME: Question: if there's user payload attached to the CC, forward it like EV_MT_DTAP? */
382 break;
383 default:
384 OSMO_ASSERT(false);
385 break;
386 }
387}
388
389/* We're on an active subscriber connection, passing DTAP back and forth */
390static void gscon_fsm_active(struct osmo_fsm_inst *fi, uint32_t event, void *data)
391{
392 struct gsm_subscriber_connection *conn = fi->priv;
393 struct msgb *resp = NULL;
394 struct mgcp_conn_peer conn_peer;
395 int rc;
396
397 switch (event) {
398 case GSCON_EV_A_ASSIGNMENT_CMD:
399 /* MSC requests us to perform assignment, this code section is
400 * triggered via signal GSCON_EV_A_ASSIGNMENT_CMD from
401 * bssmap_handle_assignm_req() in osmo_bsc_bssap.c, which does
402 * the parsing of incoming assignment requests. */
403
404 LOGPFSML(fi, LOGL_NOTICE, "Channel assignment: chan_mode=%s, full_rate=%i\n",
405 get_value_string(gsm48_chan_mode_names, conn->user_plane.chan_mode),
406 conn->user_plane.full_rate);
407
408 /* FIXME: We need to check if current channel is sufficient. If
409 * yes, do MODIFY. If not, do assignment (see commented lines below) */
410
Harald Welte3561bd42018-01-28 03:04:16 +0100411 switch (conn->user_plane.chan_mode) {
412 case GSM48_CMODE_SPEECH_V1:
413 case GSM48_CMODE_SPEECH_EFR:
414 case GSM48_CMODE_SPEECH_AMR:
415 /* A voice channel is requested, so we run down the
416 * mgcp-ass-mgcp state-chain (see FIXME above) */
417 memset(&conn_peer, 0, sizeof(conn_peer));
418 conn_peer.call_id = conn->sccp.conn_id;
419 osmo_strlcpy(conn_peer.endpoint, ENDPOINT_ID, sizeof(conn_peer.endpoint));
420
421 /* (Pre)Change state and create the connection */
422 osmo_fsm_inst_state_chg(fi, ST_WAIT_CRCX_BTS, MGCP_MGW_TIMEOUT, MGCP_MGW_TIMEOUT_TIMER_NR);
423 conn->user_plane.fi_bts =
424 mgcp_conn_create(conn->network->mgw.client, fi, GSCON_EV_MGW_FAIL_BTS,
425 GSCON_EV_MGW_CRCX_RESP_BTS, &conn_peer);
426 if (!conn->user_plane.fi_bts) {
427 resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_EQUIPMENT_FAILURE, NULL);
428 sigtran_send(conn, resp, fi);
Harald Welte3561bd42018-01-28 03:04:16 +0100429 return;
430 }
431 break;
432 case GSM48_CMODE_SIGN:
433 /* A signalling channel is requested, so we perform the
434 * channel assignment directly without performing any
435 * MGCP actions. ST_WAIT_ASS_CMPL will see by the
436 * conn->user_plane.chan_mode parameter that this
437 * assignment is for a signalling channel and will then
438 * change back to ST_ACTIVE (here) immediately. */
Harald Welte6900f812018-03-21 21:29:03 +0100439 rc = gsm0808_assign_req(conn, conn->user_plane.chan_mode,
440 conn->user_plane.full_rate);
Harald Welte3561bd42018-01-28 03:04:16 +0100441 if (rc != 0) {
442 resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_EQUIPMENT_FAILURE, NULL);
443 sigtran_send(conn, resp, fi);
444 return;
445 }
446
447 osmo_fsm_inst_state_chg(fi, ST_WAIT_ASS_CMPL, GSM0808_T10_VALUE, GSM0808_T10_TIMER_NR);
448 break;
449 default:
450 /* An unsupported channel is requested, so we have to
451 * reject this request by sending an assignment failure
452 * message immediately */
Pau Espin Pedrol55677de2018-03-17 01:12:33 +0100453 LOGPFSML(fi, LOGL_ERROR, "Requested channel mode is not supported! chan_mode=%s full_rate=%d\n",
Harald Welte3561bd42018-01-28 03:04:16 +0100454 get_value_string(gsm48_chan_mode_names, conn->user_plane.chan_mode),
455 conn->user_plane.full_rate);
456
457 /* The requested channel mode is not supported */
458 resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP, NULL);
459 sigtran_send(conn, resp, fi);
460 break;
461 }
462 break;
463 case GSCON_EV_HO_START:
464 rc = bsc_handover_start_gscon(conn);
465 if (rc) {
466 resp = gsm0808_create_clear_rqst(GSM0808_CAUSE_EQUIPMENT_FAILURE);
467 sigtran_send(conn, resp, fi);
468 osmo_fsm_inst_state_chg(fi, ST_CLEARING, 0, 0);
469 return;
470 }
471
472 /* Note: No timeout is set here, T3103 in handover_logic.c
473 * will generate a GSCON_EV_HO_TIMEOUT event should the
474 * handover time out, so we do not need another timeout
475 * here (maybe its worth to think about giving GSCON
476 * more power over the actual handover process). */
477 osmo_fsm_inst_state_chg(fi, ST_WAIT_HO_COMPL, 0, 0);
478 break;
479 case GSCON_EV_A_HO_REQ:
480 /* FIXME: reject any handover requests with HO FAIL until implemented */
481 break;
482 case GSCON_EV_MO_DTAP:
Philipp Maier4be98dc2018-03-21 11:07:53 +0100483 forward_dtap(conn, (struct msgb *)data, fi);
Harald Welte3561bd42018-01-28 03:04:16 +0100484 break;
485 case GSCON_EV_MT_DTAP:
486 submit_dtap(conn, (struct msgb *)data, fi);
487 break;
488 case GSCON_EV_TX_SCCP:
489 sigtran_send(conn, (struct msgb *)data, fi);
490 break;
491 default:
492 OSMO_ASSERT(false);
493 break;
494 }
495}
496
497/* Before we may start the channel assignment we need to get an IP/Port for the
498 * RTP connection from the MGW */
499static void gscon_fsm_wait_crcx_bts(struct osmo_fsm_inst *fi, uint32_t event, void *data)
500{
501 struct gsm_subscriber_connection *conn = fi->priv;
502 struct mgcp_conn_peer *conn_peer = NULL;
503 struct msgb *resp = NULL;
504 int rc;
505
506 switch (event) {
507 case GSCON_EV_MGW_CRCX_RESP_BTS:
508 conn_peer = data;
509
Philipp Maier393165c2018-03-21 11:15:33 +0100510 /* Check if the MGW has assigned an enpoint to us, otherwise we
511 * can not proceed. */
Harald Welte3561bd42018-01-28 03:04:16 +0100512 if (strlen(conn_peer->endpoint) <= 0) {
513 resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_EQUIPMENT_FAILURE, NULL);
514 sigtran_send(conn, resp, fi);
515 osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0);
516 return;
517 }
518
519 /* Memorize the endpoint name we got assigned from the MGW.
520 * When the BTS sided connection is done, we need to create
521 * a second connection on that same endpoint, so we need
522 * to know its ID */
523 if (!conn->user_plane.mgw_endpoint)
524 conn->user_plane.mgw_endpoint = talloc_zero_size(conn, MGCP_ENDPOINT_MAXLEN);
525 OSMO_ASSERT(conn->user_plane.mgw_endpoint);
526 osmo_strlcpy(conn->user_plane.mgw_endpoint, conn_peer->endpoint, MGCP_ENDPOINT_MAXLEN);
527
528 /* Store the IP-Address and the port the MGW assigned to us,
529 * then start the channel assignment. */
530 conn->user_plane.rtp_port = conn_peer->port;
531 conn->user_plane.rtp_ip = osmo_ntohl(inet_addr(conn_peer->addr));
Harald Welte6900f812018-03-21 21:29:03 +0100532 rc = gsm0808_assign_req(conn, conn->user_plane.chan_mode, conn->user_plane.full_rate);
Harald Welte3561bd42018-01-28 03:04:16 +0100533 if (rc != 0) {
534 resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_RQSTED_SPEECH_VERSION_UNAVAILABLE, NULL);
535 sigtran_send(conn, resp, fi);
536 osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0);
537 return;
538 }
539
540 osmo_fsm_inst_state_chg(fi, ST_WAIT_ASS_CMPL, GSM0808_T10_VALUE, GSM0808_T10_TIMER_NR);
541 break;
542 case GSCON_EV_MO_DTAP:
Philipp Maier4be98dc2018-03-21 11:07:53 +0100543 forward_dtap(conn, (struct msgb *)data, fi);
Harald Welte3561bd42018-01-28 03:04:16 +0100544 break;
545 case GSCON_EV_MT_DTAP:
546 submit_dtap(conn, (struct msgb *)data, fi);
547 break;
548 case GSCON_EV_TX_SCCP:
549 sigtran_send(conn, (struct msgb *)data, fi);
550 break;
551 default:
552 OSMO_ASSERT(false);
553 break;
554 }
555}
556
557/* We're waiting for an ASSIGNMENT COMPLETE from MS */
558static void gscon_fsm_wait_ass_cmpl(struct osmo_fsm_inst *fi, uint32_t event, void *data)
559{
560 struct gsm_subscriber_connection *conn = fi->priv;
561 struct gsm_lchan *lchan = conn->lchan;
562 struct mgcp_conn_peer conn_peer;
563 struct in_addr addr;
564 struct msgb *resp = NULL;
565 int rc;
566
567 switch (event) {
568 case GSCON_EV_RR_ASS_COMPL:
569 switch (conn->user_plane.chan_mode) {
570 case GSM48_CMODE_SPEECH_V1:
571 case GSM48_CMODE_SPEECH_EFR:
572 case GSM48_CMODE_SPEECH_AMR:
573 /* FIXME: What if we are using SCCP-Lite? */
574
575 /* We are dealing with a voice channel, so we can not
576 * confirm the assignment directly. We must first do
577 * some final steps on the MGCP side. */
578
579 /* Prepare parameters with the information we got during the assignment */
580 memset(&conn_peer, 0, sizeof(conn_peer));
581 addr.s_addr = osmo_ntohl(lchan->abis_ip.bound_ip);
582 osmo_strlcpy(conn_peer.addr, inet_ntoa(addr), sizeof(conn_peer.addr));
583 conn_peer.port = lchan->abis_ip.bound_port;
584
585 /* (Pre)Change state and modify the connection */
586 osmo_fsm_inst_state_chg(fi, ST_WAIT_MDCX_BTS, MGCP_MGW_TIMEOUT, MGCP_MGW_TIMEOUT_TIMER_NR);
587 rc = mgcp_conn_modify(conn->user_plane.fi_bts, GSCON_EV_MGW_MDCX_RESP_BTS, &conn_peer);
588 if (rc != 0) {
589 resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_EQUIPMENT_FAILURE, NULL);
590 sigtran_send(conn, resp, fi);
591 osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0);
592 return;
593 }
594 break;
595 case GSM48_CMODE_SIGN:
596 /* Confirm the successful assignment on BSSMAP and
597 * change back into active state */
Philipp Maier1f4851e2018-04-16 17:24:10 +0200598 send_ass_compl(lchan, fi, false);
Harald Welte3561bd42018-01-28 03:04:16 +0100599 osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0);
600 break;
601 default:
602 /* Unsupported modes should have been already filtered
603 * by gscon_fsm_active(). If we reach the default
604 * section here anyway than some unsupported mode must
605 * have made it into the FSM, this would be a bug, so
606 * we fire an assertion here */
607 OSMO_ASSERT(false);
608 break;
609 }
610
611 break;
612 case GSCON_EV_RR_ASS_FAIL:
613 resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_RQSTED_TERRESTRIAL_RESOURCE_UNAVAILABLE, NULL);
614 sigtran_send(conn, resp, fi);
615 osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0);
616 break;
617 case GSCON_EV_MO_DTAP:
Philipp Maier4be98dc2018-03-21 11:07:53 +0100618 forward_dtap(conn, (struct msgb *)data, fi);
Harald Welte3561bd42018-01-28 03:04:16 +0100619 break;
620 case GSCON_EV_MT_DTAP:
621 submit_dtap(conn, (struct msgb *)data, fi);
622 break;
623 case GSCON_EV_TX_SCCP:
624 sigtran_send(conn, (struct msgb *)data, fi);
625 break;
626 default:
627 OSMO_ASSERT(false);
628 break;
629 }
630}
631
632/* We are waiting for the MGW response to the MDCX */
633static void gscon_fsm_wait_mdcx_bts(struct osmo_fsm_inst *fi, uint32_t event, void *data)
634{
635 struct gsm_subscriber_connection *conn = fi->priv;
636 struct mgcp_conn_peer conn_peer;
637 struct sockaddr_in *sin = NULL;
638 struct msgb *resp = NULL;
639
640 switch (event) {
641 case GSCON_EV_MGW_MDCX_RESP_BTS:
642
643 /* Prepare parameters with the connection information we got
644 * with the assignment command */
645 memset(&conn_peer, 0, sizeof(conn_peer));
646 conn_peer.call_id = conn->sccp.conn_id;
647 sin = (struct sockaddr_in *)&conn->user_plane.aoip_rtp_addr_remote;
648 conn_peer.port = osmo_ntohs(sin->sin_port);
649 osmo_strlcpy(conn_peer.addr, inet_ntoa(sin->sin_addr), sizeof(conn_peer.addr));
650
651 /* Make sure we use the same endpoint where we created the
652 * BTS connection. */
653 osmo_strlcpy(conn_peer.endpoint, conn->user_plane.mgw_endpoint, sizeof(conn_peer.endpoint));
654
655 /* (Pre)Change state and create the connection */
656 osmo_fsm_inst_state_chg(fi, ST_WAIT_CRCX_MSC, MGCP_MGW_TIMEOUT, MGCP_MGW_TIMEOUT_TIMER_NR);
657 conn->user_plane.fi_msc =
658 mgcp_conn_create(conn->network->mgw.client, fi, GSCON_EV_MGW_FAIL_MSC, GSCON_EV_MGW_CRCX_RESP_MSC,
659 &conn_peer);
660 if (!conn->user_plane.fi_bts) {
661 resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_EQUIPMENT_FAILURE, NULL);
662 sigtran_send(conn, resp, fi);
663 osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0);
664 return;
665 }
666
667 break;
668 case GSCON_EV_MO_DTAP:
Philipp Maier4be98dc2018-03-21 11:07:53 +0100669 forward_dtap(conn, (struct msgb *)data, fi);
Harald Welte3561bd42018-01-28 03:04:16 +0100670 break;
671 case GSCON_EV_MT_DTAP:
672 submit_dtap(conn, (struct msgb *)data, fi);
673 break;
674 case GSCON_EV_TX_SCCP:
675 sigtran_send(conn, (struct msgb *)data, fi);
676 break;
677 default:
678 OSMO_ASSERT(false);
679 break;
680 }
681}
682
683static void gscon_fsm_wait_crcx_msc(struct osmo_fsm_inst *fi, uint32_t event, void *data)
684{
685 struct gsm_subscriber_connection *conn = fi->priv;
686 struct mgcp_conn_peer *conn_peer = NULL;
687 struct gsm_lchan *lchan = conn->lchan;
688 struct sockaddr_in *sin = NULL;
689
690 switch (event) {
691 case GSCON_EV_MGW_CRCX_RESP_MSC:
692 conn_peer = data;
693
694 /* Store address information we got in response from the CRCX command. */
695 sin = (struct sockaddr_in *)&conn->user_plane.aoip_rtp_addr_local;
696 sin->sin_family = AF_INET;
697 sin->sin_addr.s_addr = inet_addr(conn_peer->addr);
698 sin->sin_port = osmo_ntohs(conn_peer->port);
699
700 /* Send assignment complete message to the MSC */
Philipp Maier1f4851e2018-04-16 17:24:10 +0200701 send_ass_compl(lchan, fi, true);
Harald Welte3561bd42018-01-28 03:04:16 +0100702
703 osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0);
704
705 break;
706 case GSCON_EV_MO_DTAP:
Philipp Maier4be98dc2018-03-21 11:07:53 +0100707 forward_dtap(conn, (struct msgb *)data, fi);
Harald Welte3561bd42018-01-28 03:04:16 +0100708 break;
709 case GSCON_EV_MT_DTAP:
710 submit_dtap(conn, (struct msgb *)data, fi);
711 break;
712 case GSCON_EV_TX_SCCP:
713 sigtran_send(conn, (struct msgb *)data, fi);
714 break;
715 default:
716 OSMO_ASSERT(false);
717 break;
718 }
719}
720
721/* We're waiting for a MODE MODIFY ACK from MS + BTS */
722static void gscon_fsm_wait_mode_modify_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data)
723{
724 struct gsm_subscriber_connection *conn = fi->priv;
725 struct gsm_lchan *lchan = conn->lchan;
726
727 switch (event) {
728 case GSCON_EV_RR_MODE_MODIFY_ACK:
729 /* we assume that not only have we received the RR MODE_MODIFY_ACK, but
730 * actually that also the BTS side of the channel mode has been changed accordingly */
731 osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0);
732
733 /* FIXME: Check if this requires special handling. For now I assume that the send_ass_compl()
734 * can be used. But I am not sure. */
Philipp Maier1f4851e2018-04-16 17:24:10 +0200735 send_ass_compl(lchan, fi, false);
Harald Welte3561bd42018-01-28 03:04:16 +0100736
737 break;
738 /* FIXME: Do we need to handle DTAP traffic in this state? Maybe yes? Needs to be checked. */
739 case GSCON_EV_MO_DTAP:
Philipp Maier4be98dc2018-03-21 11:07:53 +0100740 forward_dtap(conn, (struct msgb *)data, fi);
Harald Welte3561bd42018-01-28 03:04:16 +0100741 break;
742 case GSCON_EV_MT_DTAP:
743 submit_dtap(conn, (struct msgb *)data, fi);
744 break;
745 case GSCON_EV_TX_SCCP:
746 sigtran_send(conn, (struct msgb *)data, fi);
747 break;
748 default:
749 OSMO_ASSERT(false);
750 break;
751 }
752}
753
754static void gscon_fsm_clearing(struct osmo_fsm_inst *fi, uint32_t event, void *data)
755{
756 struct gsm_subscriber_connection *conn = fi->priv;
757 struct msgb *resp;
758
759 switch (event) {
760 case GSCON_EV_RSL_CLEAR_COMPL:
761 resp = gsm0808_create_clear_complete();
762 sigtran_send(conn, resp, fi);
763 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, data);
764 break;
765 default:
766 OSMO_ASSERT(false);
767 break;
768 }
769}
770
771/* Wait for the handover logic to tell us whether the handover completed,
772 * failed or has timed out */
773static void gscon_fsm_wait_ho_compl(struct osmo_fsm_inst *fi, uint32_t event, void *data)
774{
775 struct gsm_subscriber_connection *conn = fi->priv;
776 struct mgcp_conn_peer conn_peer;
777 struct gsm_lchan *lchan = conn->lchan;
778 struct in_addr addr;
779 struct msgb *resp;
780 int rc;
781
782 switch (event) {
783 case GSCON_EV_HO_COMPL:
784 /* The handover logic informs us that the handover has been
785 * completet. Now we have to tell the MGW the IP/Port on the
786 * new BTS so that the uplink RTP traffic can be redirected
787 * there. */
788
789 /* Prepare parameters with the information we got during the
790 * handover procedure (via IPACC) */
791 memset(&conn_peer, 0, sizeof(conn_peer));
792 addr.s_addr = osmo_ntohl(lchan->abis_ip.bound_ip);
793 osmo_strlcpy(conn_peer.addr, inet_ntoa(addr), sizeof(conn_peer.addr));
794 conn_peer.port = lchan->abis_ip.bound_port;
795
796 /* (Pre)Change state and modify the connection */
797 osmo_fsm_inst_state_chg(fi, ST_WAIT_MDCX_BTS_HO, MGCP_MGW_TIMEOUT, MGCP_MGW_HO_TIMEOUT_TIMER_NR);
798 rc = mgcp_conn_modify(conn->user_plane.fi_bts, GSCON_EV_MGW_MDCX_RESP_BTS, &conn_peer);
799 if (rc != 0) {
800 resp = gsm0808_create_clear_rqst(GSM0808_CAUSE_EQUIPMENT_FAILURE);
801 sigtran_send(conn, resp, fi);
802 osmo_fsm_inst_state_chg(fi, ST_CLEARING, 0, 0);
803 return;
804 }
805 break;
806 case GSCON_EV_HO_TIMEOUT:
807 case GSCON_EV_HO_FAIL:
808 /* The handover logic informs us that the handover failed for
809 * some reason. This means the phone stays on the TS/BTS on
810 * which it currently is. We will change back to the active
811 * state again as there are no further operations needed */
812 osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0);
813 break;
814 default:
815 OSMO_ASSERT(false);
816 break;
817 }
818}
819
820/* Wait for the MGW to confirm handover related modification of the connection
821 * parameters */
822static void gscon_fsm_wait_mdcx_bts_ho(struct osmo_fsm_inst *fi, uint32_t event, void *data)
823{
824 struct gsm_subscriber_connection *conn = fi->priv;
825
826 switch (event) {
827 case GSCON_EV_MGW_MDCX_RESP_BTS:
828 /* The MGW has confirmed the handover MDCX, and the handover
829 * is now also done on the RTP side. We may now change back
830 * to the active state. */
831 osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0);
832 break;
833 case GSCON_EV_MO_DTAP:
Philipp Maier4be98dc2018-03-21 11:07:53 +0100834 forward_dtap(conn, (struct msgb *)data, fi);
Harald Welte3561bd42018-01-28 03:04:16 +0100835 break;
836 case GSCON_EV_MT_DTAP:
837 submit_dtap(conn, (struct msgb *)data, fi);
838 break;
839 case GSCON_EV_TX_SCCP:
840 sigtran_send(conn, (struct msgb *)data, fi);
841 break;
842 default:
843 OSMO_ASSERT(false);
844 break;
845 }
846}
847
848#define EV_TRANSPARENT_SCCP S(GSCON_EV_TX_SCCP) | S(GSCON_EV_MO_DTAP) | S(GSCON_EV_MT_DTAP)
849
850static const struct osmo_fsm_state gscon_fsm_states[] = {
851 [ST_INIT] = {
Harald Weltee9903fd2018-03-17 17:13:10 +0100852 .name = OSMO_STRINGIFY(INIT),
853 .in_event_mask = S(GSCON_EV_A_CONN_REQ) | S(GSCON_EV_A_CONN_IND),
854 .out_state_mask = S(ST_WAIT_CC),
855 .action = gscon_fsm_init,
856 },
Harald Welte3561bd42018-01-28 03:04:16 +0100857 [ST_WAIT_CC] = {
Harald Weltee9903fd2018-03-17 17:13:10 +0100858 .name = OSMO_STRINGIFY(WAIT_CC),
859 .in_event_mask = S(GSCON_EV_A_CONN_CFM),
860 .out_state_mask = S(ST_ACTIVE),
861 .action = gscon_fsm_wait_cc,
862 },
Harald Welte3561bd42018-01-28 03:04:16 +0100863 [ST_ACTIVE] = {
Harald Weltee9903fd2018-03-17 17:13:10 +0100864 .name = OSMO_STRINGIFY(ACTIVE),
865 .in_event_mask = EV_TRANSPARENT_SCCP | S(GSCON_EV_A_ASSIGNMENT_CMD) |
866 S(GSCON_EV_A_HO_REQ) | S(GSCON_EV_HO_START),
867 .out_state_mask = S(ST_CLEARING) | S(ST_WAIT_CRCX_BTS) | S(ST_WAIT_ASS_CMPL) |
868 S(ST_WAIT_MODE_MODIFY_ACK) | S(ST_WAIT_MO_HO_CMD) | S(ST_WAIT_HO_COMPL),
869 .action = gscon_fsm_active,
870 },
Harald Welte3561bd42018-01-28 03:04:16 +0100871 [ST_WAIT_CRCX_BTS] = {
Harald Weltee9903fd2018-03-17 17:13:10 +0100872 .name = OSMO_STRINGIFY(WAIT_CRCX_BTS),
873 .in_event_mask = EV_TRANSPARENT_SCCP | S(GSCON_EV_MGW_CRCX_RESP_BTS),
874 .out_state_mask = S(ST_ACTIVE) | S(ST_WAIT_ASS_CMPL),
875 .action = gscon_fsm_wait_crcx_bts,
876 },
Harald Welte3561bd42018-01-28 03:04:16 +0100877 [ST_WAIT_ASS_CMPL] = {
Harald Weltee9903fd2018-03-17 17:13:10 +0100878 .name = OSMO_STRINGIFY(WAIT_ASS_CMPL),
879 .in_event_mask = EV_TRANSPARENT_SCCP | S(GSCON_EV_RR_ASS_COMPL) | S(GSCON_EV_RR_ASS_FAIL),
880 .out_state_mask = S(ST_ACTIVE) | S(ST_WAIT_MDCX_BTS),
881 .action = gscon_fsm_wait_ass_cmpl,
882 },
Harald Welte3561bd42018-01-28 03:04:16 +0100883 [ST_WAIT_MDCX_BTS] = {
Harald Weltee9903fd2018-03-17 17:13:10 +0100884 .name = OSMO_STRINGIFY(WAIT_MDCX_BTS),
885 .in_event_mask = EV_TRANSPARENT_SCCP | S(GSCON_EV_MGW_MDCX_RESP_BTS),
886 .out_state_mask = S(ST_ACTIVE) | S(ST_WAIT_CRCX_MSC),
887 .action = gscon_fsm_wait_mdcx_bts,
888 },
Harald Welte3561bd42018-01-28 03:04:16 +0100889 [ST_WAIT_CRCX_MSC] = {
Harald Weltee9903fd2018-03-17 17:13:10 +0100890 .name = OSMO_STRINGIFY(WAIT_CRCX_MSC),
891 .in_event_mask = EV_TRANSPARENT_SCCP | S(GSCON_EV_MGW_CRCX_RESP_MSC),
892 .out_state_mask = S(ST_ACTIVE),
893 .action = gscon_fsm_wait_crcx_msc,
894 },
Harald Welte3561bd42018-01-28 03:04:16 +0100895 [ST_WAIT_MODE_MODIFY_ACK] = {
Harald Weltee9903fd2018-03-17 17:13:10 +0100896 .name = OSMO_STRINGIFY(WAIT_MODE_MODIFY_ACK),
897 .in_event_mask = EV_TRANSPARENT_SCCP | S(GSCON_EV_RR_MODE_MODIFY_ACK),
898 .out_state_mask = S(ST_ACTIVE) | S(ST_CLEARING),
899 .action = gscon_fsm_wait_mode_modify_ack,
900 },
Harald Welte3561bd42018-01-28 03:04:16 +0100901 [ST_CLEARING] = {
Harald Weltee9903fd2018-03-17 17:13:10 +0100902 .name = OSMO_STRINGIFY(CLEARING),
903 .in_event_mask = S(GSCON_EV_RSL_CLEAR_COMPL),
904 .action = gscon_fsm_clearing,
905 },
Harald Welte3561bd42018-01-28 03:04:16 +0100906
907 /* TODO: external handover, probably it makes sense to break up the
908 * program flow in handover_logic.c a bit and handle some of the logic
909 * here? */
910 [ST_WAIT_MT_HO_ACC] = {
Harald Weltee9903fd2018-03-17 17:13:10 +0100911 .name = OSMO_STRINGIFY(WAIT_MT_HO_ACC),
912 },
Harald Welte3561bd42018-01-28 03:04:16 +0100913 [ST_WAIT_MT_HO_COMPL] = {
Harald Weltee9903fd2018-03-17 17:13:10 +0100914 .name = OSMO_STRINGIFY(WAIT_MT_HO_COMPL),
915 },
Harald Welte3561bd42018-01-28 03:04:16 +0100916 [ST_WAIT_MO_HO_CMD] = {
Harald Weltee9903fd2018-03-17 17:13:10 +0100917 .name = OSMO_STRINGIFY(WAIT_MO_HO_CMD),
918 },
Harald Welte3561bd42018-01-28 03:04:16 +0100919 [ST_MO_HO_PROCEEDING] = {
Harald Weltee9903fd2018-03-17 17:13:10 +0100920 .name = OSMO_STRINGIFY(MO_HO_PROCEEDING),
921 },
Harald Welte3561bd42018-01-28 03:04:16 +0100922
923 /* Internal handover */
924 [ST_WAIT_HO_COMPL] = {
Harald Weltee9903fd2018-03-17 17:13:10 +0100925 .name = OSMO_STRINGIFY(WAIT_HO_COMPL),
926 .in_event_mask = S(GSCON_EV_HO_COMPL) | S(GSCON_EV_HO_FAIL) | S(GSCON_EV_HO_TIMEOUT),
Philipp Maierecb03082018-03-26 12:05:48 +0200927 .out_state_mask = S(ST_ACTIVE) | S(ST_WAIT_MDCX_BTS_HO) | S(ST_CLEARING),
Harald Weltee9903fd2018-03-17 17:13:10 +0100928 .action = gscon_fsm_wait_ho_compl,
929 },
Harald Welte3561bd42018-01-28 03:04:16 +0100930 [ST_WAIT_MDCX_BTS_HO] = {
Harald Weltee9903fd2018-03-17 17:13:10 +0100931 .name = OSMO_STRINGIFY(WAIT_MDCX_BTS_HO),
932 .in_event_mask = EV_TRANSPARENT_SCCP | S(GSCON_EV_MGW_MDCX_RESP_BTS),
933 .action = gscon_fsm_wait_mdcx_bts_ho,
934 .out_state_mask = S(ST_ACTIVE),
935 },
Harald Welte3561bd42018-01-28 03:04:16 +0100936};
937
938static void gscon_fsm_allstate(struct osmo_fsm_inst *fi, uint32_t event, void *data)
939{
940 struct gsm_subscriber_connection *conn = fi->priv;
941 struct msgb *resp = NULL;
942
943 /* When a connection on the MGW fails, make sure that the reference
944 * in our book-keeping is erased. */
945 switch (event) {
946 case GSCON_EV_MGW_FAIL_BTS:
947 conn->user_plane.fi_bts = NULL;
948 break;
949 case GSCON_EV_MGW_FAIL_MSC:
950 conn->user_plane.fi_msc = NULL;
951 break;
952 }
953
954 /* Regular allstate event processing */
955 switch (event) {
956 case GSCON_EV_MGW_FAIL_BTS:
957 case GSCON_EV_MGW_FAIL_MSC:
958 /* Note: An MGW connection die per definition at any time.
959 * However, if it dies during the assignment we must return
960 * with an assignment failure */
Philipp Maier70fcde62018-03-21 11:17:32 +0100961 OSMO_ASSERT(fi->state != ST_INIT && fi->state != ST_WAIT_CC);
962 if (fi->state == ST_WAIT_CRCX_BTS || fi->state == ST_WAIT_ASS_CMPL || fi->state == ST_WAIT_MDCX_BTS
963 || fi->state == ST_WAIT_CRCX_MSC) {
Harald Welte3561bd42018-01-28 03:04:16 +0100964 resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_EQUIPMENT_FAILURE, NULL);
965 sigtran_send(conn, resp, fi);
966 osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0);
967 }
968 break;
969 case GSCON_EV_A_CLEAR_CMD:
970 /* MSC tells us to cleanly shut down */
971 osmo_fsm_inst_state_chg(fi, ST_CLEARING, 0, 0);
972 gsm0808_clear(conn);
973 /* FIXME: Release all terestrial resources in ST_CLEARING */
974 /* According to 3GPP 48.008 3.1.9.1. "The BSS need not wait for the radio channel
975 * release to be completed or for the guard timer to expire before returning the
976 * CLEAR COMPLETE message" */
977
978 /* Close MGCP connections */
979 toss_mgcp_conn(conn, fi);
980
981 /* FIXME: Question: Is this a hack to force a clear complete from internel?
982 * nobody seems to send the event from outside? */
983 osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_RSL_CLEAR_COMPL, NULL);
984 break;
985 case GSCON_EV_A_DISC_IND:
986 /* MSC or SIGTRAN network has hard-released SCCP connection,
987 * terminate the FSM now. */
988 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, data);
989 break;
990 case GSCON_EV_RLL_REL_IND:
991 /* BTS reports that one of the LAPDm data links was released */
992 /* send proper clear request to MSC */
993 LOGPFSML(fi, LOGL_DEBUG, "Tx BSSMAP CLEAR REQUEST to MSC\n");
994 resp = gsm0808_create_clear_rqst(GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE);
995 sigtran_send(conn, resp, fi);
996 break;
997 case GSCON_EV_RSL_CONN_FAIL:
998 LOGPFSML(fi, LOGL_DEBUG, "Tx BSSMAP CLEAR REQUEST to MSC\n");
999 resp = gsm0808_create_clear_rqst(GSM0808_CAUSE_RADIO_INTERFACE_FAILURE);
1000 sigtran_send(conn, resp, fi);
1001 break;
1002 default:
1003 OSMO_ASSERT(false);
1004 break;
1005 }
1006}
1007
1008void ho_dtap_cache_flush(struct gsm_subscriber_connection *conn, int send);
1009
1010static void gscon_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
1011{
1012 struct gsm_subscriber_connection *conn = fi->priv;
1013
1014 if (conn->ho) {
1015 LOGPFSML(fi, LOGL_DEBUG, "Releasing handover state\n");
1016 bsc_clear_handover(conn, 1);
1017 conn->ho = NULL;
1018 }
1019
1020 if (conn->secondary_lchan) {
1021 LOGPFSML(fi, LOGL_DEBUG, "Releasing secondary_lchan\n");
1022 lchan_release(conn->secondary_lchan, 0, RSL_REL_LOCAL_END);
1023 conn->secondary_lchan = NULL;
1024 }
1025 if (conn->lchan) {
1026 LOGPFSML(fi, LOGL_DEBUG, "Releasing lchan\n");
1027 lchan_release(conn->lchan, 0, RSL_REL_LOCAL_END);
1028 conn->lchan = NULL;
1029 }
1030
1031 if (conn->bsub) {
1032 LOGPFSML(fi, LOGL_DEBUG, "Putting bsc_subscr\n");
1033 bsc_subscr_put(conn->bsub);
1034 conn->bsub = NULL;
1035 }
1036
1037 if (conn->sccp.state != SUBSCR_SCCP_ST_NONE) {
1038 LOGPFSML(fi, LOGL_DEBUG, "Disconnecting SCCP\n");
1039 struct bsc_msc_data *msc = conn->sccp.msc;
1040 /* FIXME: include a proper cause value / error message? */
1041 osmo_sccp_tx_disconn(msc->a.sccp_user, conn->sccp.conn_id, &msc->a.bsc_addr, 0);
1042 conn->sccp.state = SUBSCR_SCCP_ST_NONE;
1043 }
1044
1045 /* drop pending messages */
1046 ho_dtap_cache_flush(conn, 0);
1047
1048 penalty_timers_free(&conn->hodec2.penalty_timers);
1049
1050 llist_del(&conn->entry);
1051 talloc_free(conn);
1052 fi->priv = NULL;
1053}
1054
1055static void gscon_pre_term(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
1056{
1057 struct gsm_subscriber_connection *conn = fi->priv;
1058
1059 /* Make sure all possibly still open MGCP connections get closed */
1060 toss_mgcp_conn(conn, fi);
1061}
1062
1063static int gscon_timer_cb(struct osmo_fsm_inst *fi)
1064{
1065 struct gsm_subscriber_connection *conn = fi->priv;
1066 struct msgb *resp = NULL;
1067
1068 switch (fi->T) {
1069 case 993210:
Philipp Maier3ddb12d2018-04-13 16:47:26 +02001070 /* MSC has not responded/confirmed connection with CC, this
1071 * could indicate a bad SCCP connection. We now inform the the
1072 * FSM that controls the BSSMAP reset about the event. Maybe
1073 * a BSSMAP reset is necessary. */
1074 a_reset_conn_fail(conn->sccp.msc->a.reset);
1075
1076 /* Since we could not reach the MSC, we give up and terminate
1077 * the FSM instance now (N-DISCONNET.req is sent in
1078 * gscon_cleanup() above) */
Harald Welte3561bd42018-01-28 03:04:16 +01001079 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
1080 break;
1081 case GSM0808_T10_TIMER_NR: /* Assignment Failed */
1082 resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_RADIO_INTERFACE_FAILURE, NULL);
1083 sigtran_send(conn, resp, fi);
1084 osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0);
1085 break;
1086 case MGCP_MGW_TIMEOUT_TIMER_NR: /* Assignment failed (no response from MGW) */
1087 resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_EQUIPMENT_FAILURE, NULL);
1088 sigtran_send(conn, resp, fi);
1089 osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0);
1090 break;
1091 case MGCP_MGW_HO_TIMEOUT_TIMER_NR: /* Handover failed (no response from MGW) */
1092 osmo_fsm_inst_state_chg(fi, ST_ACTIVE, 0, 0);
1093 break;
1094 default:
1095 OSMO_ASSERT(false);
1096 }
1097 return 0;
1098}
1099
1100static struct osmo_fsm gscon_fsm = {
1101 .name = "SUBSCR_CONN",
1102 .states = gscon_fsm_states,
1103 .num_states = ARRAY_SIZE(gscon_fsm_states),
1104 .allstate_event_mask = S(GSCON_EV_A_DISC_IND) | S(GSCON_EV_A_CLEAR_CMD) | S(GSCON_EV_RSL_CONN_FAIL) |
1105 S(GSCON_EV_RLL_REL_IND) | S(GSCON_EV_MGW_FAIL_BTS) | S(GSCON_EV_MGW_FAIL_MSC),
1106 .allstate_action = gscon_fsm_allstate,
1107 .cleanup = gscon_cleanup,
1108 .pre_term = gscon_pre_term,
1109 .timer_cb = gscon_timer_cb,
1110 .log_subsys = DMSC,
1111 .event_names = gscon_fsm_event_names,
1112};
1113
1114/* Allocate a subscriber connection and its associated FSM */
1115struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_network *net)
1116{
1117 struct gsm_subscriber_connection *conn;
1118 static bool g_initialized = false;
1119
1120 if (!g_initialized) {
1121 osmo_fsm_register(&gscon_fsm);
1122 g_initialized = true;
1123 }
1124
1125 conn = talloc_zero(net, struct gsm_subscriber_connection);
1126 if (!conn)
1127 return NULL;
1128
1129 conn->network = net;
1130 INIT_LLIST_HEAD(&conn->ho_dtap_cache);
1131 /* BTW, penalty timers will be initialized on-demand. */
1132 conn->sccp.conn_id = -1;
1133
1134 /* don't allocate from 'conn' context, as gscon_cleanup() will call talloc_free(conn) before
1135 * libosmocore will call talloc_free(conn->fi), i.e. avoid use-after-free during cleanup */
1136 conn->fi = osmo_fsm_inst_alloc(&gscon_fsm, net, conn, LOGL_NOTICE, NULL);
1137 if (!conn->fi) {
1138 talloc_free(conn);
1139 return NULL;
1140 }
1141
1142 llist_add_tail(&conn->entry, &net->subscr_conns);
1143 return conn;
1144}