blob: c821c1cbd5ad1f32dd0c00293a79a6b43c7251e9 [file] [log] [blame]
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001/* Manage all MSC roles of a connected subscriber (MSC-A, MSC-I, MSC-T) */
2/*
Vadim Yanitskiy999a5932023-05-18 17:22:26 +07003 * (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01004 * All Rights Reserved
5 *
6 * SPDX-License-Identifier: AGPL-3.0+
7 *
8 * Author: Neels Hofmeyr
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Affero General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Affero General Public License for more details.
19 *
20 * You should have received a copy of the GNU Affero General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24#include <osmocom/gsm/gsm48.h>
25
26#include <osmocom/msc/msub.h>
27#include <osmocom/msc/msc_roles.h>
28#include <osmocom/msc/msc_a.h>
29#include <osmocom/msc/msc_i.h>
30#include <osmocom/msc/msc_t.h>
Alexander Couzens7900a052024-08-27 16:17:39 +020031#include <osmocom/msc/ran_conn.h>
Alexander Couzenseff28ab2024-09-12 00:55:25 +020032#include <osmocom/vlr/vlr.h>
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010033#include <osmocom/msc/e_link.h>
34
35const struct value_string msc_role_names[] = {
36 { MSC_ROLE_A, "MSC-A" },
37 { MSC_ROLE_I, "MSC-I" },
38 { MSC_ROLE_T, "MSC-T" },
39 {}
40};
41
42LLIST_HEAD(msub_list);
43
44#define for_each_msub_role(msub, role_idx) \
45 for ((role_idx) = 0; (role_idx) < ARRAY_SIZE((msub)->role); (role_idx)++) \
46 if ((msub)->role[role_idx])
47
48enum msub_fsm_state {
49 MSUB_ST_ACTIVE,
50 MSUB_ST_TERMINATING,
51};
52
53enum msub_fsm_event {
54 MSUB_EV_ROLE_TERMINATED,
55};
56
57static void msub_check_for_release(struct osmo_fsm_inst *fi)
58{
59 struct msub *msub = fi->priv;
Harald Weltedb6855c2019-05-09 10:28:43 +020060 struct msc_role_common *msc_role_a_c = NULL;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010061 enum msc_role role_idx;
62 int role_present[MSC_ROLES_COUNT] = {};
63 struct osmo_fsm_inst *child;
64
65 /* See what child FSMs are still present. A caller might exchange roles by first allocating a new one as child
66 * of this FSM, and then exchanging the msub->role[] pointer. Even though the currently active role is removing
67 * itself from msub, we can still see whether another one is pending as a child of this msub. */
68 llist_for_each_entry(child, &fi->proc.children, proc.child) {
69 struct msc_role_common *c = child->priv;
70 role_present[c->role]++;
71 if (c->role == MSC_ROLE_A)
72 msc_role_a_c = c;
73 }
74
75 /* Log. */
76 for (role_idx = 0; role_idx < ARRAY_SIZE(role_present); role_idx++) {
77 if (!role_present[role_idx])
78 continue;
79 LOG_MSUB(msub, LOGL_DEBUG, "%d %s still active\n", role_present[role_idx], msc_role_name(role_idx));
80 }
81
82 /* To remain valid, there must be both an MSC-A role and one of MSC-I or MSC-T;
83 * except, SGs connections need no MSC-I or MSC-T. */
84 if (role_present[MSC_ROLE_A]
85 && (role_present[MSC_ROLE_I] || role_present[MSC_ROLE_T]
86 || (msc_role_a_c && msc_role_a_c->ran->type == OSMO_RAT_EUTRAN_SGS)))
87 return;
88
89 /* The subscriber has become invalid. Go to terminating state to clearly signal that this msub is definitely
90 * going now. */
91 osmo_fsm_inst_state_chg(fi, MSUB_ST_TERMINATING, 0, 0);
92}
93
94void msub_fsm_active(struct osmo_fsm_inst *fi, uint32_t event, void *data)
95{
96 struct msub *msub = fi->priv;
97 struct osmo_fsm_inst *role_fi;
98
99 switch (event) {
100 case MSUB_EV_ROLE_TERMINATED:
101 role_fi = data;
102 /* Role implementations are required to pass their own osmo_fsm_inst pointer to osmo_fsm_inst_term(). */
103 msub_remove_role(msub, role_fi);
104 msub_check_for_release(fi);
105 return;
106 default:
107 return;
108 }
109}
110
111void msub_fsm_terminating_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
112{
113 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
114}
115
116void msub_fsm_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
117{
118 struct msub *msub = fi->priv;
119 LOG_MSUB(msub, LOGL_DEBUG, "Free\n");
120 msub_set_vsub(msub, NULL);
121 llist_del(&msub->entry);
122}
123
124#define S(x) (1 << (x))
125
126static const struct osmo_fsm_state msub_fsm_states[] = {
127 [MSUB_ST_ACTIVE] = {
128 .name = "active",
129 .in_event_mask = S(MSUB_EV_ROLE_TERMINATED),
130 .out_state_mask = S(MSUB_ST_TERMINATING),
131 .action = msub_fsm_active,
132 },
133 [MSUB_ST_TERMINATING] = {
134 .name = "terminating",
135 .onenter = msub_fsm_terminating_onenter,
136 },
137};
138
139static const struct value_string msub_fsm_event_names[] = {
140 OSMO_VALUE_STRING(MSUB_EV_ROLE_TERMINATED),
141 {}
142};
143
144struct osmo_fsm msub_fsm = {
145 .name = "msub_fsm",
146 .states = msub_fsm_states,
147 .num_states = ARRAY_SIZE(msub_fsm_states),
148 .log_subsys = DMSC,
149 .event_names = msub_fsm_event_names,
150 .cleanup = msub_fsm_cleanup,
151};
152
153static __attribute__((constructor)) void msub_fsm_init()
154{
155 OSMO_ASSERT(osmo_fsm_register(&msub_fsm) == 0);
156}
157
158struct msc_role_common *_msub_role_alloc(struct msub *msub, enum msc_role role, struct osmo_fsm *role_fsm,
159 size_t struct_size, const char *struct_name, struct ran_infra *ran)
160{
161 struct osmo_fsm_inst *fi;
162 struct msc_role_common *c;
163
164 fi = osmo_fsm_inst_alloc_child(role_fsm, msub->fi, MSUB_EV_ROLE_TERMINATED);
165 OSMO_ASSERT(fi);
166
167 c = (struct msc_role_common*)talloc_named_const(fi, struct_size, struct_name);
168 OSMO_ASSERT(c);
169 memset(c, 0, struct_size);
170 fi->priv = c;
171
172 *c = (struct msc_role_common){
173 .role = role,
174 .fi = fi,
175 .ran = ran,
176 };
177
178 msub_set_role(msub, fi);
179 return c;
180}
181
182struct msub *msub_alloc(struct gsm_network *net)
183{
184 struct msub *msub;
185 struct osmo_fsm_inst *msub_fi = osmo_fsm_inst_alloc(&msub_fsm, net, NULL, LOGL_DEBUG, NULL);
186 OSMO_ASSERT(msub_fi);
187
188 msub = talloc(msub_fi, struct msub);
189 OSMO_ASSERT(msub);
190 msub_fi->priv = msub;
191 *msub = (struct msub){
192 .net = net,
193 .fi = msub_fi,
194 };
195
196 llist_add_tail(&msub->entry, &msub_list);
197 return msub;
198}
199
200/* Careful: the subscriber may not yet be authenticated, or may already be in release. Better use
201 * msc_a_for_vsub(for_vsub, true) to make sure you don't use an invalid conn. */
202struct msub *msub_for_vsub(const struct vlr_subscr *for_vsub)
203{
204 struct msub *msub;
205 if (!for_vsub)
206 return NULL;
207
208 llist_for_each_entry(msub, &msub_list, entry) {
209 if (msub->vsub == for_vsub)
210 return msub;
211 }
212
213 return NULL;
214}
215
216const char *msub_name(const struct msub *msub)
217{
218 return vlr_subscr_name(msub? msub->vsub : NULL);
219}
220
221void msub_set_role(struct msub *msub, struct osmo_fsm_inst *msc_role)
222{
223 struct osmo_fsm_inst *prev_role;
224 struct msc_role_common *c;
225
226 OSMO_ASSERT(msc_role);
227 c = msc_role->priv;
228
229 prev_role = msub->role[c->role];
230 if (prev_role)
231 LOGPFSML(prev_role, LOGL_DEBUG, "Replaced by another %s\n", msc_role_name(c->role));
232
233 c->msub = msub;
234 msub->role[c->role] = msc_role;
235 msub_update_id(msub);
236
237 if (prev_role) {
238 struct msc_role_common *prev_c = prev_role->priv;
239 switch (prev_c->role) {
240 case MSC_ROLE_I:
241 msc_i_clear(prev_role->priv);
242 break;
243 case MSC_ROLE_T:
244 msc_t_clear(prev_role->priv);
245 break;
246 default:
247 osmo_fsm_inst_term(prev_role, OSMO_FSM_TERM_REQUEST, prev_role);
248 break;
249 }
250 }
251}
252
253void msub_remove_role(struct msub *msub, struct osmo_fsm_inst *fi)
254{
255 enum msc_role idx;
256 struct msc_role_common *c;
257 if (!msub || !fi)
258 return;
259
260 c = fi->priv;
261 LOG_MSUB(msub, LOGL_DEBUG, "%s terminated\n", msc_role_name(c->role));
262
263 for_each_msub_role(msub, idx) {
264 if (msub->role[idx] == fi)
265 msub->role[idx] = NULL;
266 }
267}
268
269struct msc_a *msub_msc_a(const struct msub *msub)
270{
271 struct osmo_fsm_inst *fi;
272 if (!msub)
273 return NULL;
274 fi = msub->role[MSC_ROLE_A];
275 if (!fi)
276 return NULL;
277 return (struct msc_a*)fi->priv;
278}
279
280struct msc_i *msub_msc_i(const struct msub *msub)
281{
282 struct osmo_fsm_inst *fi;
283 if (!msub)
284 return NULL;
285 fi = msub->role[MSC_ROLE_I];
286 if (!fi)
287 return NULL;
288 return (struct msc_i*)fi->priv;
289}
290
291struct msc_t *msub_msc_t(const struct msub *msub)
292{
293 struct osmo_fsm_inst *fi;
294 if (!msub)
295 return NULL;
296 fi = msub->role[MSC_ROLE_T];
297 if (!fi)
298 return NULL;
299 return (struct msc_t*)fi->priv;
300}
301
302/* Return the ran_conn of the MSC-I role, if available. If the MSC-I role is handled by a remote MSC, return NULL. */
303struct ran_conn *msub_ran_conn(const struct msub *msub)
304{
305 struct msc_i *msc_i = msub_msc_i(msub);
306 if (!msc_i)
307 return NULL;
308 return msc_i->ran_conn;
309}
310
311static struct ran_infra *msub_ran(const struct msub *msub)
312{
313 int i;
314 struct msc_role_common *c;
315
316 for (i = 0; i < MSC_ROLES_COUNT; i++) {
317 if (!msub->role[i])
318 continue;
319 c = msub->role[i]->priv;
320 if (!c->ran)
321 continue;
322 return c->ran;
323 }
324
325 return &msc_ran_infra[OSMO_RAT_UNKNOWN];
326}
327
328const char *msub_ran_conn_name(const struct msub *msub)
329{
330 struct msc_i *msc_i = msub_msc_i(msub);
331 struct msc_t *msc_t = msub_msc_t(msub);
332 if (msc_i && msc_i->c.remote_to)
333 return e_link_name(msc_i->c.remote_to);
334 if (msc_i && msc_i->ran_conn)
335 return ran_conn_name(msc_i->ran_conn);
336 if (msc_t && msc_t->c.remote_to)
337 return e_link_name(msc_t->c.remote_to);
338 if (msc_t && msc_t->ran_conn)
339 return ran_conn_name(msc_t->ran_conn);
340 return osmo_rat_type_name(msub_ran(msub)->type);
341}
342
343int msub_set_vsub(struct msub *msub, struct vlr_subscr *vsub)
344{
345 OSMO_ASSERT(msub);
346 if (msub->vsub == vsub)
347 return 0;
348 if (msub->vsub && vsub) {
349 LOG_MSUB(msub, LOGL_ERROR,
350 "Changing a connection's VLR Subscriber is not allowed: not changing to %s\n",
351 vlr_subscr_name(vsub));
352 return -ENOTSUP;
353 }
354 if (vsub) {
355 struct msub *other_msub = msub_for_vsub(vsub);
356 if (other_msub) {
357 struct msc_a *msc_a = msub_msc_a(msub);
358 struct msc_a *other_msc_a = msub_msc_a(other_msub);
359 LOG_MSC_A(msc_a, LOGL_ERROR,
360 "Cannot associate with VLR subscr, another connection is already active%s%s\n",
361 other_msc_a ? " at " : "", other_msc_a ? other_msc_a->c.fi->id : "");
362 LOG_MSC_A(other_msc_a, LOGL_ERROR, "Attempt to associate a second subscriber connection%s%s\n",
363 msc_a ? " at " : "", msc_a ? msc_a->c.fi->id : "");
364 if (other_msc_a && msc_a_in_release(other_msc_a)) {
365 LOG_MSC_A(other_msc_a, LOGL_ERROR,
366 "Another connection for this subscriber is coming up, since this"
367 " is already in release, forcefully discarding it\n");
368 osmo_fsm_inst_term(other_msc_a->c.fi, OSMO_FSM_TERM_ERROR, other_msc_a->c.fi);
369 /* Count this as "recovered from duplicate connection" error and do associate. */
370 } else
371 return -EINVAL;
372 }
373 }
374 if (msub->vsub) {
375 vlr_subscr_put(msub->vsub, VSUB_USE_MSUB);
376 msub->vsub = NULL;
377 }
378 if (vsub) {
379 vlr_subscr_get(vsub, VSUB_USE_MSUB);
380 msub->vsub = vsub;
381 vsub->cs.attached_via_ran = msub_ran(msub)->type;
382 msub_update_id(msub);
383 }
384 return 0;
385}
386
387struct vlr_subscr *msub_vsub(const struct msub *msub)
388{
389 return msub ? msub->vsub : NULL;
390}
391
392struct gsm_network *msub_net(const struct msub *msub)
393{
394 OSMO_ASSERT(msub->net);
395 return msub->net;
396}
397
398int msub_role_to_role_event(struct msub *msub, enum msc_role from_role, enum msc_role to_role)
399{
400 switch (from_role) {
401 case MSC_ROLE_A:
402 switch (to_role) {
403 case MSC_ROLE_I:
404 return MSC_I_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST;
405 case MSC_ROLE_T:
406 return MSC_T_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST;
407 default:
408 break;
409 }
410 break;
411
412 case MSC_ROLE_I:
413 switch (to_role) {
414 case MSC_ROLE_A:
415 return MSC_A_EV_FROM_I_PROCESS_ACCESS_SIGNALLING_REQUEST;
416 default:
417 break;
418 }
419 break;
420
421 case MSC_ROLE_T:
422 switch (to_role) {
423 case MSC_ROLE_A:
424 return MSC_A_EV_FROM_T_PROCESS_ACCESS_SIGNALLING_REQUEST;
425 default:
426 break;
427 }
428 break;
429
430 default:
431 break;
432 }
433
434 LOG_MSUB(msub, LOGL_ERROR, "Cannot tx DTAP from %s to %s\n", msc_role_name(from_role), msc_role_name(to_role));
435 return -1;
436}
437
438/* The caller retains ownership of the an_apdu_msg -- don't forget to msgb_free() it. */
439int _msub_role_dispatch(struct msub *msub, enum msc_role to_role, uint32_t to_role_event, const struct an_apdu *an_apdu,
440 const char *file, int line)
441{
442 struct osmo_fsm_inst *to_fi = msub->role[to_role];
443
444 if (!to_fi) {
445 LOG_MSUB_CAT_SRC(msub, DMSC, LOGL_ERROR, file, line,
446 "Cannot tx event to %s, no such role defined\n", msc_role_name(to_role));
447 return -EINVAL;
448 }
449
450 return _osmo_fsm_inst_dispatch(to_fi, to_role_event, (void*)an_apdu, file, line);
451}
452
453/* The caller retains ownership of the an_apdu_msg -- don't forget to msgb_free() it. */
454int msub_tx_an_apdu(struct msub *msub, enum msc_role from_role, enum msc_role to_role, struct an_apdu *an_apdu)
455{
456 int event = msub_role_to_role_event(msub, from_role, to_role);
457 if (event < 0)
458 return event;
459 return msub_role_dispatch(msub, to_role, event, an_apdu);
460}
461
462static void _msub_update_id(struct msub *msub, const char *subscr_name)
463{
464 enum msc_role idx;
465 struct msc_a *msc_a = msub_msc_a(msub);
466 struct vlr_subscr *vsub = msub_vsub(msub);
467 const char *compl_l3_name = NULL;
468 char id[128];
469
470 if (msc_a)
471 compl_l3_name = get_value_string_or_null(complete_layer3_type_names, msc_a->complete_layer3_type);
472 if (!compl_l3_name)
473 compl_l3_name = "no-compl-l3";
474
475 snprintf(id, sizeof(id), "%s:%s:%s", subscr_name, msub_ran_conn_name(msub), compl_l3_name);
476 osmo_identifier_sanitize_buf(id, NULL, '-');
477
478 for_each_msub_role(msub, idx) {
479 osmo_fsm_inst_update_id(msub->role[idx], id);
480 }
481 if (vsub) {
482 if (vsub->lu_fsm)
483 osmo_fsm_inst_update_id(vsub->lu_fsm, id);
484 if (vsub->auth_fsm)
485 osmo_fsm_inst_update_id(vsub->auth_fsm, id);
486 if (vsub->proc_arq_fsm)
487 osmo_fsm_inst_update_id(vsub->proc_arq_fsm, id);
488 }
489}
490
491/* Compose an ID almost like gsm48_mi_to_string(), but print the MI type along, and print a TMSI as hex. */
Neels Hofmeyr46d526a2020-05-29 03:27:50 +0200492void msub_update_id_from_mi(struct msub *msub, const struct osmo_mobile_identity *mi)
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100493{
Neels Hofmeyr46d526a2020-05-29 03:27:50 +0200494 _msub_update_id(msub, osmo_mobile_identity_to_str_c(OTC_SELECT, mi));
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100495}
496
497/* Update msub->fi id string from current msub->vsub and msub->complete_layer3_type. */
498void msub_update_id(struct msub *msub)
499{
500 if (!msub)
501 return;
502 _msub_update_id(msub, vlr_subscr_name(msub->vsub));
503}
504
505/* Iterate all msub instances that are relevant for this subscriber, and update FSM ID strings for all of the FSM
506 * instances. */
507void msub_update_id_for_vsub(struct vlr_subscr *for_vsub)
508{
509 struct msub *msub;
510 if (!for_vsub)
511 return;
512
513 llist_for_each_entry(msub, &msub_list, entry) {
514 if (msub->vsub == for_vsub)
515 msub_update_id(msub);
516 }
517}
518
519void msc_role_forget_conn(struct osmo_fsm_inst *role, struct ran_conn *conn)
520{
521 struct msc_i *old_i = role->priv;
522 struct msc_t *old_t = role->priv;
523 struct msc_role_common *c = role->priv;
524 struct ran_conn **conn_p = NULL;
525
526 switch (c->role) {
527 case MSC_ROLE_I:
528 conn_p = &old_i->ran_conn;
529 break;
530
531 case MSC_ROLE_T:
532 conn_p = &old_t->ran_conn;
533 break;
534 default:
535 break;
536 }
537
538 if (!conn_p)
539 return;
540
541 if (*conn_p != conn)
542 return;
543
544 (*conn_p)->msc_role = NULL;
545 *conn_p = NULL;
546}
547
Vadim Yanitskiyc44342b2021-12-07 18:32:35 +0300548/* NOTE: the resulting message buffer will be attached to OTC_SELECT, so its lifetime
549 * is limited by the current select() loop iteration. Use talloc_steal() to avoid this. */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100550struct msgb *msc_role_ran_encode(struct osmo_fsm_inst *fi, const struct ran_msg *ran_msg)
551{
552 struct msc_role_common *c = fi->priv;
553 struct msgb *msg;
554 if (!c->ran->ran_encode) {
555 LOGPFSML(fi, LOGL_ERROR, "Cannot encode %s: no NAS encoding function defined for RAN type %s\n",
556 ran_msg_type_name(ran_msg->msg_type), osmo_rat_type_name(c->ran->type));
557 return NULL;
558 }
559 msg = c->ran->ran_encode(fi, ran_msg);
560 if (!msg)
561 LOGPFSML(fi, LOGL_ERROR, "Failed to encode %s\n", ran_msg_type_name(ran_msg->msg_type));
Vadim Yanitskiyc44342b2021-12-07 18:32:35 +0300562 else
563 talloc_steal(OTC_SELECT, msg);
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100564 return msg;
565}
566
567int msc_role_ran_decode(struct osmo_fsm_inst *fi, const struct an_apdu *an_apdu,
568 ran_decode_cb_t decode_cb, void *decode_cb_data)
569{
570 struct ran_dec ran_dec;
571 struct msc_role_common *c = fi->priv;
572 if (!an_apdu) {
573 LOGPFSML(fi, LOGL_ERROR, "NULL AN-APDU\n");
574 return -EINVAL;
575 }
576 if (an_apdu->an_proto != c->ran->an_proto) {
577 LOGPFSML(fi, LOGL_ERROR, "Unexpected AN-APDU protocol: %s\n", an_proto_name(an_apdu->an_proto));
578 return -EINVAL;
579 }
580 if (!an_apdu->msg) {
581 LOGPFSML(fi, LOGL_DEBUG, "No PDU in this AN-APDU\n");
582 return 0;
583 }
584 ran_dec = (struct ran_dec) {
585 .caller_fi = fi,
586 .caller_data = decode_cb_data,
587 .decode_cb = decode_cb,
588 };
589 if (!c->ran->ran_dec_l2) {
590 LOGPFSML(fi, LOGL_ERROR, "No ran_dec_l2() defined for RAN type %s\n",
591 osmo_rat_type_name(c->ran->type));
592 return -ENOTSUP;
593 }
594 return c->ran->ran_dec_l2(&ran_dec, an_apdu->msg);
595}