blob: 5d8f78bc2fde516adb849599dd9b9a73792b7071 [file] [log] [blame]
Harald Welteb8b85a12016-06-17 00:06:42 +02001/* Osmocom Visitor Location Register (VLR): Location Update FSMs */
2
3/* (C) 2016 by Harald Welte <laforge@gnumonks.org>
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include <osmocom/core/fsm.h>
Max43b01b02017-09-15 11:22:30 +020023#include <osmocom/gsm/gsm48.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020024#include <osmocom/msc/vlr.h>
25#include <osmocom/msc/debug.h>
Harald Welteb8b85a12016-06-17 00:06:42 +020026
27#include "vlr_core.h"
28#include "vlr_auth_fsm.h"
29#include "vlr_lu_fsm.h"
Harald Welte0df904d2018-12-03 11:00:04 +010030#include "vlr_sgs_fsm.h"
Harald Welteb8b85a12016-06-17 00:06:42 +020031
32#define S(x) (1 << (x))
33
34#define LU_TIMEOUT_LONG 30
35
36enum vlr_fsm_result {
37 VLR_FSM_RESULT_NONE,
38 VLR_FSM_RESULT_SUCCESS,
39 VLR_FSM_RESULT_FAILURE,
40};
41
42
43/***********************************************************************
44 * Update_HLR_VLR, TS 23.012 Chapter 4.1.2.4
45 ***********************************************************************/
46
47enum upd_hlr_vlr_state {
48 UPD_HLR_VLR_S_INIT,
49 UPD_HLR_VLR_S_WAIT_FOR_DATA,
50 UPD_HLR_VLR_S_DONE,
51};
52
53enum upd_hlr_vlr_evt {
54 UPD_HLR_VLR_E_START,
55 UPD_HLR_VLR_E_INS_SUB_DATA,
56 UPD_HLR_VLR_E_ACT_TRACE_MODE,
57 UPD_HLR_VLR_E_FW_CHECK_SS_IND,
58 UPD_HLR_VLR_E_UPD_LOC_ACK,
59 UPD_HLR_VLR_E_UPD_LOC_NACK,
60};
61
62static const struct value_string upd_hlr_vlr_event_names[] = {
63 OSMO_VALUE_STRING(UPD_HLR_VLR_E_START),
64 OSMO_VALUE_STRING(UPD_HLR_VLR_E_INS_SUB_DATA),
65 OSMO_VALUE_STRING(UPD_HLR_VLR_E_ACT_TRACE_MODE),
66 OSMO_VALUE_STRING(UPD_HLR_VLR_E_FW_CHECK_SS_IND),
67 OSMO_VALUE_STRING(UPD_HLR_VLR_E_UPD_LOC_ACK),
68 OSMO_VALUE_STRING(UPD_HLR_VLR_E_UPD_LOC_NACK),
69 { 0, NULL }
70};
71
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +010072static inline struct vlr_subscr *upd_hlr_vlr_fi_priv(struct osmo_fsm_inst *fi);
73
Harald Welteb8b85a12016-06-17 00:06:42 +020074static void upd_hlr_vlr_fsm_init(struct osmo_fsm_inst *fi, uint32_t event,
75 void *data)
76{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +010077 struct vlr_subscr *vsub = upd_hlr_vlr_fi_priv(fi);
Max770fbd22018-01-24 12:48:33 +010078 int rc;
Harald Welteb8b85a12016-06-17 00:06:42 +020079
80 OSMO_ASSERT(event == UPD_HLR_VLR_E_START);
81
82 /* Send UpdateLocation to HLR */
Philipp Maier6038ad42018-11-13 13:55:09 +010083 rc = vlr_subscr_req_lu(vsub);
Max770fbd22018-01-24 12:48:33 +010084 if (rc < 0)
85 LOGPFSML(fi, LOGL_ERROR, "Failed to send UpdateLocation to HLR\n");
Harald Welteb8b85a12016-06-17 00:06:42 +020086 osmo_fsm_inst_state_chg(fi, UPD_HLR_VLR_S_WAIT_FOR_DATA,
87 LU_TIMEOUT_LONG, 0);
88}
89
90static void upd_hlr_vlr_fsm_wait_data(struct osmo_fsm_inst *fi, uint32_t event,
91 void *data)
92{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +010093 struct vlr_subscr *vsub = upd_hlr_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +020094
95 switch (event) {
96 case UPD_HLR_VLR_E_INS_SUB_DATA:
97 /* FIXME: Insert_Subscr_Data_VLR */
98 break;
99 case UPD_HLR_VLR_E_ACT_TRACE_MODE:
100 /* TODO: Activate_Tracing_VLR */
101 break;
102 case UPD_HLR_VLR_E_FW_CHECK_SS_IND:
103 /* TODO: Forward Check SS Ind to MSC */
104 break;
105 case UPD_HLR_VLR_E_UPD_LOC_ACK:
106 /* Inside Update_HLR_VLR after UpdateLocationAck */
107 vsub->sub_dataconf_by_hlr_ind = true;
108 vsub->loc_conf_in_hlr_ind = true;
109 osmo_fsm_inst_state_chg(fi, UPD_HLR_VLR_S_DONE, 0, 0);
110 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
111 break;
112 case UPD_HLR_VLR_E_UPD_LOC_NACK:
113 /* Inside Update_HLR_VLR after UpdateLocationNack */
114 /* TODO: Check_User_Error_In_Serving_Network_Entity */
115 vsub->sub_dataconf_by_hlr_ind = false;
116 vsub->loc_conf_in_hlr_ind = false;
117 osmo_fsm_inst_state_chg(fi, UPD_HLR_VLR_S_DONE, 0, 0);
118 /* Data is a pointer to a gsm48_gmm_cause which we
119 * simply pass through */
120 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, data);
121 break;
122 }
123}
124
125static const struct osmo_fsm_state upd_hlr_vlr_states[] = {
126 [UPD_HLR_VLR_S_INIT] = {
127 .in_event_mask = S(UPD_HLR_VLR_E_START),
128 .out_state_mask = S(UPD_HLR_VLR_S_WAIT_FOR_DATA),
129 .name = OSMO_STRINGIFY(UPD_HLR_VLR_S_INIT),
130 .action = upd_hlr_vlr_fsm_init,
131 },
132 [UPD_HLR_VLR_S_WAIT_FOR_DATA] = {
133 .in_event_mask = S(UPD_HLR_VLR_E_INS_SUB_DATA) |
134 S(UPD_HLR_VLR_E_ACT_TRACE_MODE) |
135 S(UPD_HLR_VLR_E_FW_CHECK_SS_IND) |
136 S(UPD_HLR_VLR_E_UPD_LOC_ACK) |
137 S(UPD_HLR_VLR_E_UPD_LOC_NACK),
138 .out_state_mask = S(UPD_HLR_VLR_S_DONE),
139 .name = OSMO_STRINGIFY(UPD_HLR_VLR_S_WAIT_FOR_DATA),
140 .action = upd_hlr_vlr_fsm_wait_data,
141 },
142 [UPD_HLR_VLR_S_DONE] = {
143 .name = OSMO_STRINGIFY(UPD_HLR_VLR_S_DONE),
144 },
145};
146
147static struct osmo_fsm upd_hlr_vlr_fsm = {
148 .name = "upd_hlr_vlr_fsm",
149 .states = upd_hlr_vlr_states,
150 .num_states = ARRAY_SIZE(upd_hlr_vlr_states),
151 .allstate_event_mask = 0,
152 .allstate_action = NULL,
153 .log_subsys = DVLR,
154 .event_names = upd_hlr_vlr_event_names,
155};
156
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100157static inline struct vlr_subscr *upd_hlr_vlr_fi_priv(struct osmo_fsm_inst *fi)
158{
159 OSMO_ASSERT(fi->fsm == &upd_hlr_vlr_fsm);
160 return (struct vlr_subscr*)fi->priv;
161}
162
Harald Welteb8b85a12016-06-17 00:06:42 +0200163struct osmo_fsm_inst *
164upd_hlr_vlr_proc_start(struct osmo_fsm_inst *parent,
165 struct vlr_subscr *vsub,
166 uint32_t parent_event)
167{
168 struct osmo_fsm_inst *fi;
169
170 fi = osmo_fsm_inst_alloc_child(&upd_hlr_vlr_fsm, parent,
171 parent_event);
172 if (!fi)
173 return NULL;
174
175 fi->priv = vsub;
176 osmo_fsm_inst_dispatch(fi, UPD_HLR_VLR_E_START, NULL);
177
178 return fi;
179}
180
181
182/***********************************************************************
183 * Subscriber_Present_VLR, TS 29.002 Chapter 25.10.1
184 ***********************************************************************/
185
186enum sub_pres_vlr_state {
187 SUB_PRES_VLR_S_INIT,
188 SUB_PRES_VLR_S_WAIT_FOR_HLR,
189 SUB_PRES_VLR_S_DONE,
190};
191
192enum sub_pres_vlr_event {
193 SUB_PRES_VLR_E_START,
194 SUB_PRES_VLR_E_READY_SM_CNF,
195 SUB_PRES_VLR_E_READY_SM_ERR,
196};
197
198static const struct value_string sub_pres_vlr_event_names[] = {
199 OSMO_VALUE_STRING(SUB_PRES_VLR_E_START),
200 OSMO_VALUE_STRING(SUB_PRES_VLR_E_READY_SM_CNF),
201 OSMO_VALUE_STRING(SUB_PRES_VLR_E_READY_SM_ERR),
202 { 0, NULL }
203};
204
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100205static inline struct vlr_subscr *sub_pres_vlr_fi_priv(struct osmo_fsm_inst *fi);
206
Harald Welteb8b85a12016-06-17 00:06:42 +0200207static void sub_pres_vlr_fsm_init(struct osmo_fsm_inst *fi, uint32_t event,
208 void *data)
209{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100210 struct vlr_subscr *vsub = sub_pres_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200211 OSMO_ASSERT(event == SUB_PRES_VLR_E_START);
212
213 if (!vsub->ms_not_reachable_flag) {
214 osmo_fsm_inst_state_chg(fi, SUB_PRES_VLR_S_DONE, 0, 0);
215 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
216 return;
217 }
218 /* FIXME: Send READY_FOR_SM via GSUP */
219 osmo_fsm_inst_state_chg(fi, SUB_PRES_VLR_S_WAIT_FOR_HLR,
220 LU_TIMEOUT_LONG, 0);
221}
222
223static void sub_pres_vlr_fsm_wait_hlr(struct osmo_fsm_inst *fi, uint32_t event,
224 void *data)
225{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100226 struct vlr_subscr *vsub = sub_pres_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200227
228 switch (event) {
229 case SUB_PRES_VLR_E_READY_SM_CNF:
230 vsub->ms_not_reachable_flag = false;
231 break;
232 case SUB_PRES_VLR_E_READY_SM_ERR:
233 break;
234 }
235 osmo_fsm_inst_state_chg(fi, SUB_PRES_VLR_S_DONE, 0, 0);
236 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
237}
238
239static const struct osmo_fsm_state sub_pres_vlr_states[] = {
240 [SUB_PRES_VLR_S_INIT] = {
241 .in_event_mask = S(SUB_PRES_VLR_E_START),
242 .out_state_mask = S(SUB_PRES_VLR_S_WAIT_FOR_HLR) |
243 S(SUB_PRES_VLR_S_DONE),
244 .name = OSMO_STRINGIFY(SUB_PRES_VLR_S_INIT),
245 .action = sub_pres_vlr_fsm_init,
246 },
247 [SUB_PRES_VLR_S_WAIT_FOR_HLR] = {
248 .in_event_mask = S(SUB_PRES_VLR_E_READY_SM_CNF) |
249 S(SUB_PRES_VLR_E_READY_SM_ERR),
250 .out_state_mask = S(SUB_PRES_VLR_S_DONE),
251 .name = OSMO_STRINGIFY(SUB_PRES_VLR_S_WAIT_FOR_HLR),
252 .action = sub_pres_vlr_fsm_wait_hlr,
253 },
254 [SUB_PRES_VLR_S_DONE] = {
255 .name = OSMO_STRINGIFY(SUB_PRES_VLR_S_DONE),
256 },
257};
258
259static struct osmo_fsm sub_pres_vlr_fsm = {
260 .name = "sub_pres_vlr_fsm",
261 .states = sub_pres_vlr_states,
262 .num_states = ARRAY_SIZE(sub_pres_vlr_states),
263 .allstate_event_mask = 0,
264 .allstate_action = NULL,
265 .log_subsys = DVLR,
266 .event_names = sub_pres_vlr_event_names,
267};
268
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100269static inline struct vlr_subscr *sub_pres_vlr_fi_priv(struct osmo_fsm_inst *fi)
270{
271 OSMO_ASSERT(fi->fsm == &sub_pres_vlr_fsm);
272 return (struct vlr_subscr*)fi->priv;
273}
274
Neels Hofmeyr5f1ac6d2018-12-11 01:59:25 +0100275/* THIS IS CURRENTLY DEAD CODE, SINCE WE NEVER SET vsub->ms_not_reachable_flag = true.
276 *
277 * Note that the start event is dispatched right away, so in case the FSM immediately concludes from that
Neels Hofmeyr1a5bcd52017-11-18 22:19:55 +0100278 * event, the created FSM struct may no longer be valid as it already deallocated again, and it may
279 * furthermore already have invoked the parent FSM instance's deallocation as well. Hence, instead of
280 * returning, store the created FSM instance address in *fi_p before dispatching the event. It is thus
281 * possible to store the instance's pointer in a parent FSM instance without running danger of using
282 * already freed memory. */
283void sub_pres_vlr_fsm_start(struct osmo_fsm_inst **fi_p,
284 struct osmo_fsm_inst *parent,
285 struct vlr_subscr *vsub,
286 uint32_t term_event)
Harald Welteb8b85a12016-06-17 00:06:42 +0200287{
288 struct osmo_fsm_inst *fi;
289
Neels Hofmeyr1a5bcd52017-11-18 22:19:55 +0100290 OSMO_ASSERT(fi_p);
291
Harald Welteb8b85a12016-06-17 00:06:42 +0200292 fi = osmo_fsm_inst_alloc_child(&sub_pres_vlr_fsm, parent,
293 term_event);
Neels Hofmeyr1a5bcd52017-11-18 22:19:55 +0100294 *fi_p = fi;
Harald Welteb8b85a12016-06-17 00:06:42 +0200295 if (!fi)
Neels Hofmeyr1a5bcd52017-11-18 22:19:55 +0100296 return;
Harald Welteb8b85a12016-06-17 00:06:42 +0200297
298 fi->priv = vsub;
299 osmo_fsm_inst_dispatch(fi, SUB_PRES_VLR_E_START, NULL);
Harald Welteb8b85a12016-06-17 00:06:42 +0200300}
301
302/***********************************************************************
303 * Location_Update_Completion_VLR, TS 23.012 Chapter 4.1.2.3
304 ***********************************************************************/
305
306enum lu_compl_vlr_state {
307 LU_COMPL_VLR_S_INIT,
308 LU_COMPL_VLR_S_WAIT_SUB_PRES,
309 LU_COMPL_VLR_S_WAIT_IMEI,
310 LU_COMPL_VLR_S_WAIT_IMEI_TMSI,
311 LU_COMPL_VLR_S_WAIT_TMSI_CNF,
312 LU_COMPL_VLR_S_DONE,
313};
314
315enum lu_compl_vlr_event {
316 LU_COMPL_VLR_E_START,
317 LU_COMPL_VLR_E_SUB_PRES_COMPL,
318 LU_COMPL_VLR_E_IMEI_CHECK_ACK,
319 LU_COMPL_VLR_E_IMEI_CHECK_NACK,
320 LU_COMPL_VLR_E_NEW_TMSI_ACK,
321};
322
323static const struct value_string lu_compl_vlr_event_names[] = {
324 OSMO_VALUE_STRING(LU_COMPL_VLR_E_START),
325 OSMO_VALUE_STRING(LU_COMPL_VLR_E_SUB_PRES_COMPL),
326 OSMO_VALUE_STRING(LU_COMPL_VLR_E_IMEI_CHECK_ACK),
327 OSMO_VALUE_STRING(LU_COMPL_VLR_E_IMEI_CHECK_NACK),
328 OSMO_VALUE_STRING(LU_COMPL_VLR_E_NEW_TMSI_ACK),
329 { 0, NULL }
330};
331
332struct lu_compl_vlr_priv {
333 struct vlr_subscr *vsub;
334 void *msc_conn_ref;
335 struct osmo_fsm_inst *sub_pres_vlr_fsm;
336 uint32_t parent_event_success;
337 uint32_t parent_event_failure;
338 void *parent_event_data;
339 enum vlr_fsm_result result;
340 uint8_t cause;
341 bool assign_tmsi;
342};
343
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100344static inline struct lu_compl_vlr_priv *lu_compl_vlr_fi_priv(struct osmo_fsm_inst *fi);
345
Harald Welteb8b85a12016-06-17 00:06:42 +0200346static void _vlr_lu_compl_fsm_done(struct osmo_fsm_inst *fi,
347 enum vlr_fsm_result result,
348 uint8_t cause)
349{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100350 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200351 lcvp->result = result;
352 lcvp->cause = cause;
353 osmo_fsm_inst_state_chg(fi, LU_COMPL_VLR_S_DONE, 0, 0);
354}
355
356static void vlr_lu_compl_fsm_success(struct osmo_fsm_inst *fi)
357{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100358 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200359 struct vlr_subscr *vsub = lcvp->vsub;
360 if (!vsub->lu_complete) {
361 vsub->lu_complete = true;
Stefan Sperlingdefc3c82018-05-15 14:48:04 +0200362 /* Balanced by vlr_subscr_expire() */
Neels Hofmeyr7c5346c2019-02-19 02:36:35 +0100363 vlr_subscr_get(vsub, VSUB_USE_ATTACHED);
Harald Welteb8b85a12016-06-17 00:06:42 +0200364 }
365 _vlr_lu_compl_fsm_done(fi, VLR_FSM_RESULT_SUCCESS, 0);
Harald Welte0df904d2018-12-03 11:00:04 +0100366 vlr_sgs_fsm_update_id(vsub);
Harald Welteb8b85a12016-06-17 00:06:42 +0200367}
368
Harald Welteb8b85a12016-06-17 00:06:42 +0200369static void vlr_lu_compl_fsm_dispatch_result(struct osmo_fsm_inst *fi,
370 uint32_t prev_state)
371{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100372 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200373 if (!fi->proc.parent) {
374 LOGPFSML(fi, LOGL_ERROR, "No parent FSM\n");
375 return;
376 }
377 osmo_fsm_inst_dispatch(fi->proc.parent,
378 (lcvp->result == VLR_FSM_RESULT_SUCCESS)
379 ? lcvp->parent_event_success
380 : lcvp->parent_event_failure,
381 &lcvp->cause);
382}
383
384static void lu_compl_vlr_init(struct osmo_fsm_inst *fi, uint32_t event,
385 void *data)
386{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100387 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200388 struct vlr_subscr *vsub = lcvp->vsub;
389 struct vlr_instance *vlr;
390 OSMO_ASSERT(vsub);
391 vlr = vsub->vlr;
392 OSMO_ASSERT(vlr);
393
394 OSMO_ASSERT(event == LU_COMPL_VLR_E_START);
395
396 /* TODO: National Roaming restrictions? */
397 /* TODO: Roaming restriction due to unsupported feature in subscriber
398 * data? */
399 /* TODO: Regional subscription restriction? */
400 /* TODO: Administrative restriction of subscribres' access feature? */
401 /* TODO: AccessRestrictuionData parameter available? */
402 /* TODO: AccessRestrictionData permits RAT? */
403 /* Node 1 */
404 /* TODO: Autonomous CSG supported in VPLMN and allowed by HPLMN? */
405 /* TODO: Hybrid Cel / CSG Cell */
406 /* Node 2 */
407 vsub->la_allowed = true;
408 vsub->imsi_detached_flag = false;
409 /* Start Subscriber_Present_VLR Procedure */
410 osmo_fsm_inst_state_chg(fi, LU_COMPL_VLR_S_WAIT_SUB_PRES,
411 LU_TIMEOUT_LONG, 0);
412
Neels Hofmeyraa14bac2018-12-11 01:56:11 +0100413 /* If ms_not_reachable_flag == false, the sub_pres_vlr_fsm will anyway terminate straight away and dispatch
414 * LU_COMPL_VLR_E_SUB_PRES_COMPL to this fi, so we might as well skip that dance here and save some logging. */
415 if (vsub->ms_not_reachable_flag)
416 sub_pres_vlr_fsm_start(&lcvp->sub_pres_vlr_fsm, fi, vsub, LU_COMPL_VLR_E_SUB_PRES_COMPL);
417 else
418 osmo_fsm_inst_dispatch(fi, LU_COMPL_VLR_E_SUB_PRES_COMPL, NULL);
Harald Welteb8b85a12016-06-17 00:06:42 +0200419}
420
421static void lu_compl_vlr_new_tmsi(struct osmo_fsm_inst *fi)
422{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100423 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200424 struct vlr_subscr *vsub = lcvp->vsub;
425 struct vlr_instance *vlr = vsub->vlr;
426
427 LOGPFSM(fi, "%s()\n", __func__);
428
429 if (vlr_subscr_alloc_tmsi(vsub)) {
Oliver Smithc0a5e712019-07-23 10:43:36 +0200430 _vlr_lu_compl_fsm_done(fi, VLR_FSM_RESULT_FAILURE, GSM48_REJECT_SRV_OPT_TMP_OUT_OF_ORDER);
Harald Welteb8b85a12016-06-17 00:06:42 +0200431 return;
432 }
433
434 osmo_fsm_inst_state_chg(fi, LU_COMPL_VLR_S_WAIT_TMSI_CNF,
435 vlr_timer(vlr, 3250), 3250);
436
437 vlr->ops.tx_lu_acc(lcvp->msc_conn_ref, vsub->tmsi_new);
438}
439
440/* After completion of Subscriber_Present_VLR */
441static void lu_compl_vlr_wait_subscr_pres(struct osmo_fsm_inst *fi,
442 uint32_t event,
443 void *data)
444{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100445 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200446 struct vlr_subscr *vsub = lcvp->vsub;
447 struct vlr_instance *vlr = vsub->vlr;
448
449 OSMO_ASSERT(event == LU_COMPL_VLR_E_SUB_PRES_COMPL);
450
451 lcvp->sub_pres_vlr_fsm = NULL;
452
453 /* TODO: Trace_Subscriber_Activity_VLR */
454
Oliver Smithcbf2c932019-05-06 13:09:55 +0200455 /* If imeisv_early is enabled: IMEI already retrieved and checked (vlr_loc_upd_node1_pre), don't do it again. */
456 if (vlr->cfg.check_imei_rqd && !vlr->cfg.retrieve_imeisv_early) {
Harald Welteb8b85a12016-06-17 00:06:42 +0200457 /* Check IMEI VLR */
458 osmo_fsm_inst_state_chg(fi,
459 lcvp->assign_tmsi ?
460 LU_COMPL_VLR_S_WAIT_IMEI_TMSI
461 : LU_COMPL_VLR_S_WAIT_IMEI,
462 vlr_timer(vlr, 3270), 3270);
463 vlr->ops.tx_id_req(lcvp->msc_conn_ref, GSM_MI_TYPE_IMEI);
464 return;
465 }
466
467 /* Do we need to allocate a TMSI? */
468 if (lcvp->assign_tmsi) {
469 lu_compl_vlr_new_tmsi(fi);
470 return;
471 }
Neels Hofmeyr0cc03ca2024-03-25 06:41:35 +0100472 /* else, any previously used TMSI is now invalid. */
473 vsub->tmsi = GSM_RESERVED_TMSI;
Harald Welteb8b85a12016-06-17 00:06:42 +0200474
475 /* Location Updating Accept */
476 vlr->ops.tx_lu_acc(lcvp->msc_conn_ref, GSM_RESERVED_TMSI);
477 vlr_lu_compl_fsm_success(fi);
478}
479
480/* Waiting for completion of CHECK_IMEI_VLR */
481static void lu_compl_vlr_wait_imei(struct osmo_fsm_inst *fi, uint32_t event,
482 void *data)
483{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100484 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200485 struct vlr_subscr *vsub = lcvp->vsub;
486 struct vlr_instance *vlr = vsub->vlr;
487
488 switch (event) {
489 case LU_COMPL_VLR_E_IMEI_CHECK_ACK:
490 if (!vsub->imei[0]) {
491 /* Abort: Do nothing */
Oliver Smithc0a5e712019-07-23 10:43:36 +0200492 _vlr_lu_compl_fsm_done(fi, VLR_FSM_RESULT_FAILURE, GSM48_REJECT_PROTOCOL_ERROR);
Harald Welteb8b85a12016-06-17 00:06:42 +0200493 return;
494 }
495 /* Pass */
496 break;
497
498 case LU_COMPL_VLR_E_IMEI_CHECK_NACK:
Oliver Smithc0a5e712019-07-23 10:43:36 +0200499 _vlr_lu_compl_fsm_done(fi, VLR_FSM_RESULT_FAILURE, GSM48_REJECT_ILLEGAL_ME);
Harald Welteb8b85a12016-06-17 00:06:42 +0200500 /* FIXME: IMEI Check Fail to VLR Application (Detach IMSI VLR) */
501 return;
502 }
503
504 /* IMEI is available. Allocate TMSI if needed. */
505 if (lcvp->assign_tmsi) {
506 if (fi->state != LU_COMPL_VLR_S_WAIT_IMEI_TMSI)
507 LOGPFSML(fi, LOGL_ERROR,
508 "TMSI required, expected to be in state"
509 " LU_COMPL_VLR_S_WAIT_IMEI_TMSI,"
510 " am in %s instead\n",
511 osmo_fsm_state_name(fi->fsm, fi->state));
512 /* Logged an error, continue anyway. */
513
514 lu_compl_vlr_new_tmsi(fi);
515
516 /* Wait for TMSI ack */
517 return;
518 }
Neels Hofmeyr0cc03ca2024-03-25 06:41:35 +0100519 /* else, any previously used TMSI is now invalid. */
520 vsub->tmsi = GSM_RESERVED_TMSI;
Harald Welteb8b85a12016-06-17 00:06:42 +0200521
522 /* No TMSI needed, accept now. */
523 vlr->ops.tx_lu_acc(lcvp->msc_conn_ref, GSM_RESERVED_TMSI);
524 vlr_lu_compl_fsm_success(fi);
525}
526
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100527static inline struct lu_compl_vlr_priv *lu_compl_vlr_fi_priv(struct osmo_fsm_inst *fi);
528
Harald Welteb8b85a12016-06-17 00:06:42 +0200529/* Waiting for TMSI confirmation */
530static void lu_compl_vlr_wait_tmsi(struct osmo_fsm_inst *fi, uint32_t event,
531 void *data)
532{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100533 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200534 struct vlr_subscr *vsub = lcvp->vsub;
535
536 OSMO_ASSERT(event == LU_COMPL_VLR_E_NEW_TMSI_ACK);
537
538 if (!vsub || vsub->tmsi_new == GSM_RESERVED_TMSI) {
539 LOGPFSML(fi, LOGL_ERROR, "TMSI Realloc Compl implies that"
540 " the subscriber has a new TMSI allocated, but"
541 " the new TMSI is unset.\n");
Oliver Smithc0a5e712019-07-23 10:43:36 +0200542 _vlr_lu_compl_fsm_done(fi, VLR_FSM_RESULT_FAILURE, GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200543 return;
544 }
545
546 vsub->tmsi = vsub->tmsi_new;
547 vsub->tmsi_new = GSM_RESERVED_TMSI;
Neels Hofmeyr361e5712019-01-03 02:32:14 +0100548 vsub->vlr->ops.subscr_update(vsub);
Harald Welteb8b85a12016-06-17 00:06:42 +0200549
550 vlr_lu_compl_fsm_success(fi);
551}
552
553static const struct osmo_fsm_state lu_compl_vlr_states[] = {
554 [LU_COMPL_VLR_S_INIT] = {
555 .in_event_mask = S(LU_COMPL_VLR_E_START),
556 .out_state_mask = S(LU_COMPL_VLR_S_DONE) |
Neels Hofmeyrd50f8982018-12-11 02:24:57 +0100557 S(LU_COMPL_VLR_S_WAIT_SUB_PRES),
Harald Welteb8b85a12016-06-17 00:06:42 +0200558 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_INIT),
559 .action = lu_compl_vlr_init,
560 },
561 [LU_COMPL_VLR_S_WAIT_SUB_PRES] = {
562 .in_event_mask = S(LU_COMPL_VLR_E_SUB_PRES_COMPL),
563 .out_state_mask = S(LU_COMPL_VLR_S_WAIT_IMEI) |
564 S(LU_COMPL_VLR_S_WAIT_IMEI_TMSI) |
565 S(LU_COMPL_VLR_S_WAIT_TMSI_CNF) |
566 S(LU_COMPL_VLR_S_DONE),
567 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_SUB_PRES),
568 .action = lu_compl_vlr_wait_subscr_pres,
569 },
570 [LU_COMPL_VLR_S_WAIT_IMEI] = {
571 .in_event_mask = S(LU_COMPL_VLR_E_IMEI_CHECK_ACK) |
572 S(LU_COMPL_VLR_E_IMEI_CHECK_NACK),
573 .out_state_mask = S(LU_COMPL_VLR_S_DONE),
574 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_IMEI),
575 .action = lu_compl_vlr_wait_imei,
576 },
577 [LU_COMPL_VLR_S_WAIT_IMEI_TMSI] = {
578 .in_event_mask = S(LU_COMPL_VLR_E_IMEI_CHECK_ACK) |
579 S(LU_COMPL_VLR_E_IMEI_CHECK_NACK),
580 .out_state_mask = S(LU_COMPL_VLR_S_DONE) |
581 S(LU_COMPL_VLR_S_WAIT_TMSI_CNF),
582 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_IMEI_TMSI),
583 .action = lu_compl_vlr_wait_imei,
584 },
585 [LU_COMPL_VLR_S_WAIT_TMSI_CNF] = {
586 .in_event_mask = S(LU_COMPL_VLR_E_NEW_TMSI_ACK),
587 .out_state_mask = S(LU_COMPL_VLR_S_DONE),
588 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_TMSI_CNF),
589 .action = lu_compl_vlr_wait_tmsi,
590 },
591 [LU_COMPL_VLR_S_DONE] = {
592 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_DONE),
593 .onenter = vlr_lu_compl_fsm_dispatch_result,
594 },
595};
596
597static struct osmo_fsm lu_compl_vlr_fsm = {
598 .name = "lu_compl_vlr_fsm",
599 .states = lu_compl_vlr_states,
600 .num_states = ARRAY_SIZE(lu_compl_vlr_states),
601 .allstate_event_mask = 0,
602 .allstate_action = NULL,
603 .log_subsys = DVLR,
604 .event_names = lu_compl_vlr_event_names,
605};
606
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100607static inline struct lu_compl_vlr_priv *lu_compl_vlr_fi_priv(struct osmo_fsm_inst *fi)
608{
609 OSMO_ASSERT(fi->fsm == &lu_compl_vlr_fsm);
610 return (struct lu_compl_vlr_priv*)fi->priv;
611}
612
Harald Welteb8b85a12016-06-17 00:06:42 +0200613struct osmo_fsm_inst *
614lu_compl_vlr_proc_alloc(struct osmo_fsm_inst *parent,
615 struct vlr_subscr *vsub,
616 void *msc_conn_ref,
617 uint32_t parent_event_success,
618 uint32_t parent_event_failure,
619 bool assign_tmsi)
620{
621 struct osmo_fsm_inst *fi;
622 struct lu_compl_vlr_priv *lcvp;
623
624 fi = osmo_fsm_inst_alloc_child(&lu_compl_vlr_fsm, parent,
625 parent_event_failure);
626 if (!fi)
627 return NULL;
628
629 lcvp = talloc_zero(fi, struct lu_compl_vlr_priv);
630 lcvp->vsub = vsub;
631 lcvp->msc_conn_ref = msc_conn_ref;
632 lcvp->parent_event_success = parent_event_success;
633 lcvp->parent_event_failure = parent_event_failure;
634 lcvp->assign_tmsi = assign_tmsi;
635 fi->priv = lcvp;
636
637 return fi;
638}
639
640
641/***********************************************************************
642 * Update_Location_Area_VLR, TS 23.012 Chapter 4.1.2.1
643 ***********************************************************************/
644
645static const struct value_string fsm_lu_event_names[] = {
646 OSMO_VALUE_STRING(VLR_ULA_E_UPDATE_LA),
647 OSMO_VALUE_STRING(VLR_ULA_E_SEND_ID_ACK),
648 OSMO_VALUE_STRING(VLR_ULA_E_SEND_ID_NACK),
Neels Hofmeyr3189f392022-10-26 18:11:58 +0200649 OSMO_VALUE_STRING(VLR_ULA_E_AUTH_SUCCESS),
Neels Hofmeyr1cb18a22022-10-11 00:18:04 +0200650 OSMO_VALUE_STRING(VLR_ULA_E_AUTH_NO_INFO),
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200651 OSMO_VALUE_STRING(VLR_ULA_E_AUTH_FAILURE),
Harald Welteb8b85a12016-06-17 00:06:42 +0200652 OSMO_VALUE_STRING(VLR_ULA_E_CIPH_RES),
653 OSMO_VALUE_STRING(VLR_ULA_E_ID_IMSI),
654 OSMO_VALUE_STRING(VLR_ULA_E_ID_IMEI),
655 OSMO_VALUE_STRING(VLR_ULA_E_ID_IMEISV),
Oliver Smith7d053092018-12-14 17:37:38 +0100656 OSMO_VALUE_STRING(VLR_ULA_E_HLR_IMEI_ACK),
657 OSMO_VALUE_STRING(VLR_ULA_E_HLR_IMEI_NACK),
Harald Welteb8b85a12016-06-17 00:06:42 +0200658 OSMO_VALUE_STRING(VLR_ULA_E_HLR_LU_RES),
659 OSMO_VALUE_STRING(VLR_ULA_E_UPD_HLR_COMPL),
660 OSMO_VALUE_STRING(VLR_ULA_E_LU_COMPL_SUCCESS),
661 OSMO_VALUE_STRING(VLR_ULA_E_LU_COMPL_FAILURE),
662 OSMO_VALUE_STRING(VLR_ULA_E_NEW_TMSI_ACK),
663 { 0, NULL }
664};
665
666struct lu_fsm_priv {
667 struct vlr_instance *vlr;
668 struct vlr_subscr *vsub;
669 void *msc_conn_ref;
670 struct osmo_fsm_inst *upd_hlr_vlr_fsm;
671 struct osmo_fsm_inst *lu_compl_vlr_fsm;
672 uint32_t parent_event_success;
673 uint32_t parent_event_failure;
674 void *parent_event_data;
675 enum vlr_fsm_result result;
676 uint8_t rej_cause;
677
678 enum vlr_lu_type type;
679 bool lu_by_tmsi;
680 char imsi[16];
681 uint32_t tmsi;
682 struct osmo_location_area_id old_lai;
683 struct osmo_location_area_id new_lai;
684 bool authentication_required;
Neels Hofmeyr2ea72642022-10-10 23:35:47 +0200685 /* is_ciphering_to_be_attempted: true when any A5/n > 0 are enabled. Ciphering is allowed, always attempt to get Auth Info from
686 * the HLR. */
Neels Hofmeyrd99a6072022-10-10 23:34:48 +0200687 bool is_ciphering_to_be_attempted;
Neels Hofmeyr2ea72642022-10-10 23:35:47 +0200688 /* is_ciphering_required: true when A5/0 is disabled. If we cannot get Auth Info from the HLR, reject the
689 * subscriber. */
690 bool is_ciphering_required;
Sylvain Munautda9f37e2019-03-14 11:02:36 +0100691 uint8_t key_seq;
Harald Welteb8b85a12016-06-17 00:06:42 +0200692 bool is_r99;
693 bool is_utran;
694 bool assign_tmsi;
695};
696
697
698/* Determine if given location area is served by this VLR */
699static bool lai_in_this_vlr(struct vlr_instance *vlr,
700 const struct osmo_location_area_id *lai)
701{
Martin Hauke3f07dac2019-11-14 17:49:08 +0100702 /* TODO: VLR needs to keep a locally configured list of LAIs */
Harald Welteb8b85a12016-06-17 00:06:42 +0200703 return true;
704}
705
Neels Hofmeyrc48afa12022-10-10 23:47:04 +0200706/* Return true when authentication should be attempted. */
707static bool try_auth(struct lu_fsm_priv *lfp)
Harald Welteb8b85a12016-06-17 00:06:42 +0200708{
709 /* The cases where the authentication procedure should be used
710 * are defined in 3GPP TS 33.102 */
711 /* For now we use a default value passed in to vlr_lu_fsm(). */
Sylvain Munautda9f37e2019-03-14 11:02:36 +0100712 return lfp->authentication_required ||
Neels Hofmeyrd99a6072022-10-10 23:34:48 +0200713 (lfp->is_ciphering_to_be_attempted && !auth_try_reuse_tuple(lfp->vsub, lfp->key_seq));
Harald Welteb8b85a12016-06-17 00:06:42 +0200714}
715
Neels Hofmeyrc48afa12022-10-10 23:47:04 +0200716/* Return true when CipherModeCmd / SecurityModeCmd should be attempted. */
717static bool is_cmc_smc_to_be_attempted(struct lu_fsm_priv *lfp)
Harald Welteb8b85a12016-06-17 00:06:42 +0200718{
Vadim Yanitskiy565ea2b2021-11-28 16:42:58 +0300719 /* UTRAN: always send SecModeCmd, even if ciphering is not required.
720 * GERAN: avoid sending CiphModeCmd if ciphering is not required. */
Neels Hofmeyrd99a6072022-10-10 23:34:48 +0200721 return lfp->is_utran || lfp->is_ciphering_to_be_attempted;
Harald Welteb8b85a12016-06-17 00:06:42 +0200722}
723
724/* Determine if a HLR Update is required */
725static bool hlr_update_needed(struct vlr_subscr *vsub)
726{
727 /* TODO: properly decide this, rather than always assuming we
728 * need to update the HLR. */
729 return true;
730}
731
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100732static inline struct lu_fsm_priv *lu_fsm_fi_priv(struct osmo_fsm_inst *fi);
733
Harald Welteb8b85a12016-06-17 00:06:42 +0200734static void lu_fsm_dispatch_result(struct osmo_fsm_inst *fi,
735 uint32_t prev_state)
736{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100737 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200738 if (!fi->proc.parent) {
739 LOGPFSML(fi, LOGL_ERROR, "No parent FSM\n");
740 return;
741 }
742 osmo_fsm_inst_dispatch(fi->proc.parent,
743 (lfp->result == VLR_FSM_RESULT_SUCCESS)
744 ? lfp->parent_event_success
745 : lfp->parent_event_failure,
746 lfp->parent_event_data);
747}
748
749static void _lu_fsm_done(struct osmo_fsm_inst *fi,
750 enum vlr_fsm_result result)
751{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100752 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200753 lfp->result = result;
754 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_DONE, 0, 0);
755}
756
757static void lu_fsm_success(struct osmo_fsm_inst *fi)
758{
759 _lu_fsm_done(fi, VLR_FSM_RESULT_SUCCESS);
760}
761
Neels Hofmeyr15809592018-04-06 02:57:51 +0200762static void lu_fsm_failure(struct osmo_fsm_inst *fi, enum gsm48_reject_value rej_cause)
Harald Welteb8b85a12016-06-17 00:06:42 +0200763{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100764 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Neels Hofmeyr15809592018-04-06 02:57:51 +0200765 lfp->vlr->ops.tx_lu_rej(lfp->msc_conn_ref, rej_cause ? : GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200766 _lu_fsm_done(fi, VLR_FSM_RESULT_FAILURE);
767}
768
769static void vlr_loc_upd_start_lu_compl_fsm(struct osmo_fsm_inst *fi)
770{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100771 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200772 lfp->lu_compl_vlr_fsm =
773 lu_compl_vlr_proc_alloc(fi, lfp->vsub, lfp->msc_conn_ref,
774 VLR_ULA_E_LU_COMPL_SUCCESS,
775 VLR_ULA_E_LU_COMPL_FAILURE,
776 lfp->assign_tmsi);
777
778 osmo_fsm_inst_dispatch(lfp->lu_compl_vlr_fsm, LU_COMPL_VLR_E_START, NULL);
779}
780
781static void lu_fsm_discard_lu_compl_fsm(struct osmo_fsm_inst *fi)
782{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100783 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200784 if (!lfp->lu_compl_vlr_fsm)
785 return;
786 osmo_fsm_inst_term(lfp->lu_compl_vlr_fsm, OSMO_FSM_TERM_PARENT, NULL);
787}
788
789/* 4.1.2.1 Node 4 */
790static void vlr_loc_upd_node_4(struct osmo_fsm_inst *fi)
791{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100792 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200793 struct vlr_subscr *vsub = lfp->vsub;
794 bool hlr_unknown = false;
795
796 LOGPFSM(fi, "%s()\n", __func__);
797
798 if (hlr_unknown) {
799 /* FIXME: Delete subscriber record */
800 /* LU REJ: Roaming not allowed */
801 lu_fsm_failure(fi, GSM48_REJECT_ROAMING_NOT_ALLOWED);
802 } else {
803 /* Update_HLR_VLR */
804 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_HLR_UPD,
805 LU_TIMEOUT_LONG, 0);
806 lfp->upd_hlr_vlr_fsm =
807 upd_hlr_vlr_proc_start(fi, vsub, VLR_ULA_E_UPD_HLR_COMPL);
808 }
809}
810
811/* 4.1.2.1 Node B */
812static void vlr_loc_upd_node_b(struct osmo_fsm_inst *fi)
813{
814 LOGPFSM(fi, "%s()\n", __func__);
815
Neels Hofmeyref9126c2017-07-18 15:38:39 +0200816 /* OsmoHLR does not support PgA, neither stores the IMEISV, so we have no need to update the HLR
817 * with either. TODO: depend on actual HLR configuration. See 3GPP TS 23.012 Release 14, process
818 * Update_Location_Area_VLR (ULA_VLR2). */
Harald Welteb8b85a12016-06-17 00:06:42 +0200819 if (0) { /* IMEISV or PgA to send */
820 vlr_loc_upd_node_4(fi);
821 } else {
822 /* Location_Update_Completion */
823 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_LU_COMPL,
824 LU_TIMEOUT_LONG, 0);
825 vlr_loc_upd_start_lu_compl_fsm(fi);
826 }
827}
828
829/* Non-standard: after Ciphering Mode Complete (or no ciph required) */
830static void vlr_loc_upd_post_ciph(struct osmo_fsm_inst *fi)
831{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100832 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200833 struct vlr_subscr *vsub = lfp->vsub;
Harald Welte544a32f2020-06-21 22:15:53 +0200834 int rc;
Harald Welteb8b85a12016-06-17 00:06:42 +0200835
836 LOGPFSM(fi, "%s()\n", __func__);
837
838 OSMO_ASSERT(vsub);
839
Harald Welte544a32f2020-06-21 22:15:53 +0200840 rc = lfp->vlr->ops.tx_common_id(lfp->msc_conn_ref);
841 if (rc)
842 LOGPFSML(fi, LOGL_ERROR, "Error while sending Common ID (%d)\n", rc);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200843
Harald Welteb8b85a12016-06-17 00:06:42 +0200844 vsub->conf_by_radio_contact_ind = true;
845 /* Update LAI */
846 vsub->cgi.lai = lfp->new_lai;
847 vsub->dormant_ind = false;
848 vsub->cancel_loc_rx = false;
849 if (hlr_update_needed(vsub)) {
850 vlr_loc_upd_node_4(fi);
851 } else {
852 /* TODO: ADD Support */
853 /* TODO: Node A: PgA Support */
854 vlr_loc_upd_node_b(fi);
855 }
856}
857
858/* 4.1.2.1 after Authentication successful (or no auth rqd) */
859static void vlr_loc_upd_post_auth(struct osmo_fsm_inst *fi)
860{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100861 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200862 struct vlr_subscr *vsub = lfp->vsub;
Neels Hofmeyr7795a192018-03-10 00:26:36 +0100863 bool umts_aka;
Harald Welteb8b85a12016-06-17 00:06:42 +0200864
865 LOGPFSM(fi, "%s()\n", __func__);
866
867 OSMO_ASSERT(vsub);
868
Neels Hofmeyr1cb18a22022-10-11 00:18:04 +0200869 /* Continue with ciphering, if enabled.
870 * If auth/ciph is optional and the HLR returned no auth info, continue without ciphering. */
871 if (!is_cmc_smc_to_be_attempted(lfp)
872 || (vsub->sec_ctx == VLR_SEC_CTX_NONE && !lfp->is_ciphering_required)) {
Harald Welteb8b85a12016-06-17 00:06:42 +0200873 vlr_loc_upd_post_ciph(fi);
874 return;
875 }
876
Neels Hofmeyr2ef2da52017-12-18 01:23:42 +0100877 if (!vsub->last_tuple) {
878 LOGPFSML(fi, LOGL_ERROR, "No auth tuple available\n");
Neels Hofmeyrd2278ec2018-03-02 02:44:05 +0100879 lu_fsm_failure(fi, GSM48_REJECT_NETWORK_FAILURE);
Neels Hofmeyr2ef2da52017-12-18 01:23:42 +0100880 return;
881 }
882
Neels Hofmeyr7795a192018-03-10 00:26:36 +0100883 switch (vsub->sec_ctx) {
884 case VLR_SEC_CTX_GSM:
885 umts_aka = false;
886 break;
887 case VLR_SEC_CTX_UMTS:
888 umts_aka = true;
889 break;
890 default:
891 LOGPFSML(fi, LOGL_ERROR, "Cannot start ciphering, security context is not established\n");
892 lu_fsm_failure(fi, GSM48_REJECT_NETWORK_FAILURE);
893 return;
894 }
895
Harald Welteb8b85a12016-06-17 00:06:42 +0200896 if (vlr_set_ciph_mode(vsub->vlr, fi, lfp->msc_conn_ref,
Neels Hofmeyr7795a192018-03-10 00:26:36 +0100897 umts_aka,
Neels Hofmeyr54a706c2017-07-18 15:39:27 +0200898 vsub->vlr->cfg.retrieve_imeisv_ciphered)) {
Harald Welteb8b85a12016-06-17 00:06:42 +0200899 LOGPFSML(fi, LOGL_ERROR,
900 "Failed to send Ciphering Mode Command\n");
Neels Hofmeyrd2278ec2018-03-02 02:44:05 +0100901 lu_fsm_failure(fi, GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200902 return;
903 }
904
905 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_CIPH, LU_TIMEOUT_LONG, 0);
906}
907
908static void vlr_loc_upd_node1(struct osmo_fsm_inst *fi)
909{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100910 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200911 struct vlr_subscr *vsub = lfp->vsub;
912
913 LOGPFSM(fi, "%s()\n", __func__);
914
915 OSMO_ASSERT(vsub);
916
Neels Hofmeyrc48afa12022-10-10 23:47:04 +0200917 if (try_auth(lfp)) {
Harald Welteb8b85a12016-06-17 00:06:42 +0200918 /* Authenticate_VLR */
919 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_AUTH,
920 LU_TIMEOUT_LONG, 0);
Vadim Yanitskiy3daf0c22020-01-25 06:02:48 +0700921 vsub->auth_fsm = auth_fsm_start(lfp->vsub,
Neels Hofmeyr923b6642022-09-28 00:15:45 +0200922 fi,
Neels Hofmeyr3189f392022-10-26 18:11:58 +0200923 VLR_ULA_E_AUTH_SUCCESS,
Neels Hofmeyr1cb18a22022-10-11 00:18:04 +0200924 VLR_ULA_E_AUTH_NO_INFO,
Neels Hofmeyr66d4ab82022-09-28 12:26:32 +0200925 VLR_ULA_E_AUTH_FAILURE,
Harald Welteb8b85a12016-06-17 00:06:42 +0200926 lfp->is_r99,
927 lfp->is_utran);
928 } else {
929 /* no need for authentication */
930 vlr_loc_upd_post_auth(fi);
931 }
932}
933
Oliver Smithcbf2c932019-05-06 13:09:55 +0200934static void vlr_loc_upd_node1_pre(struct osmo_fsm_inst *fi)
935{
936 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
937 struct vlr_instance *vlr = lfp->vlr;
938
939 LOGPFSM(fi, "%s()\n", __func__);
940
941 if (vlr->cfg.check_imei_rqd && vlr->cfg.retrieve_imeisv_early) {
942 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_HLR_CHECK_IMEI_EARLY, vlr_timer(lfp->vlr, 3270), 3270);
943 vlr_subscr_tx_req_check_imei(lfp->vsub);
944 } else {
945 vlr_loc_upd_node1(fi);
946 }
947}
948
949/* End of Check_IMEI Procedure. Executed early (before the location update), so we can send the IMEI to the HLR even if
950 * the MS would be rejected in LU. See the "Configuring the Subscribers Create on Demand Feature" section of the OsmoHLR
951 * user manual for a detailed explanation of the use case. */
952static void lu_fsm_wait_hlr_check_imei_early(struct osmo_fsm_inst *fi, uint32_t event, void *data)
953{
954 switch (event) {
955 case VLR_ULA_E_HLR_IMEI_ACK:
956 vlr_loc_upd_node1(fi);
957 break;
958 case VLR_ULA_E_HLR_IMEI_NACK:
959 lu_fsm_failure(fi, GSM48_REJECT_ILLEGAL_ME);
960 break;
961 default:
962 OSMO_ASSERT(0);
963 break;
964 }
965}
966
Harald Welteb8b85a12016-06-17 00:06:42 +0200967static void vlr_loc_upd_want_imsi(struct osmo_fsm_inst *fi)
968{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100969 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200970 struct vlr_instance *vlr = lfp->vlr;
971
972 LOGPFSM(fi, "%s()\n", __func__);
973
974 OSMO_ASSERT(lfp->vsub);
975
976 /* Obtain_IMSI_VLR */
977 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_IMSI,
978 vlr_timer(vlr, 3270), 3270);
979 vlr->ops.tx_id_req(lfp->msc_conn_ref, GSM_MI_TYPE_IMSI);
Oliver Smithcbf2c932019-05-06 13:09:55 +0200980 /* will continue at vlr_loc_upd_node1_pre() once IMSI arrives */
Harald Welteb8b85a12016-06-17 00:06:42 +0200981}
982
983static int assoc_lfp_with_sub(struct osmo_fsm_inst *fi, struct vlr_subscr *vsub)
984{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100985 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200986 struct vlr_instance *vlr = lfp->vlr;
987
988 if (vsub->lu_fsm) {
989 LOGPFSML(fi, LOGL_ERROR,
990 "A Location Updating process is already pending for"
991 " this subscriber. Aborting.\n");
992 /* Also get rid of the other pending LU attempt? */
993 /*lu_fsm_failure(vsub->lu_fsm, GSM48_REJECT_CONGESTION);*/
994 lu_fsm_failure(fi, GSM48_REJECT_CONGESTION);
995 return -EINVAL;
996 }
997 vsub->lu_fsm = fi;
998 vsub->msc_conn_ref = lfp->msc_conn_ref;
999 /* FIXME: send new LAC to HLR? */
Max7d41d872018-12-19 11:48:33 +01001000 vsub->cgi.lai.lac = lfp->new_lai.lac;
Harald Welteb8b85a12016-06-17 00:06:42 +02001001 lfp->vsub = vsub;
1002 /* Tell MSC to associate this subscriber with the given
1003 * connection */
Neels Hofmeyr1035d902018-12-28 21:22:32 +01001004 if (vlr->ops.subscr_assoc(lfp->msc_conn_ref, lfp->vsub))
1005 lu_fsm_failure(fi, GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +02001006 return 0;
1007}
1008
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001009static int _lu_fsm_associate_vsub(struct osmo_fsm_inst *fi)
1010{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001011 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001012 struct vlr_instance *vlr = lfp->vlr;
1013 struct vlr_subscr *vsub = NULL;
1014
1015 if (!lfp->imsi[0]) {
1016 /* TMSI was used */
1017 lfp->lu_by_tmsi = true;
1018 /* TMSI clash: if a different subscriber already has this TMSI,
1019 * we will find that other subscriber in the VLR. So the IMSIs
1020 * would mismatch, but we don't know about it. Theoretically,
1021 * an authentication process would thwart any attempt to use
1022 * someone else's TMSI.
1023 * TODO: Otherwise we can ask for the IMSI and verify that it
1024 * matches the IMSI on record. */
Neels Hofmeyr7c5346c2019-02-19 02:36:35 +01001025 vsub = vlr_subscr_find_or_create_by_tmsi(vlr, lfp->tmsi, __func__, NULL);
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001026
1027 if (!vsub) {
1028 LOGPFSML(fi, LOGL_ERROR, "VLR subscriber allocation failed\n");
1029 lu_fsm_failure(fi, GSM48_REJECT_SRV_OPT_TMP_OUT_OF_ORDER);
1030 return -1;
1031 }
1032
1033 vsub->sub_dataconf_by_hlr_ind = false;
1034 if (assoc_lfp_with_sub(fi, vsub)) {
Neels Hofmeyr7c5346c2019-02-19 02:36:35 +01001035 vlr_subscr_put(vsub, __func__);
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001036 return -1; /* error, fsm failure invoked in assoc_lfp_with_sub() */
1037 }
Neels Hofmeyr7c5346c2019-02-19 02:36:35 +01001038 vlr_subscr_put(vsub, __func__);
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001039 } else {
1040 /* IMSI was used */
Neels Hofmeyr7c5346c2019-02-19 02:36:35 +01001041 vsub = vlr_subscr_find_or_create_by_imsi(vlr, lfp->imsi, __func__, NULL);
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001042
1043 if (!vsub) {
1044 LOGPFSML(fi, LOGL_ERROR, "VLR subscriber allocation failed\n");
1045 lu_fsm_failure(fi, GSM48_REJECT_SRV_OPT_TMP_OUT_OF_ORDER);
Neels Hofmeyr7c5346c2019-02-19 02:36:35 +01001046 vlr_subscr_put(vsub, __func__);
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001047 return -1;
1048 }
1049
1050 vsub->sub_dataconf_by_hlr_ind = false;
1051 if (assoc_lfp_with_sub(fi, vsub)) {
Neels Hofmeyr7c5346c2019-02-19 02:36:35 +01001052 vlr_subscr_put(vsub, __func__);
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001053 return -1; /* error, fsm failure invoked in assoc_lfp_with_sub() */
1054 }
Neels Hofmeyr7c5346c2019-02-19 02:36:35 +01001055 vlr_subscr_put(vsub, __func__);
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001056 }
1057 return 0;
1058}
1059
Harald Welteb8b85a12016-06-17 00:06:42 +02001060/* 4.1.2.1: Subscriber (via MSC/SGSN) requests location update */
1061static void _start_lu_main(struct osmo_fsm_inst *fi)
1062{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001063 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001064 struct vlr_instance *vlr = lfp->vlr;
Harald Welteb8b85a12016-06-17 00:06:42 +02001065
1066 /* TODO: PUESBINE related handling */
1067
1068 /* Is previous LAI in this VLR? */
1069 if (!lai_in_this_vlr(vlr, &lfp->old_lai)) {
1070#if 0
1071 /* FIXME: check previous VLR, (3) */
1072 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_PVLR,
1073 LU_TIMEOUT_LONG, 0);
1074 return;
1075#endif
1076 LOGPFSML(fi, LOGL_NOTICE, "LAI change from %s,"
1077 " but checking previous VLR not implemented\n",
Neels Hofmeyr379d5792018-02-22 04:04:54 +01001078 osmo_lai_name(&lfp->old_lai));
Harald Welteb8b85a12016-06-17 00:06:42 +02001079 }
1080
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001081 /* If this is a TMSI based LU, we may not have the IMSI. Make sure that
1082 * we know the IMSI, either on record, or request it. */
1083 if (!lfp->vsub->imsi[0])
1084 vlr_loc_upd_want_imsi(fi);
1085 else
Oliver Smithcbf2c932019-05-06 13:09:55 +02001086 vlr_loc_upd_node1_pre(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001087}
1088
Harald Welteb8b85a12016-06-17 00:06:42 +02001089static void lu_fsm_idle(struct osmo_fsm_inst *fi, uint32_t event,
1090 void *data)
1091{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001092 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001093 struct vlr_instance *vlr = lfp->vlr;
1094
1095 OSMO_ASSERT(event == VLR_ULA_E_UPDATE_LA);
1096
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001097 if (_lu_fsm_associate_vsub(fi))
1098 return; /* error. FSM already terminated. */
1099
1100 OSMO_ASSERT(lfp->vsub);
1101
Harald Welte0df904d2018-12-03 11:00:04 +01001102 /* At this point we know for which subscriber the location update is,
1103 * we now must inform SGs-UE FSM that we received a location update
1104 * via A, IU or Gs interface. */
1105 osmo_fsm_inst_dispatch(lfp->vsub->sgs_fsm, SGS_UE_E_RX_LU_FROM_A_IU_GS, NULL);
1106
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001107 /* See 3GPP TS 23.012, procedure Retrieve_IMEISV_If_Required */
1108 if ((!vlr->cfg.retrieve_imeisv_early)
1109 || (lfp->type == VLR_LU_TYPE_PERIODIC && lfp->vsub->imeisv[0])) {
Harald Welteb8b85a12016-06-17 00:06:42 +02001110 /* R_IMEISV_IR1 passed */
1111 _start_lu_main(fi);
1112 } else {
1113 vlr->ops.tx_id_req(lfp->msc_conn_ref, GSM_MI_TYPE_IMEISV);
1114 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_IMEISV,
1115 vlr_timer(vlr, 3270), 3270);
1116 }
1117}
1118
1119static void lu_fsm_wait_imeisv(struct osmo_fsm_inst *fi, uint32_t event,
1120 void *data)
1121{
1122 switch (event) {
1123 case VLR_ULA_E_ID_IMEISV:
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001124 /* IMEISV was copied in vlr_subscr_rx_id_resp(), and that's
1125 * where we received this event from. */
Harald Welteb8b85a12016-06-17 00:06:42 +02001126 _start_lu_main(fi);
1127 break;
1128 default:
Oliver Smithffd522e2019-05-10 14:39:37 +02001129 OSMO_ASSERT(0);
Harald Welteb8b85a12016-06-17 00:06:42 +02001130 break;
1131 }
1132}
1133
1134/* Wait for response from Send_Identification to PVLR */
1135static void lu_fsm_wait_pvlr(struct osmo_fsm_inst *fi, uint32_t event,
1136 void *data)
1137{
1138 switch (event) {
1139 case VLR_ULA_E_SEND_ID_ACK:
Oliver Smithcbf2c932019-05-06 13:09:55 +02001140 vlr_loc_upd_node1_pre(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001141 break;
1142 case VLR_ULA_E_SEND_ID_NACK:
1143 vlr_loc_upd_want_imsi(fi);
1144 break;
1145 default:
Oliver Smithffd522e2019-05-10 14:39:37 +02001146 OSMO_ASSERT(0);
Harald Welteb8b85a12016-06-17 00:06:42 +02001147 break;
1148 }
1149}
1150
1151/* Wait for result of Authenticate_VLR procedure */
1152static void lu_fsm_wait_auth(struct osmo_fsm_inst *fi, uint32_t event,
1153 void *data)
1154{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001155 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Neels Hofmeyr15809592018-04-06 02:57:51 +02001156 enum gsm48_reject_value *res = data;
Harald Welteb8b85a12016-06-17 00:06:42 +02001157
Harald Welteb8b85a12016-06-17 00:06:42 +02001158 lfp->upd_hlr_vlr_fsm = NULL;
1159
Neels Hofmeyr923b6642022-09-28 00:15:45 +02001160 switch (event) {
Neels Hofmeyr3189f392022-10-26 18:11:58 +02001161 case VLR_ULA_E_AUTH_SUCCESS:
Neels Hofmeyr923b6642022-09-28 00:15:45 +02001162 /* Result == Pass */
1163 vlr_loc_upd_post_auth(fi);
1164 return;
1165
1166 case VLR_ULA_E_AUTH_FAILURE:
Neels Hofmeyr1cb18a22022-10-11 00:18:04 +02001167 lu_fsm_failure(fi, res ? *res : GSM48_REJECT_NETWORK_FAILURE);
1168 return;
1169
1170 case VLR_ULA_E_AUTH_NO_INFO:
1171 /* HLR returned no auth info for the subscriber. Continue only if authentication is optional. */
1172 if (lfp->authentication_required || lfp->is_ciphering_required) {
1173 lu_fsm_failure(fi, res ? *res : GSM48_REJECT_NETWORK_FAILURE);
1174 return;
1175 }
1176 LOGPFSML(fi, LOGL_INFO,
1177 "Attaching subscriber without auth (auth is optional, and no auth info received from HLR)\n");
1178 vlr_loc_upd_post_auth(fi);
Neels Hofmeyr15809592018-04-06 02:57:51 +02001179 return;
Harald Welteb8b85a12016-06-17 00:06:42 +02001180
Neels Hofmeyr923b6642022-09-28 00:15:45 +02001181 default:
1182 OSMO_ASSERT(false);
1183 }
Harald Welteb8b85a12016-06-17 00:06:42 +02001184}
1185
1186static void lu_fsm_wait_ciph(struct osmo_fsm_inst *fi, uint32_t event,
1187 void *data)
1188{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001189 enum vlr_ciph_result_cause result = VLR_CIPH_REJECT;
Harald Welteb8b85a12016-06-17 00:06:42 +02001190
1191 OSMO_ASSERT(event == VLR_ULA_E_CIPH_RES);
1192
1193 if (!data)
1194 LOGPFSML(fi, LOGL_ERROR, "invalid ciphering result: NULL\n");
1195 else
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001196 result = *(enum vlr_ciph_result_cause*)data;
Harald Welteb8b85a12016-06-17 00:06:42 +02001197
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001198 switch (result) {
Harald Welteb8b85a12016-06-17 00:06:42 +02001199 case VLR_CIPH_COMPL:
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001200 vlr_loc_upd_post_ciph(fi);
1201 return;
Harald Welteb8b85a12016-06-17 00:06:42 +02001202 case VLR_CIPH_REJECT:
1203 LOGPFSM(fi, "ciphering rejected\n");
1204 lu_fsm_failure(fi, GSM48_REJECT_INVALID_MANDANTORY_INF);
1205 return;
1206 default:
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001207 LOGPFSML(fi, LOGL_ERROR, "invalid ciphering result: %d\n", result);
Harald Welteb8b85a12016-06-17 00:06:42 +02001208 lu_fsm_failure(fi, GSM48_REJECT_INVALID_MANDANTORY_INF);
1209 return;
1210 }
Harald Welteb8b85a12016-06-17 00:06:42 +02001211}
1212
1213static void lu_fsm_wait_imsi(struct osmo_fsm_inst *fi, uint32_t event,
1214 void *data)
1215{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001216 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001217 struct vlr_subscr *vsub = lfp->vsub;
1218 char *mi_string = data;
1219
1220 switch (event) {
1221 case VLR_ULA_E_ID_IMSI:
1222 vlr_subscr_set_imsi(vsub, mi_string);
Oliver Smithcbf2c932019-05-06 13:09:55 +02001223 vlr_loc_upd_node1_pre(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001224 break;
1225 default:
Oliver Smithffd522e2019-05-10 14:39:37 +02001226 OSMO_ASSERT(0);
Harald Welteb8b85a12016-06-17 00:06:42 +02001227 break;
1228 }
1229}
1230
1231/* At the end of Update_HLR_VLR */
1232static void lu_fsm_wait_hlr_ul_res(struct osmo_fsm_inst *fi, uint32_t event,
1233 void *data)
1234{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001235 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001236
1237 switch (event) {
1238 case VLR_ULA_E_HLR_LU_RES:
1239 /* pass-through this event to Update_HLR_VLR */
1240 if (data == NULL)
1241 osmo_fsm_inst_dispatch(lfp->upd_hlr_vlr_fsm, UPD_HLR_VLR_E_UPD_LOC_ACK, NULL);
1242 else
1243 osmo_fsm_inst_dispatch(lfp->upd_hlr_vlr_fsm, UPD_HLR_VLR_E_UPD_LOC_NACK, data);
1244 break;
1245 case VLR_ULA_E_UPD_HLR_COMPL:
1246 if (data == NULL) {
1247 /* successful case */
1248 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_LU_COMPL,
1249 LU_TIMEOUT_LONG, 0);
1250 vlr_loc_upd_start_lu_compl_fsm(fi);
1251 /* continue in MSC ?!? */
1252 } else {
1253 /* unsuccessful case */
Neels Hofmeyrdd2aeba2018-10-30 19:47:01 +01001254 enum gsm48_reject_value cause =
1255 *(enum gsm48_reject_value *)data;
Neels Hofmeyref9126c2017-07-18 15:38:39 +02001256 /* Ignoring standalone mode for now. */
Harald Welteb8b85a12016-06-17 00:06:42 +02001257 if (0 /* procedure_error && vlr->cfg.standalone_mode */) {
1258 osmo_fsm_inst_state_chg(fi,
1259 VLR_ULA_S_WAIT_LU_COMPL_STANDALONE,
1260 LU_TIMEOUT_LONG, 0);
1261 vlr_loc_upd_start_lu_compl_fsm(fi);
1262 } else {
1263 lu_fsm_failure(fi, cause);
1264 }
1265 }
1266 break;
Neels Hofmeyr364f9272019-08-22 17:20:14 +02001267 case VLR_ULA_E_ID_IMEI:
1268 case VLR_ULA_E_ID_IMEISV:
1269 /* Got the IMEI from ME, nothing to do right now though. */
1270 break;
Harald Welteb8b85a12016-06-17 00:06:42 +02001271 default:
Oliver Smithffd522e2019-05-10 14:39:37 +02001272 OSMO_ASSERT(0);
Harald Welteb8b85a12016-06-17 00:06:42 +02001273 break;
1274 }
1275}
1276
1277/* Wait for end of Location_Update_Completion_VLR */
1278static void lu_fsm_wait_lu_compl(struct osmo_fsm_inst *fi, uint32_t event,
1279 void *data)
1280{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001281 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001282 uint8_t cause;
1283
1284 switch (event) {
1285 case VLR_ULA_E_NEW_TMSI_ACK:
1286 osmo_fsm_inst_dispatch(lfp->lu_compl_vlr_fsm,
1287 LU_COMPL_VLR_E_NEW_TMSI_ACK, NULL);
1288 break;
1289 case VLR_ULA_E_ID_IMEI:
Neels Hofmeyr106ba522019-08-08 02:00:54 +02001290 case VLR_ULA_E_ID_IMEISV:
Oliver Smith7d053092018-12-14 17:37:38 +01001291 /* Got the IMEI from ME, now send it to HLR */
1292 vlr_subscr_tx_req_check_imei(lfp->vsub);
1293 break;
1294 case VLR_ULA_E_HLR_IMEI_ACK:
Harald Welteb8b85a12016-06-17 00:06:42 +02001295 osmo_fsm_inst_dispatch(lfp->lu_compl_vlr_fsm,
1296 LU_COMPL_VLR_E_IMEI_CHECK_ACK, NULL);
1297 break;
Oliver Smith7d053092018-12-14 17:37:38 +01001298 case VLR_ULA_E_HLR_IMEI_NACK:
1299 osmo_fsm_inst_dispatch(lfp->lu_compl_vlr_fsm,
1300 LU_COMPL_VLR_E_IMEI_CHECK_NACK, NULL);
1301 break;
Harald Welteb8b85a12016-06-17 00:06:42 +02001302 case VLR_ULA_E_LU_COMPL_SUCCESS:
1303 lu_fsm_discard_lu_compl_fsm(fi);
1304
1305 /* Update Register */
1306 /* TODO: Set_Notification_Type 23.078 */
1307 /* TODO: Notify_gsmSCF 23.078 */
1308 /* TODO: Authenticated Radio Contact Established -> ARC */
Stefan Sperling3a741282018-03-13 21:11:49 +01001309
1310 if (lfp->type == VLR_LU_TYPE_IMSI_ATTACH)
1311 lfp->vlr->ops.tx_mm_info(lfp->msc_conn_ref);
1312
Harald Welteb8b85a12016-06-17 00:06:42 +02001313 lu_fsm_success(fi);
1314 break;
1315 case VLR_ULA_E_LU_COMPL_FAILURE:
1316 cause = GSM48_REJECT_NETWORK_FAILURE;
1317 if (data)
1318 cause = *(uint8_t*)data;
1319 lu_fsm_discard_lu_compl_fsm(fi);
1320 lu_fsm_failure(fi, cause);
1321 break;
1322 default:
Oliver Smithffd522e2019-05-10 14:39:37 +02001323 OSMO_ASSERT(0);
Harald Welteb8b85a12016-06-17 00:06:42 +02001324 break;
1325 }
1326}
1327
1328/* Wait for end of Location_Update_Completion_VLR (standalone case) */
1329static void lu_fsm_wait_lu_compl_standalone(struct osmo_fsm_inst *fi,
1330 uint32_t event, void *data)
1331{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001332 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001333 struct vlr_subscr *vsub = lfp->vsub;
1334 uint8_t cause;
1335
1336 switch (event) {
1337 case VLR_ULA_E_NEW_TMSI_ACK:
1338 osmo_fsm_inst_dispatch(lfp->lu_compl_vlr_fsm,
1339 LU_COMPL_VLR_E_NEW_TMSI_ACK, NULL);
1340 break;
1341 case VLR_ULA_E_LU_COMPL_SUCCESS:
1342 lu_fsm_discard_lu_compl_fsm(fi);
1343 vsub->sub_dataconf_by_hlr_ind = false;
1344 lu_fsm_success(fi);
1345 break;
1346 case VLR_ULA_E_LU_COMPL_FAILURE:
1347 vsub->sub_dataconf_by_hlr_ind = false;
1348 cause = GSM48_REJECT_NETWORK_FAILURE;
1349 if (data)
1350 cause = *(uint8_t*)data;
1351 lu_fsm_discard_lu_compl_fsm(fi);
1352 lu_fsm_failure(fi, cause);
1353 break;
1354 default:
Oliver Smithffd522e2019-05-10 14:39:37 +02001355 OSMO_ASSERT(0);
Harald Welteb8b85a12016-06-17 00:06:42 +02001356 break;
1357 }
1358}
1359
1360static const struct osmo_fsm_state vlr_lu_fsm_states[] = {
1361 [VLR_ULA_S_IDLE] = {
1362 .in_event_mask = S(VLR_ULA_E_UPDATE_LA),
1363 .out_state_mask = S(VLR_ULA_S_WAIT_IMEISV) |
1364 S(VLR_ULA_S_WAIT_PVLR) |
1365 S(VLR_ULA_S_WAIT_IMSI) |
1366 S(VLR_ULA_S_WAIT_AUTH) |
Sylvain Munautda9f37e2019-03-14 11:02:36 +01001367 S(VLR_ULA_S_WAIT_CIPH) |
Oliver Smithcbf2c932019-05-06 13:09:55 +02001368 S(VLR_ULA_S_WAIT_HLR_CHECK_IMEI_EARLY) |
Harald Welteb8b85a12016-06-17 00:06:42 +02001369 S(VLR_ULA_S_WAIT_HLR_UPD) |
1370 S(VLR_ULA_S_DONE),
1371 .name = OSMO_STRINGIFY(VLR_ULA_S_IDLE),
1372 .action = lu_fsm_idle,
1373 },
1374 [VLR_ULA_S_WAIT_IMEISV] = {
1375 .in_event_mask = S(VLR_ULA_E_ID_IMEISV),
1376 .out_state_mask = S(VLR_ULA_S_WAIT_PVLR) |
1377 S(VLR_ULA_S_WAIT_IMSI) |
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001378 S(VLR_ULA_S_WAIT_AUTH) |
Sylvain Munautda9f37e2019-03-14 11:02:36 +01001379 S(VLR_ULA_S_WAIT_CIPH) |
Oliver Smithcbf2c932019-05-06 13:09:55 +02001380 S(VLR_ULA_S_WAIT_HLR_CHECK_IMEI_EARLY) |
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001381 S(VLR_ULA_S_WAIT_HLR_UPD) |
Harald Welteb8b85a12016-06-17 00:06:42 +02001382 S(VLR_ULA_S_DONE),
1383 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_IMEISV),
1384 .action = lu_fsm_wait_imeisv,
1385 },
1386 [VLR_ULA_S_WAIT_PVLR] = {
1387 .in_event_mask = S(VLR_ULA_E_SEND_ID_ACK) |
1388 S(VLR_ULA_E_SEND_ID_NACK),
1389 .out_state_mask = S(VLR_ULA_S_WAIT_IMSI) |
1390 S(VLR_ULA_S_WAIT_AUTH) |
Sylvain Munautda9f37e2019-03-14 11:02:36 +01001391 S(VLR_ULA_S_WAIT_CIPH) |
Oliver Smithcbf2c932019-05-06 13:09:55 +02001392 S(VLR_ULA_S_WAIT_HLR_CHECK_IMEI_EARLY) |
Harald Welteb8b85a12016-06-17 00:06:42 +02001393 S(VLR_ULA_S_DONE),
1394 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_PVLR),
1395 .action = lu_fsm_wait_pvlr,
1396 },
1397 [VLR_ULA_S_WAIT_AUTH] = {
Neels Hofmeyr3189f392022-10-26 18:11:58 +02001398 .in_event_mask = S(VLR_ULA_E_AUTH_SUCCESS) |
Neels Hofmeyr1cb18a22022-10-11 00:18:04 +02001399 S(VLR_ULA_E_AUTH_NO_INFO) |
Neels Hofmeyr923b6642022-09-28 00:15:45 +02001400 S(VLR_ULA_E_AUTH_FAILURE),
Harald Welteb8b85a12016-06-17 00:06:42 +02001401 .out_state_mask = S(VLR_ULA_S_WAIT_CIPH) |
1402 S(VLR_ULA_S_WAIT_LU_COMPL) |
1403 S(VLR_ULA_S_WAIT_HLR_UPD) |
1404 S(VLR_ULA_S_DONE),
1405 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_AUTH),
1406 .action = lu_fsm_wait_auth,
1407 },
1408 [VLR_ULA_S_WAIT_CIPH] = {
1409 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_CIPH),
1410 .in_event_mask = S(VLR_ULA_E_CIPH_RES),
1411 .out_state_mask = S(VLR_ULA_S_WAIT_LU_COMPL) |
1412 S(VLR_ULA_S_WAIT_HLR_UPD) |
1413 S(VLR_ULA_S_DONE),
1414 .action = lu_fsm_wait_ciph,
1415 },
1416 [VLR_ULA_S_WAIT_IMSI] = {
1417 .in_event_mask = S(VLR_ULA_E_ID_IMSI),
1418 .out_state_mask = S(VLR_ULA_S_WAIT_AUTH) |
Sylvain Munautda9f37e2019-03-14 11:02:36 +01001419 S(VLR_ULA_S_WAIT_CIPH) |
Oliver Smithcbf2c932019-05-06 13:09:55 +02001420 S(VLR_ULA_S_WAIT_HLR_CHECK_IMEI_EARLY) |
Harald Welteb8b85a12016-06-17 00:06:42 +02001421 S(VLR_ULA_S_WAIT_HLR_UPD) |
1422 S(VLR_ULA_S_DONE),
1423 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_IMSI),
1424 .action = lu_fsm_wait_imsi,
1425 },
Oliver Smithcbf2c932019-05-06 13:09:55 +02001426 [VLR_ULA_S_WAIT_HLR_CHECK_IMEI_EARLY] = {
1427 .in_event_mask = S(VLR_ULA_E_HLR_IMEI_ACK) |
1428 S(VLR_ULA_E_HLR_IMEI_NACK),
1429 .out_state_mask = S(VLR_ULA_S_WAIT_AUTH) |
1430 S(VLR_ULA_S_WAIT_CIPH) |
1431 S(VLR_ULA_S_WAIT_HLR_UPD) |
1432 S(VLR_ULA_S_WAIT_LU_COMPL) |
1433 S(VLR_ULA_S_DONE),
1434 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_HLR_CHECK_IMEI_EARLY),
1435 .action = lu_fsm_wait_hlr_check_imei_early,
1436 },
Harald Welteb8b85a12016-06-17 00:06:42 +02001437 [VLR_ULA_S_WAIT_HLR_UPD] = {
1438 .in_event_mask = S(VLR_ULA_E_HLR_LU_RES) |
Neels Hofmeyr364f9272019-08-22 17:20:14 +02001439 S(VLR_ULA_E_UPD_HLR_COMPL) |
1440 S(VLR_ULA_E_ID_IMEI) |
1441 S(VLR_ULA_E_ID_IMEISV),
Harald Welteb8b85a12016-06-17 00:06:42 +02001442 .out_state_mask = S(VLR_ULA_S_WAIT_LU_COMPL) |
1443 S(VLR_ULA_S_WAIT_LU_COMPL_STANDALONE) |
1444 S(VLR_ULA_S_DONE),
1445 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_HLR_UPD),
1446 .action = lu_fsm_wait_hlr_ul_res,
1447 },
1448 [VLR_ULA_S_WAIT_LU_COMPL] = {
1449 .in_event_mask = S(VLR_ULA_E_LU_COMPL_SUCCESS) |
1450 S(VLR_ULA_E_LU_COMPL_FAILURE) |
1451 S(VLR_ULA_E_NEW_TMSI_ACK) |
1452 S(VLR_ULA_E_ID_IMEI) |
Oliver Smith7d053092018-12-14 17:37:38 +01001453 S(VLR_ULA_E_ID_IMEISV) |
1454 S(VLR_ULA_E_HLR_IMEI_ACK) |
1455 S(VLR_ULA_E_HLR_IMEI_NACK),
Harald Welteb8b85a12016-06-17 00:06:42 +02001456 .out_state_mask = S(VLR_ULA_S_DONE),
1457 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_LU_COMPL),
1458 .action = lu_fsm_wait_lu_compl,
1459 },
1460 [VLR_ULA_S_WAIT_LU_COMPL_STANDALONE] = {
1461 .in_event_mask = S(VLR_ULA_E_LU_COMPL_SUCCESS) |
1462 S(VLR_ULA_E_LU_COMPL_FAILURE) |
1463 S(VLR_ULA_E_NEW_TMSI_ACK),
1464 .out_state_mask = S(VLR_ULA_S_DONE),
1465 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_LU_COMPL_STANDALONE),
1466 .action = lu_fsm_wait_lu_compl_standalone,
1467 },
1468 [VLR_ULA_S_DONE] = {
1469 .name = OSMO_STRINGIFY(VLR_ULA_S_DONE),
1470 .onenter = lu_fsm_dispatch_result,
1471 },
1472};
1473
1474static void fsm_lu_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
1475{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001476 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001477 struct vlr_subscr *vsub = lfp->vsub;
1478
1479 LOGPFSM(fi, "fsm_lu_cleanup called with cause %s\n",
1480 osmo_fsm_term_cause_name(cause));
1481 if (vsub && vsub->lu_fsm == fi)
1482 vsub->lu_fsm = NULL;
1483}
1484
1485static struct osmo_fsm vlr_lu_fsm = {
1486 .name = "vlr_lu_fsm",
1487 .states = vlr_lu_fsm_states,
1488 .num_states = ARRAY_SIZE(vlr_lu_fsm_states),
1489 .allstate_event_mask = 0,
1490 .allstate_action = NULL,
1491 .log_subsys = DVLR,
1492 .event_names = fsm_lu_event_names,
1493 .cleanup = fsm_lu_cleanup,
1494};
1495
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001496static inline struct lu_fsm_priv *lu_fsm_fi_priv(struct osmo_fsm_inst *fi)
1497{
1498 OSMO_ASSERT(fi->fsm == &vlr_lu_fsm);
1499 return (struct lu_fsm_priv*)fi->priv;
1500}
1501
Harald Welteb8b85a12016-06-17 00:06:42 +02001502struct osmo_fsm_inst *
1503vlr_loc_update(struct osmo_fsm_inst *parent,
1504 uint32_t parent_event_success,
1505 uint32_t parent_event_failure,
1506 void *parent_event_data,
1507 struct vlr_instance *vlr, void *msc_conn_ref,
1508 enum vlr_lu_type type, uint32_t tmsi, const char *imsi,
1509 const struct osmo_location_area_id *old_lai,
1510 const struct osmo_location_area_id *new_lai,
1511 bool authentication_required,
Neels Hofmeyrd99a6072022-10-10 23:34:48 +02001512 bool is_ciphering_to_be_attempted,
Neels Hofmeyr2ea72642022-10-10 23:35:47 +02001513 bool is_ciphering_required,
Sylvain Munautda9f37e2019-03-14 11:02:36 +01001514 uint8_t key_seq,
Harald Welteb8b85a12016-06-17 00:06:42 +02001515 bool is_r99, bool is_utran,
1516 bool assign_tmsi)
1517{
1518 struct osmo_fsm_inst *fi;
1519 struct lu_fsm_priv *lfp;
1520
Neels Hofmeyr2ea72642022-10-10 23:35:47 +02001521 if (is_ciphering_required)
1522 OSMO_ASSERT(is_ciphering_to_be_attempted);
1523
Harald Welteb8b85a12016-06-17 00:06:42 +02001524 fi = osmo_fsm_inst_alloc_child(&vlr_lu_fsm, parent, parent_event_failure);
1525 if (!fi)
1526 return NULL;
1527
1528 lfp = talloc_zero(fi, struct lu_fsm_priv);
1529 lfp->vlr = vlr;
1530 lfp->msc_conn_ref = msc_conn_ref;
1531 lfp->tmsi = tmsi;
1532 lfp->type = type;
1533 lfp->old_lai = *old_lai;
1534 lfp->new_lai = *new_lai;
1535 lfp->lu_by_tmsi = true;
1536 lfp->parent_event_success = parent_event_success;
1537 lfp->parent_event_failure = parent_event_failure;
1538 lfp->parent_event_data = parent_event_data;
1539 lfp->authentication_required = authentication_required;
Neels Hofmeyrd99a6072022-10-10 23:34:48 +02001540 lfp->is_ciphering_to_be_attempted = is_ciphering_to_be_attempted;
Neels Hofmeyr2ea72642022-10-10 23:35:47 +02001541 lfp->is_ciphering_required = is_ciphering_required;
Sylvain Munautda9f37e2019-03-14 11:02:36 +01001542 lfp->key_seq = key_seq;
Harald Welteb8b85a12016-06-17 00:06:42 +02001543 lfp->is_r99 = is_r99;
1544 lfp->is_utran = is_utran;
1545 lfp->assign_tmsi = assign_tmsi;
1546 if (imsi) {
1547 strncpy(lfp->imsi, imsi, sizeof(lfp->imsi)-1);
1548 lfp->imsi[sizeof(lfp->imsi)-1] = '\0';
1549 lfp->lu_by_tmsi = false;
1550 }
1551 fi->priv = lfp;
1552
1553 LOGPFSM(fi, "rev=%s net=%s%s%s\n",
1554 is_r99 ? "R99" : "GSM",
1555 is_utran ? "UTRAN" : "GERAN",
Neels Hofmeyrd99a6072022-10-10 23:34:48 +02001556 (authentication_required || is_ciphering_to_be_attempted) ?
Harald Welteb8b85a12016-06-17 00:06:42 +02001557 " Auth" : " (no Auth)",
Neels Hofmeyrd99a6072022-10-10 23:34:48 +02001558 (authentication_required || is_ciphering_to_be_attempted) ?
1559 (is_ciphering_to_be_attempted ? "+Ciph" : " (no Ciph)")
Harald Welteb8b85a12016-06-17 00:06:42 +02001560 : "");
1561
Neels Hofmeyr84da6b12016-05-20 21:59:55 +02001562 if (is_utran && !authentication_required)
1563 LOGPFSML(fi, LOGL_ERROR,
1564 "Authentication off on UTRAN network. Good luck.\n");
1565
Harald Welteb8b85a12016-06-17 00:06:42 +02001566 osmo_fsm_inst_dispatch(fi, VLR_ULA_E_UPDATE_LA, NULL);
1567
1568 return fi;
1569}
1570
Neels Hofmeyr15809592018-04-06 02:57:51 +02001571void vlr_loc_update_cancel(struct osmo_fsm_inst *fi,
1572 enum osmo_fsm_term_cause fsm_cause,
1573 uint8_t gsm48_cause)
Harald Welteb8b85a12016-06-17 00:06:42 +02001574{
Neels Hofmeyr15809592018-04-06 02:57:51 +02001575 struct lu_fsm_priv *lfp;
1576
1577 OSMO_ASSERT(fi);
1578 OSMO_ASSERT(fi->fsm == &vlr_lu_fsm);
1579
1580 lfp = fi->priv;
1581 lfp->rej_cause = gsm48_cause;
1582
1583 if (fi->state != VLR_ULA_S_DONE)
1584 lu_fsm_failure(fi, gsm48_cause);
Harald Welteb8b85a12016-06-17 00:06:42 +02001585}
1586
1587void vlr_lu_fsm_init(void)
1588{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001589 OSMO_ASSERT(osmo_fsm_register(&vlr_lu_fsm) == 0);
1590 OSMO_ASSERT(osmo_fsm_register(&upd_hlr_vlr_fsm) == 0);
1591 OSMO_ASSERT(osmo_fsm_register(&sub_pres_vlr_fsm) == 0);
1592 OSMO_ASSERT(osmo_fsm_register(&lu_compl_vlr_fsm) == 0);
Harald Welteb8b85a12016-06-17 00:06:42 +02001593}