blob: 5629d26f9a81c9e707bbbc03963f1bad4ee557f7 [file] [log] [blame]
Harald Welteb8b85a12016-06-17 00:06:42 +02001/* MSC subscriber connection implementation */
2
3/*
4 * (C) 2016 by sysmocom s.m.f.c. <info@sysmocom.de>
5 * All Rights Reserved
6 *
7 * Author: Neels Hofmeyr
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Affero General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Affero General Public License for more details.
18 *
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24#include <osmocom/core/logging.h>
25#include <osmocom/core/fsm.h>
Harald Welte2483f1b2016-06-19 18:06:02 +020026#include <osmocom/core/signal.h>
Harald Welteb8b85a12016-06-17 00:06:42 +020027
Neels Hofmeyr90843962017-09-04 15:04:35 +020028#include <osmocom/msc/osmo_msc.h>
29#include <osmocom/msc/vlr.h>
30#include <osmocom/msc/debug.h>
31#include <osmocom/msc/transaction.h>
32#include <osmocom/msc/signal.h>
33#include <osmocom/msc/a_iface.h>
Daniel Willmann4e825b62018-02-15 10:33:26 +010034#include <osmocom/msc/iucs.h>
Philipp Maierfbf66102017-04-09 12:32:51 +020035
Harald Welte2483f1b2016-06-19 18:06:02 +020036#define SUBSCR_CONN_TIMEOUT 5 /* seconds */
Harald Welteb8b85a12016-06-17 00:06:42 +020037
38static const struct value_string subscr_conn_fsm_event_names[] = {
39 OSMO_VALUE_STRING(SUBSCR_CONN_E_INVALID),
Harald Welte2483f1b2016-06-19 18:06:02 +020040 OSMO_VALUE_STRING(SUBSCR_CONN_E_START),
Harald Welteb8b85a12016-06-17 00:06:42 +020041 OSMO_VALUE_STRING(SUBSCR_CONN_E_ACCEPTED),
Harald Welte2483f1b2016-06-19 18:06:02 +020042 OSMO_VALUE_STRING(SUBSCR_CONN_E_COMMUNICATING),
Neels Hofmeyre9e2f5c2018-03-15 13:26:43 +010043 OSMO_VALUE_STRING(SUBSCR_CONN_E_RELEASE_WHEN_UNUSED),
Harald Welteb8b85a12016-06-17 00:06:42 +020044 OSMO_VALUE_STRING(SUBSCR_CONN_E_MO_CLOSE),
45 OSMO_VALUE_STRING(SUBSCR_CONN_E_CN_CLOSE),
Harald Welteb8b85a12016-06-17 00:06:42 +020046 { 0, NULL }
47};
48
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020049static void paging_event(struct gsm_subscriber_connection *conn,
50 enum gsm_paging_event pe)
Harald Welteb8b85a12016-06-17 00:06:42 +020051{
Harald Welte2483f1b2016-06-19 18:06:02 +020052 subscr_paging_dispatch(GSM_HOOK_RR_PAGING, pe, NULL, conn, conn->vsub);
53}
54
55void subscr_conn_fsm_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
56{
57 OSMO_ASSERT(event == SUBSCR_CONN_E_START);
58 osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_NEW,
59 SUBSCR_CONN_TIMEOUT, 0);
Harald Welteb8b85a12016-06-17 00:06:42 +020060}
61
62void subscr_conn_fsm_new(struct osmo_fsm_inst *fi, uint32_t event, void *data)
63{
64 struct gsm_subscriber_connection *conn = fi->priv;
Harald Welte2483f1b2016-06-19 18:06:02 +020065 bool success;
Harald Welteb8b85a12016-06-17 00:06:42 +020066
Harald Welteb8b85a12016-06-17 00:06:42 +020067 /* If accepted, transition the state, all other cases mean failure. */
68 switch (event) {
69 case SUBSCR_CONN_E_ACCEPTED:
Harald Welte2483f1b2016-06-19 18:06:02 +020070 osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_ACCEPTED,
71 SUBSCR_CONN_TIMEOUT, 0);
Harald Welteb8b85a12016-06-17 00:06:42 +020072 break;
73
74 case SUBSCR_CONN_E_MO_CLOSE:
75 case SUBSCR_CONN_E_CN_CLOSE:
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020076 if (data)
77 LOGPFSM(fi, "Close event, cause %u\n",
78 *(uint32_t*)data);
79 /* will release further below, see
80 * 'if (fi->state != SUBSCR_CONN_S_ACCEPTED)' */
Harald Welteb8b85a12016-06-17 00:06:42 +020081 break;
82
83 default:
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020084 LOGPFSML(fi, LOGL_ERROR,
85 "Unexpected event: %d %s\n", event,
86 osmo_fsm_event_name(fi->fsm, event));
Harald Welteb8b85a12016-06-17 00:06:42 +020087 break;
88 }
89
Harald Welte2483f1b2016-06-19 18:06:02 +020090 success = (fi->state == SUBSCR_CONN_S_ACCEPTED);
91
Neels Hofmeyr16c42b52018-04-02 12:26:16 +020092 if (conn->complete_layer3_type == COMPLETE_LAYER3_LU)
Harald Welte2483f1b2016-06-19 18:06:02 +020093 rate_ctr_inc(&conn->network->msc_ctrs->ctr[
94 success ? MSC_CTR_LOC_UPDATE_COMPLETED
95 : MSC_CTR_LOC_UPDATE_FAILED]);
96
97 /* signal paging success or failure in case this was a paging */
Neels Hofmeyr16c42b52018-04-02 12:26:16 +020098 if (conn->complete_layer3_type == COMPLETE_LAYER3_PAGING_RESP)
Neels Hofmeyr84da6b12016-05-20 21:59:55 +020099 paging_event(conn,
100 success ? GSM_PAGING_SUCCEEDED
101 : GSM_PAGING_EXPIRED);
102
103 /* FIXME rate counters */
104 /*rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_COMPLETED]);*/
Harald Welteb8b85a12016-06-17 00:06:42 +0200105
106 /* On failure, discard the conn */
Harald Welte2483f1b2016-06-19 18:06:02 +0200107 if (!success) {
Harald Welteb8b85a12016-06-17 00:06:42 +0200108 /* TODO: on MO_CLOSE or CN_CLOSE, first go to RELEASING and
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200109 * await BSC/RNC confirmation? */
Harald Welteb8b85a12016-06-17 00:06:42 +0200110 osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_RELEASED, 0, 0);
111 return;
112 }
113
Neels Hofmeyr16c42b52018-04-02 12:26:16 +0200114 if (conn->complete_layer3_type == COMPLETE_LAYER3_CM_SERVICE_REQ) {
Harald Welteb8b85a12016-06-17 00:06:42 +0200115 conn->received_cm_service_request = true;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200116 LOGPFSML(fi, LOGL_DEBUG, "received_cm_service_request = true\n");
Harald Welteb8b85a12016-06-17 00:06:42 +0200117 }
118
Neels Hofmeyre9e2f5c2018-03-15 13:26:43 +0100119 osmo_fsm_inst_dispatch(fi, SUBSCR_CONN_E_RELEASE_WHEN_UNUSED, data);
Harald Welteb8b85a12016-06-17 00:06:42 +0200120}
121
Neels Hofmeyre9e2f5c2018-03-15 13:26:43 +0100122static void subscr_conn_fsm_release_when_unused(struct osmo_fsm_inst *fi, uint32_t event, void *data)
Harald Welteb8b85a12016-06-17 00:06:42 +0200123{
124 struct gsm_subscriber_connection *conn = fi->priv;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200125 struct gsm_trans *trans;
Harald Welteb8b85a12016-06-17 00:06:42 +0200126
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200127 if (conn->silent_call) {
Neels Hofmeyre9e2f5c2018-03-15 13:26:43 +0100128 LOGPFSML(fi, LOGL_DEBUG, "%s: silent call still active\n", __func__);
Harald Welteb8b85a12016-06-17 00:06:42 +0200129 return;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200130 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200131
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200132 if (conn->received_cm_service_request) {
Neels Hofmeyre9e2f5c2018-03-15 13:26:43 +0100133 LOGPFSML(fi, LOGL_DEBUG, "%s: still awaiting first request after a CM Service Request\n",
134 __func__);
Harald Welteb8b85a12016-06-17 00:06:42 +0200135 return;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200136 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200137
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200138 if (conn->vsub && !llist_empty(&conn->vsub->cs.requests)) {
139 struct subscr_request *sr;
140 if (!log_check_level(fi->fsm->log_subsys, LOGL_DEBUG)) {
141 llist_for_each_entry(sr, &conn->vsub->cs.requests, entry) {
Neels Hofmeyre9e2f5c2018-03-15 13:26:43 +0100142 LOGPFSML(fi, LOGL_DEBUG, "%s: still active: %s\n",
143 __func__, sr->label);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200144 }
145 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200146 return;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200147 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200148
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200149 if ((trans = trans_has_conn(conn))) {
150 LOGPFSML(fi, LOGL_DEBUG,
Neels Hofmeyre9e2f5c2018-03-15 13:26:43 +0100151 "%s: connection still has active transaction: %s\n",
152 __func__, gsm48_pdisc_name(trans->protocol));
Harald Welteb8b85a12016-06-17 00:06:42 +0200153 return;
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200154 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200155
Neels Hofmeyre9e2f5c2018-03-15 13:26:43 +0100156 LOGPFSML(fi, LOGL_DEBUG, "%s: releasing conn\n", __func__);
Harald Welteb8b85a12016-06-17 00:06:42 +0200157 osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_RELEASED, 0, 0);
158}
159
Harald Welte2483f1b2016-06-19 18:06:02 +0200160static void subscr_conn_fsm_accepted_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
161{
162 struct gsm_subscriber_connection *conn = fi->priv;
163 osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_ATTACHED, conn->vsub);
164}
165
Harald Welteb8b85a12016-06-17 00:06:42 +0200166static void subscr_conn_fsm_accepted(struct osmo_fsm_inst *fi, uint32_t event, void *data)
167{
168 switch (event) {
Harald Welte2483f1b2016-06-19 18:06:02 +0200169 case SUBSCR_CONN_E_COMMUNICATING:
170 osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_COMMUNICATING, 0, 0);
171 return;
172
Neels Hofmeyre9e2f5c2018-03-15 13:26:43 +0100173 case SUBSCR_CONN_E_RELEASE_WHEN_UNUSED:
174 subscr_conn_fsm_release_when_unused(fi, event, data);
Harald Welteb8b85a12016-06-17 00:06:42 +0200175 return;
176
177 default:
178 break;
179 }
180 /* Whatever unexpected happens in the accepted state, it means release.
181 * Even if an unexpected event is passed, the safest thing to do is
182 * discard the conn. We don't expect another SUBSCR_CONN_E_ACCEPTED. */
183 osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_RELEASED, 0, 0);
184}
185
Harald Welte2483f1b2016-06-19 18:06:02 +0200186static void subscr_conn_fsm_communicating(struct osmo_fsm_inst *fi, uint32_t event, void *data)
187{
188 switch (event) {
189 case SUBSCR_CONN_E_COMMUNICATING:
190 /* no-op */
191 return;
192
Neels Hofmeyre9e2f5c2018-03-15 13:26:43 +0100193 case SUBSCR_CONN_E_RELEASE_WHEN_UNUSED:
194 subscr_conn_fsm_release_when_unused(fi, event, data);
Harald Welte2483f1b2016-06-19 18:06:02 +0200195 return;
196
197 default:
198 break;
199 }
200 /* Whatever unexpected happens in the accepted state, it means release.
201 * Even if an unexpected event is passed, the safest thing to do is
202 * discard the conn. We don't expect another SUBSCR_CONN_E_ACCEPTED. */
203 osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_RELEASED, 0, 0);
204}
205
206static void subscr_conn_fsm_cleanup(struct osmo_fsm_inst *fi,
207 enum osmo_fsm_term_cause cause)
Harald Welteb8b85a12016-06-17 00:06:42 +0200208{
209 struct gsm_subscriber_connection *conn = fi->priv;
Harald Welte2483f1b2016-06-19 18:06:02 +0200210 fi->priv = NULL;
211
Harald Welteb8b85a12016-06-17 00:06:42 +0200212 if (!conn)
213 return;
Neels Hofmeyr4d3a66b2018-03-31 18:45:59 +0200214 conn->fi = NULL;
Harald Welte2483f1b2016-06-19 18:06:02 +0200215 msc_subscr_conn_close(conn, cause);
Neels Hofmeyr6166f292017-11-22 14:33:12 +0100216 msc_subscr_conn_put(conn, MSC_CONN_USE_FSM);
Harald Welte2483f1b2016-06-19 18:06:02 +0200217}
Harald Welteb8b85a12016-06-17 00:06:42 +0200218
Harald Welte2483f1b2016-06-19 18:06:02 +0200219int subscr_conn_fsm_timeout(struct osmo_fsm_inst *fi)
220{
221 struct gsm_subscriber_connection *conn = fi->priv;
222 if (conn)
223 vlr_subscr_conn_timeout(conn->vsub);
Neels Hofmeyr3ddd7422017-11-18 23:25:41 +0100224 else
225 osmo_fsm_inst_dispatch(fi, SUBSCR_CONN_E_CN_CLOSE, NULL);
Harald Welte2483f1b2016-06-19 18:06:02 +0200226 return 0;
227}
228
229static void subscr_conn_fsm_release(struct osmo_fsm_inst *fi, uint32_t prev_state)
230{
231 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
Harald Welteb8b85a12016-06-17 00:06:42 +0200232}
233
234#define S(x) (1 << (x))
235
236static const struct osmo_fsm_state subscr_conn_fsm_states[] = {
Harald Welte2483f1b2016-06-19 18:06:02 +0200237 [SUBSCR_CONN_S_INIT] = {
238 .name = OSMO_STRINGIFY(SUBSCR_CONN_S_INIT),
239 .in_event_mask = S(SUBSCR_CONN_E_START),
240 .out_state_mask = S(SUBSCR_CONN_S_NEW),
241 .action = subscr_conn_fsm_init,
242 },
Harald Welteb8b85a12016-06-17 00:06:42 +0200243 [SUBSCR_CONN_S_NEW] = {
244 .name = OSMO_STRINGIFY(SUBSCR_CONN_S_NEW),
245 .in_event_mask = S(SUBSCR_CONN_E_ACCEPTED) |
246 S(SUBSCR_CONN_E_MO_CLOSE) |
Harald Welte2483f1b2016-06-19 18:06:02 +0200247 S(SUBSCR_CONN_E_CN_CLOSE),
Harald Welteb8b85a12016-06-17 00:06:42 +0200248 .out_state_mask = S(SUBSCR_CONN_S_ACCEPTED) |
249 S(SUBSCR_CONN_S_RELEASED),
250 .action = subscr_conn_fsm_new,
251 },
252 [SUBSCR_CONN_S_ACCEPTED] = {
253 .name = OSMO_STRINGIFY(SUBSCR_CONN_S_ACCEPTED),
254 /* allow everything to release for any odd behavior */
Harald Welte2483f1b2016-06-19 18:06:02 +0200255 .in_event_mask = S(SUBSCR_CONN_E_COMMUNICATING) |
Neels Hofmeyre9e2f5c2018-03-15 13:26:43 +0100256 S(SUBSCR_CONN_E_RELEASE_WHEN_UNUSED) |
Harald Welte2483f1b2016-06-19 18:06:02 +0200257 S(SUBSCR_CONN_E_ACCEPTED) |
Harald Welteb8b85a12016-06-17 00:06:42 +0200258 S(SUBSCR_CONN_E_MO_CLOSE) |
Harald Welte2483f1b2016-06-19 18:06:02 +0200259 S(SUBSCR_CONN_E_CN_CLOSE),
260 .out_state_mask = S(SUBSCR_CONN_S_RELEASED) |
261 S(SUBSCR_CONN_S_COMMUNICATING),
262 .onenter = subscr_conn_fsm_accepted_enter,
Harald Welteb8b85a12016-06-17 00:06:42 +0200263 .action = subscr_conn_fsm_accepted,
264 },
Harald Welte2483f1b2016-06-19 18:06:02 +0200265 [SUBSCR_CONN_S_COMMUNICATING] = {
266 .name = OSMO_STRINGIFY(SUBSCR_CONN_S_COMMUNICATING),
267 /* allow everything to release for any odd behavior */
Neels Hofmeyre9e2f5c2018-03-15 13:26:43 +0100268 .in_event_mask = S(SUBSCR_CONN_E_RELEASE_WHEN_UNUSED) |
Harald Welte2483f1b2016-06-19 18:06:02 +0200269 S(SUBSCR_CONN_E_ACCEPTED) |
270 S(SUBSCR_CONN_E_COMMUNICATING) |
271 S(SUBSCR_CONN_E_MO_CLOSE) |
272 S(SUBSCR_CONN_E_CN_CLOSE),
273 .out_state_mask = S(SUBSCR_CONN_S_RELEASED),
274 .action = subscr_conn_fsm_communicating,
275 },
Harald Welteb8b85a12016-06-17 00:06:42 +0200276 [SUBSCR_CONN_S_RELEASED] = {
277 .name = OSMO_STRINGIFY(SUBSCR_CONN_S_RELEASED),
278 .onenter = subscr_conn_fsm_release,
279 },
280};
281
282static struct osmo_fsm subscr_conn_fsm = {
283 .name = "Subscr_Conn",
284 .states = subscr_conn_fsm_states,
285 .num_states = ARRAY_SIZE(subscr_conn_fsm_states),
286 .allstate_event_mask = 0,
287 .allstate_action = NULL,
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200288 .log_subsys = DMM,
Harald Welteb8b85a12016-06-17 00:06:42 +0200289 .event_names = subscr_conn_fsm_event_names,
Harald Welte2483f1b2016-06-19 18:06:02 +0200290 .cleanup = subscr_conn_fsm_cleanup,
291 .timer_cb = subscr_conn_fsm_timeout,
Harald Welteb8b85a12016-06-17 00:06:42 +0200292};
293
Daniel Willmann4e825b62018-02-15 10:33:26 +0100294char *msc_subscr_conn_get_conn_id(struct gsm_subscriber_connection *conn)
295{
296 char *id;
297
298 switch (conn->via_ran) {
299 case RAN_GERAN_A:
300 id = talloc_asprintf(conn, "GERAN_A-%08x", conn->a.conn_id);
301 break;
302 case RAN_UTRAN_IU:
303 id = talloc_asprintf(conn, "UTRAN_IU-%08x", iu_get_conn_id(conn->iu.ue_ctx));
304 break;
305 default:
306 LOGP(DMM, LOGL_ERROR, "RAN of conn %p unknown!\n", conn);
307 return NULL;
308 }
309
310 return id;
311}
312
Harald Welteb8b85a12016-06-17 00:06:42 +0200313int msc_create_conn_fsm(struct gsm_subscriber_connection *conn, const char *id)
314{
315 struct osmo_fsm_inst *fi;
316 OSMO_ASSERT(conn);
317
Neels Hofmeyr4d3a66b2018-03-31 18:45:59 +0200318 if (conn->fi) {
Harald Welteb8b85a12016-06-17 00:06:42 +0200319 LOGP(DMM, LOGL_ERROR,
320 "%s: Error: connection already in use\n", id);
321 return -EINVAL;
322 }
323
Harald Welte2483f1b2016-06-19 18:06:02 +0200324 /* Allocate the FSM not with the subscr_conn. Semantically it would
325 * make sense, but in subscr_conn_fsm_cleanup(), we want to discard the
326 * subscriber connection. If the FSM is freed along with the subscriber
327 * connection, then in _osmo_fsm_inst_term() the osmo_fsm_inst_free()
328 * that follows the cleanup() call would run into a double free. */
329 fi = osmo_fsm_inst_alloc(&subscr_conn_fsm, conn->network,
Neels Hofmeyr6166f292017-11-22 14:33:12 +0100330 msc_subscr_conn_get(conn, MSC_CONN_USE_FSM),
Harald Welte2483f1b2016-06-19 18:06:02 +0200331 LOGL_DEBUG, id);
Harald Welteb8b85a12016-06-17 00:06:42 +0200332
333 if (!fi) {
334 LOGP(DMM, LOGL_ERROR,
335 "%s: Failed to allocate subscr conn master FSM\n", id);
336 return -ENOMEM;
337 }
Neels Hofmeyr4d3a66b2018-03-31 18:45:59 +0200338 conn->fi = fi;
339 osmo_fsm_inst_dispatch(conn->fi, SUBSCR_CONN_E_START, NULL);
Harald Welteb8b85a12016-06-17 00:06:42 +0200340 return 0;
341}
342
Maxd83b17b2018-02-06 16:51:31 +0100343bool msc_subscr_conn_is_accepted(const struct gsm_subscriber_connection *conn)
Harald Welteb8b85a12016-06-17 00:06:42 +0200344{
345 if (!conn)
346 return false;
Harald Welte2483f1b2016-06-19 18:06:02 +0200347 if (!conn->vsub)
Harald Welteb8b85a12016-06-17 00:06:42 +0200348 return false;
Neels Hofmeyr4d3a66b2018-03-31 18:45:59 +0200349 if (!conn->fi)
Harald Welteb8b85a12016-06-17 00:06:42 +0200350 return false;
Neels Hofmeyr4d3a66b2018-03-31 18:45:59 +0200351 if (!(conn->fi->state == SUBSCR_CONN_S_ACCEPTED
352 || conn->fi->state == SUBSCR_CONN_S_COMMUNICATING))
Harald Welteb8b85a12016-06-17 00:06:42 +0200353 return false;
354 return true;
355}
356
Harald Welte2483f1b2016-06-19 18:06:02 +0200357void msc_subscr_conn_communicating(struct gsm_subscriber_connection *conn)
358{
359 OSMO_ASSERT(conn);
Neels Hofmeyrd6a769b2018-03-12 23:59:07 +0100360 /* This function is called to indicate that *some* communication is happening with the phone.
361 * Late in the process, that may be a Release Confirm and the FSM and conn are already in
362 * teardown. No need to signal SUBSCR_CONN_E_COMMUNICATING then. */
Neels Hofmeyr4d3a66b2018-03-31 18:45:59 +0200363 if (conn->fi)
364 osmo_fsm_inst_dispatch(conn->fi, SUBSCR_CONN_E_COMMUNICATING, NULL);
Harald Welte2483f1b2016-06-19 18:06:02 +0200365}
366
Harald Welteb8b85a12016-06-17 00:06:42 +0200367void msc_subscr_conn_init(void)
368{
369 osmo_fsm_register(&subscr_conn_fsm);
370}
Neels Hofmeyr16c42b52018-04-02 12:26:16 +0200371
Neels Hofmeyr93c74632018-04-02 23:10:28 +0200372/* Allocate a new subscriber conn. */
373struct gsm_subscriber_connection *msc_subscr_conn_alloc(struct gsm_network *network,
374 enum ran_type via_ran, uint16_t lac)
375{
376 struct gsm_subscriber_connection *conn;
377
378 conn = talloc_zero(network, struct gsm_subscriber_connection);
379 if (!conn)
380 return NULL;
381
382 *conn = (struct gsm_subscriber_connection){
383 .network = network,
384 .via_ran = via_ran,
385 .lac = lac,
386 };
387
388 llist_add_tail(&conn->entry, &network->subscr_conns);
389 return conn;
390}
391
Neels Hofmeyr16c42b52018-04-02 12:26:16 +0200392const struct value_string complete_layer3_type_names[] = {
393 { COMPLETE_LAYER3_NONE, "NONE" },
394 { COMPLETE_LAYER3_LU, "LU" },
395 { COMPLETE_LAYER3_CM_SERVICE_REQ, "CM_SERVICE_REQ" },
396 { COMPLETE_LAYER3_PAGING_RESP, "PAGING_RESP" },
397 { 0, NULL }
398};
399
400void msc_subscr_conn_update_id(struct gsm_subscriber_connection *conn,
401 enum complete_layer3_type from, const char *id)
402{
403 conn->complete_layer3_type = from;
404 osmo_fsm_inst_update_id(conn->fi, id);
405 LOGPFSML(conn->fi, LOGL_DEBUG, "Updated ID from %s\n", complete_layer3_type_name(from));
406}