blob: 8152d20e8d4c1ed8cf626d9e2d64dbb32e27a897 [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() */
Harald Welteb8b85a12016-06-17 00:06:42 +0200363 vlr_subscr_get(vsub);
364 }
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
369static void vlr_lu_compl_fsm_failure(struct osmo_fsm_inst *fi, uint8_t cause)
370{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100371 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200372 lcvp->vsub->vlr->ops.tx_lu_rej(lcvp->msc_conn_ref, cause);
373 _vlr_lu_compl_fsm_done(fi, VLR_FSM_RESULT_FAILURE, cause);
374}
375
376static void vlr_lu_compl_fsm_dispatch_result(struct osmo_fsm_inst *fi,
377 uint32_t prev_state)
378{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100379 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200380 if (!fi->proc.parent) {
381 LOGPFSML(fi, LOGL_ERROR, "No parent FSM\n");
382 return;
383 }
384 osmo_fsm_inst_dispatch(fi->proc.parent,
385 (lcvp->result == VLR_FSM_RESULT_SUCCESS)
386 ? lcvp->parent_event_success
387 : lcvp->parent_event_failure,
388 &lcvp->cause);
389}
390
391static void lu_compl_vlr_init(struct osmo_fsm_inst *fi, uint32_t event,
392 void *data)
393{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100394 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200395 struct vlr_subscr *vsub = lcvp->vsub;
396 struct vlr_instance *vlr;
397 OSMO_ASSERT(vsub);
398 vlr = vsub->vlr;
399 OSMO_ASSERT(vlr);
400
401 OSMO_ASSERT(event == LU_COMPL_VLR_E_START);
402
403 /* TODO: National Roaming restrictions? */
404 /* TODO: Roaming restriction due to unsupported feature in subscriber
405 * data? */
406 /* TODO: Regional subscription restriction? */
407 /* TODO: Administrative restriction of subscribres' access feature? */
408 /* TODO: AccessRestrictuionData parameter available? */
409 /* TODO: AccessRestrictionData permits RAT? */
410 /* Node 1 */
411 /* TODO: Autonomous CSG supported in VPLMN and allowed by HPLMN? */
412 /* TODO: Hybrid Cel / CSG Cell */
413 /* Node 2 */
414 vsub->la_allowed = true;
415 vsub->imsi_detached_flag = false;
416 /* Start Subscriber_Present_VLR Procedure */
417 osmo_fsm_inst_state_chg(fi, LU_COMPL_VLR_S_WAIT_SUB_PRES,
418 LU_TIMEOUT_LONG, 0);
419
Neels Hofmeyraa14bac2018-12-11 01:56:11 +0100420 /* If ms_not_reachable_flag == false, the sub_pres_vlr_fsm will anyway terminate straight away and dispatch
421 * LU_COMPL_VLR_E_SUB_PRES_COMPL to this fi, so we might as well skip that dance here and save some logging. */
422 if (vsub->ms_not_reachable_flag)
423 sub_pres_vlr_fsm_start(&lcvp->sub_pres_vlr_fsm, fi, vsub, LU_COMPL_VLR_E_SUB_PRES_COMPL);
424 else
425 osmo_fsm_inst_dispatch(fi, LU_COMPL_VLR_E_SUB_PRES_COMPL, NULL);
Harald Welteb8b85a12016-06-17 00:06:42 +0200426}
427
428static void lu_compl_vlr_new_tmsi(struct osmo_fsm_inst *fi)
429{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100430 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200431 struct vlr_subscr *vsub = lcvp->vsub;
432 struct vlr_instance *vlr = vsub->vlr;
433
434 LOGPFSM(fi, "%s()\n", __func__);
435
436 if (vlr_subscr_alloc_tmsi(vsub)) {
437 vlr_lu_compl_fsm_failure(fi,
438 GSM48_REJECT_SRV_OPT_TMP_OUT_OF_ORDER);
439 return;
440 }
441
442 osmo_fsm_inst_state_chg(fi, LU_COMPL_VLR_S_WAIT_TMSI_CNF,
443 vlr_timer(vlr, 3250), 3250);
444
445 vlr->ops.tx_lu_acc(lcvp->msc_conn_ref, vsub->tmsi_new);
446}
447
448/* After completion of Subscriber_Present_VLR */
449static void lu_compl_vlr_wait_subscr_pres(struct osmo_fsm_inst *fi,
450 uint32_t event,
451 void *data)
452{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100453 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200454 struct vlr_subscr *vsub = lcvp->vsub;
455 struct vlr_instance *vlr = vsub->vlr;
456
457 OSMO_ASSERT(event == LU_COMPL_VLR_E_SUB_PRES_COMPL);
458
459 lcvp->sub_pres_vlr_fsm = NULL;
460
461 /* TODO: Trace_Subscriber_Activity_VLR */
462
463 if (vlr->cfg.check_imei_rqd) {
464 /* Check IMEI VLR */
465 osmo_fsm_inst_state_chg(fi,
466 lcvp->assign_tmsi ?
467 LU_COMPL_VLR_S_WAIT_IMEI_TMSI
468 : LU_COMPL_VLR_S_WAIT_IMEI,
469 vlr_timer(vlr, 3270), 3270);
470 vlr->ops.tx_id_req(lcvp->msc_conn_ref, GSM_MI_TYPE_IMEI);
471 return;
472 }
473
474 /* Do we need to allocate a TMSI? */
475 if (lcvp->assign_tmsi) {
476 lu_compl_vlr_new_tmsi(fi);
477 return;
478 }
479
480 /* Location Updating Accept */
481 vlr->ops.tx_lu_acc(lcvp->msc_conn_ref, GSM_RESERVED_TMSI);
482 vlr_lu_compl_fsm_success(fi);
483}
484
485/* Waiting for completion of CHECK_IMEI_VLR */
486static void lu_compl_vlr_wait_imei(struct osmo_fsm_inst *fi, uint32_t event,
487 void *data)
488{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100489 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200490 struct vlr_subscr *vsub = lcvp->vsub;
491 struct vlr_instance *vlr = vsub->vlr;
492
493 switch (event) {
494 case LU_COMPL_VLR_E_IMEI_CHECK_ACK:
495 if (!vsub->imei[0]) {
496 /* Abort: Do nothing */
497 vlr_lu_compl_fsm_failure(fi,
498 GSM48_REJECT_PROTOCOL_ERROR);
499 return;
500 }
501 /* Pass */
502 break;
503
504 case LU_COMPL_VLR_E_IMEI_CHECK_NACK:
505 vlr_lu_compl_fsm_failure(fi, GSM48_REJECT_ILLEGAL_ME);
506 /* FIXME: IMEI Check Fail to VLR Application (Detach IMSI VLR) */
507 return;
508 }
509
510 /* IMEI is available. Allocate TMSI if needed. */
511 if (lcvp->assign_tmsi) {
512 if (fi->state != LU_COMPL_VLR_S_WAIT_IMEI_TMSI)
513 LOGPFSML(fi, LOGL_ERROR,
514 "TMSI required, expected to be in state"
515 " LU_COMPL_VLR_S_WAIT_IMEI_TMSI,"
516 " am in %s instead\n",
517 osmo_fsm_state_name(fi->fsm, fi->state));
518 /* Logged an error, continue anyway. */
519
520 lu_compl_vlr_new_tmsi(fi);
521
522 /* Wait for TMSI ack */
523 return;
524 }
525
526 /* No TMSI needed, accept now. */
527 vlr->ops.tx_lu_acc(lcvp->msc_conn_ref, GSM_RESERVED_TMSI);
528 vlr_lu_compl_fsm_success(fi);
529}
530
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100531static inline struct lu_compl_vlr_priv *lu_compl_vlr_fi_priv(struct osmo_fsm_inst *fi);
532
Harald Welteb8b85a12016-06-17 00:06:42 +0200533/* Waiting for TMSI confirmation */
534static void lu_compl_vlr_wait_tmsi(struct osmo_fsm_inst *fi, uint32_t event,
535 void *data)
536{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100537 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200538 struct vlr_subscr *vsub = lcvp->vsub;
539
540 OSMO_ASSERT(event == LU_COMPL_VLR_E_NEW_TMSI_ACK);
541
542 if (!vsub || vsub->tmsi_new == GSM_RESERVED_TMSI) {
543 LOGPFSML(fi, LOGL_ERROR, "TMSI Realloc Compl implies that"
544 " the subscriber has a new TMSI allocated, but"
545 " the new TMSI is unset.\n");
546 vlr_lu_compl_fsm_failure(fi, GSM48_REJECT_NETWORK_FAILURE);
547 return;
548 }
549
550 vsub->tmsi = vsub->tmsi_new;
551 vsub->tmsi_new = GSM_RESERVED_TMSI;
Neels Hofmeyr361e5712019-01-03 02:32:14 +0100552 vsub->vlr->ops.subscr_update(vsub);
Harald Welteb8b85a12016-06-17 00:06:42 +0200553
554 vlr_lu_compl_fsm_success(fi);
555}
556
557static const struct osmo_fsm_state lu_compl_vlr_states[] = {
558 [LU_COMPL_VLR_S_INIT] = {
559 .in_event_mask = S(LU_COMPL_VLR_E_START),
560 .out_state_mask = S(LU_COMPL_VLR_S_DONE) |
Neels Hofmeyrd50f8982018-12-11 02:24:57 +0100561 S(LU_COMPL_VLR_S_WAIT_SUB_PRES),
Harald Welteb8b85a12016-06-17 00:06:42 +0200562 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_INIT),
563 .action = lu_compl_vlr_init,
564 },
565 [LU_COMPL_VLR_S_WAIT_SUB_PRES] = {
566 .in_event_mask = S(LU_COMPL_VLR_E_SUB_PRES_COMPL),
567 .out_state_mask = S(LU_COMPL_VLR_S_WAIT_IMEI) |
568 S(LU_COMPL_VLR_S_WAIT_IMEI_TMSI) |
569 S(LU_COMPL_VLR_S_WAIT_TMSI_CNF) |
570 S(LU_COMPL_VLR_S_DONE),
571 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_SUB_PRES),
572 .action = lu_compl_vlr_wait_subscr_pres,
573 },
574 [LU_COMPL_VLR_S_WAIT_IMEI] = {
575 .in_event_mask = S(LU_COMPL_VLR_E_IMEI_CHECK_ACK) |
576 S(LU_COMPL_VLR_E_IMEI_CHECK_NACK),
577 .out_state_mask = S(LU_COMPL_VLR_S_DONE),
578 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_IMEI),
579 .action = lu_compl_vlr_wait_imei,
580 },
581 [LU_COMPL_VLR_S_WAIT_IMEI_TMSI] = {
582 .in_event_mask = S(LU_COMPL_VLR_E_IMEI_CHECK_ACK) |
583 S(LU_COMPL_VLR_E_IMEI_CHECK_NACK),
584 .out_state_mask = S(LU_COMPL_VLR_S_DONE) |
585 S(LU_COMPL_VLR_S_WAIT_TMSI_CNF),
586 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_IMEI_TMSI),
587 .action = lu_compl_vlr_wait_imei,
588 },
589 [LU_COMPL_VLR_S_WAIT_TMSI_CNF] = {
590 .in_event_mask = S(LU_COMPL_VLR_E_NEW_TMSI_ACK),
591 .out_state_mask = S(LU_COMPL_VLR_S_DONE),
592 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_TMSI_CNF),
593 .action = lu_compl_vlr_wait_tmsi,
594 },
595 [LU_COMPL_VLR_S_DONE] = {
596 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_DONE),
597 .onenter = vlr_lu_compl_fsm_dispatch_result,
598 },
599};
600
601static struct osmo_fsm lu_compl_vlr_fsm = {
602 .name = "lu_compl_vlr_fsm",
603 .states = lu_compl_vlr_states,
604 .num_states = ARRAY_SIZE(lu_compl_vlr_states),
605 .allstate_event_mask = 0,
606 .allstate_action = NULL,
607 .log_subsys = DVLR,
608 .event_names = lu_compl_vlr_event_names,
609};
610
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100611static inline struct lu_compl_vlr_priv *lu_compl_vlr_fi_priv(struct osmo_fsm_inst *fi)
612{
613 OSMO_ASSERT(fi->fsm == &lu_compl_vlr_fsm);
614 return (struct lu_compl_vlr_priv*)fi->priv;
615}
616
Harald Welteb8b85a12016-06-17 00:06:42 +0200617struct osmo_fsm_inst *
618lu_compl_vlr_proc_alloc(struct osmo_fsm_inst *parent,
619 struct vlr_subscr *vsub,
620 void *msc_conn_ref,
621 uint32_t parent_event_success,
622 uint32_t parent_event_failure,
623 bool assign_tmsi)
624{
625 struct osmo_fsm_inst *fi;
626 struct lu_compl_vlr_priv *lcvp;
627
628 fi = osmo_fsm_inst_alloc_child(&lu_compl_vlr_fsm, parent,
629 parent_event_failure);
630 if (!fi)
631 return NULL;
632
633 lcvp = talloc_zero(fi, struct lu_compl_vlr_priv);
634 lcvp->vsub = vsub;
635 lcvp->msc_conn_ref = msc_conn_ref;
636 lcvp->parent_event_success = parent_event_success;
637 lcvp->parent_event_failure = parent_event_failure;
638 lcvp->assign_tmsi = assign_tmsi;
639 fi->priv = lcvp;
640
641 return fi;
642}
643
644
645/***********************************************************************
646 * Update_Location_Area_VLR, TS 23.012 Chapter 4.1.2.1
647 ***********************************************************************/
648
649static const struct value_string fsm_lu_event_names[] = {
650 OSMO_VALUE_STRING(VLR_ULA_E_UPDATE_LA),
651 OSMO_VALUE_STRING(VLR_ULA_E_SEND_ID_ACK),
652 OSMO_VALUE_STRING(VLR_ULA_E_SEND_ID_NACK),
653 OSMO_VALUE_STRING(VLR_ULA_E_AUTH_RES),
654 OSMO_VALUE_STRING(VLR_ULA_E_CIPH_RES),
655 OSMO_VALUE_STRING(VLR_ULA_E_ID_IMSI),
656 OSMO_VALUE_STRING(VLR_ULA_E_ID_IMEI),
657 OSMO_VALUE_STRING(VLR_ULA_E_ID_IMEISV),
Oliver Smith7d053092018-12-14 17:37:38 +0100658 OSMO_VALUE_STRING(VLR_ULA_E_HLR_IMEI_ACK),
659 OSMO_VALUE_STRING(VLR_ULA_E_HLR_IMEI_NACK),
Harald Welteb8b85a12016-06-17 00:06:42 +0200660 OSMO_VALUE_STRING(VLR_ULA_E_HLR_LU_RES),
661 OSMO_VALUE_STRING(VLR_ULA_E_UPD_HLR_COMPL),
662 OSMO_VALUE_STRING(VLR_ULA_E_LU_COMPL_SUCCESS),
663 OSMO_VALUE_STRING(VLR_ULA_E_LU_COMPL_FAILURE),
664 OSMO_VALUE_STRING(VLR_ULA_E_NEW_TMSI_ACK),
665 { 0, NULL }
666};
667
668struct lu_fsm_priv {
669 struct vlr_instance *vlr;
670 struct vlr_subscr *vsub;
671 void *msc_conn_ref;
672 struct osmo_fsm_inst *upd_hlr_vlr_fsm;
673 struct osmo_fsm_inst *lu_compl_vlr_fsm;
674 uint32_t parent_event_success;
675 uint32_t parent_event_failure;
676 void *parent_event_data;
677 enum vlr_fsm_result result;
678 uint8_t rej_cause;
679
680 enum vlr_lu_type type;
681 bool lu_by_tmsi;
682 char imsi[16];
683 uint32_t tmsi;
684 struct osmo_location_area_id old_lai;
685 struct osmo_location_area_id new_lai;
686 bool authentication_required;
Harald Welte71c51df2017-12-23 18:51:48 +0100687 bool ciphering_required;
Harald Welteb8b85a12016-06-17 00:06:42 +0200688 bool is_r99;
689 bool is_utran;
690 bool assign_tmsi;
691};
692
693
694/* Determine if given location area is served by this VLR */
695static bool lai_in_this_vlr(struct vlr_instance *vlr,
696 const struct osmo_location_area_id *lai)
697{
698 /* TODO: VLR needs to keep a locally configued list of LAIs */
699 return true;
700}
701
702/* Determine if authentication is required */
703static bool is_auth_required(struct lu_fsm_priv *lfp)
704{
705 /* The cases where the authentication procedure should be used
706 * are defined in 3GPP TS 33.102 */
707 /* For now we use a default value passed in to vlr_lu_fsm(). */
Harald Welte71c51df2017-12-23 18:51:48 +0100708 return lfp->authentication_required || lfp->ciphering_required;
Harald Welteb8b85a12016-06-17 00:06:42 +0200709}
710
711/* Determine if ciphering is required */
712static bool is_ciph_required(struct lu_fsm_priv *lfp)
713{
Harald Welte71c51df2017-12-23 18:51:48 +0100714 return lfp->ciphering_required;
Harald Welteb8b85a12016-06-17 00:06:42 +0200715}
716
717/* Determine if a HLR Update is required */
718static bool hlr_update_needed(struct vlr_subscr *vsub)
719{
720 /* TODO: properly decide this, rather than always assuming we
721 * need to update the HLR. */
722 return true;
723}
724
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100725static inline struct lu_fsm_priv *lu_fsm_fi_priv(struct osmo_fsm_inst *fi);
726
Harald Welteb8b85a12016-06-17 00:06:42 +0200727static void lu_fsm_dispatch_result(struct osmo_fsm_inst *fi,
728 uint32_t prev_state)
729{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100730 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200731 if (!fi->proc.parent) {
732 LOGPFSML(fi, LOGL_ERROR, "No parent FSM\n");
733 return;
734 }
735 osmo_fsm_inst_dispatch(fi->proc.parent,
736 (lfp->result == VLR_FSM_RESULT_SUCCESS)
737 ? lfp->parent_event_success
738 : lfp->parent_event_failure,
739 lfp->parent_event_data);
740}
741
742static void _lu_fsm_done(struct osmo_fsm_inst *fi,
743 enum vlr_fsm_result result)
744{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100745 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200746 lfp->result = result;
747 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_DONE, 0, 0);
748}
749
750static void lu_fsm_success(struct osmo_fsm_inst *fi)
751{
752 _lu_fsm_done(fi, VLR_FSM_RESULT_SUCCESS);
753}
754
Neels Hofmeyr15809592018-04-06 02:57:51 +0200755static void lu_fsm_failure(struct osmo_fsm_inst *fi, enum gsm48_reject_value rej_cause)
Harald Welteb8b85a12016-06-17 00:06:42 +0200756{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100757 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Neels Hofmeyr15809592018-04-06 02:57:51 +0200758 lfp->vlr->ops.tx_lu_rej(lfp->msc_conn_ref, rej_cause ? : GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200759 _lu_fsm_done(fi, VLR_FSM_RESULT_FAILURE);
760}
761
762static void vlr_loc_upd_start_lu_compl_fsm(struct osmo_fsm_inst *fi)
763{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100764 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200765 lfp->lu_compl_vlr_fsm =
766 lu_compl_vlr_proc_alloc(fi, lfp->vsub, lfp->msc_conn_ref,
767 VLR_ULA_E_LU_COMPL_SUCCESS,
768 VLR_ULA_E_LU_COMPL_FAILURE,
769 lfp->assign_tmsi);
770
771 osmo_fsm_inst_dispatch(lfp->lu_compl_vlr_fsm, LU_COMPL_VLR_E_START, NULL);
772}
773
774static void lu_fsm_discard_lu_compl_fsm(struct osmo_fsm_inst *fi)
775{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100776 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200777 if (!lfp->lu_compl_vlr_fsm)
778 return;
779 osmo_fsm_inst_term(lfp->lu_compl_vlr_fsm, OSMO_FSM_TERM_PARENT, NULL);
780}
781
782/* 4.1.2.1 Node 4 */
783static void vlr_loc_upd_node_4(struct osmo_fsm_inst *fi)
784{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100785 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200786 struct vlr_subscr *vsub = lfp->vsub;
787 bool hlr_unknown = false;
788
789 LOGPFSM(fi, "%s()\n", __func__);
790
791 if (hlr_unknown) {
792 /* FIXME: Delete subscriber record */
793 /* LU REJ: Roaming not allowed */
794 lu_fsm_failure(fi, GSM48_REJECT_ROAMING_NOT_ALLOWED);
795 } else {
796 /* Update_HLR_VLR */
797 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_HLR_UPD,
798 LU_TIMEOUT_LONG, 0);
799 lfp->upd_hlr_vlr_fsm =
800 upd_hlr_vlr_proc_start(fi, vsub, VLR_ULA_E_UPD_HLR_COMPL);
801 }
802}
803
804/* 4.1.2.1 Node B */
805static void vlr_loc_upd_node_b(struct osmo_fsm_inst *fi)
806{
807 LOGPFSM(fi, "%s()\n", __func__);
808
Neels Hofmeyref9126c2017-07-18 15:38:39 +0200809 /* OsmoHLR does not support PgA, neither stores the IMEISV, so we have no need to update the HLR
810 * with either. TODO: depend on actual HLR configuration. See 3GPP TS 23.012 Release 14, process
811 * Update_Location_Area_VLR (ULA_VLR2). */
Harald Welteb8b85a12016-06-17 00:06:42 +0200812 if (0) { /* IMEISV or PgA to send */
813 vlr_loc_upd_node_4(fi);
814 } else {
815 /* Location_Update_Completion */
816 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_LU_COMPL,
817 LU_TIMEOUT_LONG, 0);
818 vlr_loc_upd_start_lu_compl_fsm(fi);
819 }
820}
821
822/* Non-standard: after Ciphering Mode Complete (or no ciph required) */
823static void vlr_loc_upd_post_ciph(struct osmo_fsm_inst *fi)
824{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100825 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200826 struct vlr_subscr *vsub = lfp->vsub;
827
828 LOGPFSM(fi, "%s()\n", __func__);
829
830 OSMO_ASSERT(vsub);
831
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200832 if (lfp->is_utran) {
833 int rc;
834 rc = lfp->vlr->ops.tx_common_id(lfp->msc_conn_ref);
835 if (rc)
836 LOGPFSML(fi, LOGL_ERROR,
837 "Error while sending Common ID (%d)\n", rc);
838 }
839
Harald Welteb8b85a12016-06-17 00:06:42 +0200840 vsub->conf_by_radio_contact_ind = true;
841 /* Update LAI */
842 vsub->cgi.lai = lfp->new_lai;
843 vsub->dormant_ind = false;
844 vsub->cancel_loc_rx = false;
845 if (hlr_update_needed(vsub)) {
846 vlr_loc_upd_node_4(fi);
847 } else {
848 /* TODO: ADD Support */
849 /* TODO: Node A: PgA Support */
850 vlr_loc_upd_node_b(fi);
851 }
852}
853
854/* 4.1.2.1 after Authentication successful (or no auth rqd) */
855static void vlr_loc_upd_post_auth(struct osmo_fsm_inst *fi)
856{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100857 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200858 struct vlr_subscr *vsub = lfp->vsub;
Neels Hofmeyr7795a192018-03-10 00:26:36 +0100859 bool umts_aka;
Harald Welteb8b85a12016-06-17 00:06:42 +0200860
861 LOGPFSM(fi, "%s()\n", __func__);
862
863 OSMO_ASSERT(vsub);
864
865 if (!is_ciph_required(lfp)) {
866 vlr_loc_upd_post_ciph(fi);
867 return;
868 }
869
Neels Hofmeyr2ef2da52017-12-18 01:23:42 +0100870 if (!vsub->last_tuple) {
871 LOGPFSML(fi, LOGL_ERROR, "No auth tuple available\n");
Neels Hofmeyrd2278ec2018-03-02 02:44:05 +0100872 lu_fsm_failure(fi, GSM48_REJECT_NETWORK_FAILURE);
Neels Hofmeyr2ef2da52017-12-18 01:23:42 +0100873 return;
874 }
875
Neels Hofmeyr7795a192018-03-10 00:26:36 +0100876 switch (vsub->sec_ctx) {
877 case VLR_SEC_CTX_GSM:
878 umts_aka = false;
879 break;
880 case VLR_SEC_CTX_UMTS:
881 umts_aka = true;
882 break;
883 default:
884 LOGPFSML(fi, LOGL_ERROR, "Cannot start ciphering, security context is not established\n");
885 lu_fsm_failure(fi, GSM48_REJECT_NETWORK_FAILURE);
886 return;
887 }
888
Harald Welteb8b85a12016-06-17 00:06:42 +0200889 if (vlr_set_ciph_mode(vsub->vlr, fi, lfp->msc_conn_ref,
890 lfp->ciphering_required,
Neels Hofmeyr7795a192018-03-10 00:26:36 +0100891 umts_aka,
Neels Hofmeyr54a706c2017-07-18 15:39:27 +0200892 vsub->vlr->cfg.retrieve_imeisv_ciphered)) {
Harald Welteb8b85a12016-06-17 00:06:42 +0200893 LOGPFSML(fi, LOGL_ERROR,
894 "Failed to send Ciphering Mode Command\n");
Neels Hofmeyrd2278ec2018-03-02 02:44:05 +0100895 lu_fsm_failure(fi, GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200896 return;
897 }
898
899 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_CIPH, LU_TIMEOUT_LONG, 0);
900}
901
902static void vlr_loc_upd_node1(struct osmo_fsm_inst *fi)
903{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100904 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200905 struct vlr_subscr *vsub = lfp->vsub;
906
907 LOGPFSM(fi, "%s()\n", __func__);
908
909 OSMO_ASSERT(vsub);
910
911 if (is_auth_required(lfp)) {
912 /* Authenticate_VLR */
913 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_AUTH,
914 LU_TIMEOUT_LONG, 0);
915 vsub->auth_fsm = auth_fsm_start(lfp->vsub, fi->log_level,
916 fi, VLR_ULA_E_AUTH_RES,
917 lfp->is_r99,
918 lfp->is_utran);
919 } else {
920 /* no need for authentication */
921 vlr_loc_upd_post_auth(fi);
922 }
923}
924
925static void vlr_loc_upd_want_imsi(struct osmo_fsm_inst *fi)
926{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100927 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200928 struct vlr_instance *vlr = lfp->vlr;
929
930 LOGPFSM(fi, "%s()\n", __func__);
931
932 OSMO_ASSERT(lfp->vsub);
933
934 /* Obtain_IMSI_VLR */
935 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_IMSI,
936 vlr_timer(vlr, 3270), 3270);
937 vlr->ops.tx_id_req(lfp->msc_conn_ref, GSM_MI_TYPE_IMSI);
938 /* will continue at vlr_loc_upd_node1() once IMSI arrives */
939}
940
941static int assoc_lfp_with_sub(struct osmo_fsm_inst *fi, struct vlr_subscr *vsub)
942{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100943 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200944 struct vlr_instance *vlr = lfp->vlr;
945
946 if (vsub->lu_fsm) {
947 LOGPFSML(fi, LOGL_ERROR,
948 "A Location Updating process is already pending for"
949 " this subscriber. Aborting.\n");
950 /* Also get rid of the other pending LU attempt? */
951 /*lu_fsm_failure(vsub->lu_fsm, GSM48_REJECT_CONGESTION);*/
952 lu_fsm_failure(fi, GSM48_REJECT_CONGESTION);
953 return -EINVAL;
954 }
955 vsub->lu_fsm = fi;
956 vsub->msc_conn_ref = lfp->msc_conn_ref;
957 /* FIXME: send new LAC to HLR? */
Max7d41d872018-12-19 11:48:33 +0100958 vsub->cgi.lai.lac = lfp->new_lai.lac;
Harald Welteb8b85a12016-06-17 00:06:42 +0200959 lfp->vsub = vsub;
960 /* Tell MSC to associate this subscriber with the given
961 * connection */
Neels Hofmeyr1035d902018-12-28 21:22:32 +0100962 if (vlr->ops.subscr_assoc(lfp->msc_conn_ref, lfp->vsub))
963 lu_fsm_failure(fi, GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200964 return 0;
965}
966
Neels Hofmeyr54a706c2017-07-18 15:39:27 +0200967static int _lu_fsm_associate_vsub(struct osmo_fsm_inst *fi)
968{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100969 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Neels Hofmeyr54a706c2017-07-18 15:39:27 +0200970 struct vlr_instance *vlr = lfp->vlr;
971 struct vlr_subscr *vsub = NULL;
972
973 if (!lfp->imsi[0]) {
974 /* TMSI was used */
975 lfp->lu_by_tmsi = true;
976 /* TMSI clash: if a different subscriber already has this TMSI,
977 * we will find that other subscriber in the VLR. So the IMSIs
978 * would mismatch, but we don't know about it. Theoretically,
979 * an authentication process would thwart any attempt to use
980 * someone else's TMSI.
981 * TODO: Otherwise we can ask for the IMSI and verify that it
982 * matches the IMSI on record. */
983 vsub = vlr_subscr_find_or_create_by_tmsi(vlr, lfp->tmsi, NULL);
984
985 if (!vsub) {
986 LOGPFSML(fi, LOGL_ERROR, "VLR subscriber allocation failed\n");
987 lu_fsm_failure(fi, GSM48_REJECT_SRV_OPT_TMP_OUT_OF_ORDER);
988 return -1;
989 }
990
991 vsub->sub_dataconf_by_hlr_ind = false;
992 if (assoc_lfp_with_sub(fi, vsub)) {
993 vlr_subscr_put(vsub);
994 return -1; /* error, fsm failure invoked in assoc_lfp_with_sub() */
995 }
996 vlr_subscr_put(vsub);
997 } else {
998 /* IMSI was used */
999 vsub = vlr_subscr_find_or_create_by_imsi(vlr, lfp->imsi, NULL);
1000
1001 if (!vsub) {
1002 LOGPFSML(fi, LOGL_ERROR, "VLR subscriber allocation failed\n");
1003 lu_fsm_failure(fi, GSM48_REJECT_SRV_OPT_TMP_OUT_OF_ORDER);
1004 vlr_subscr_put(vsub);
1005 return -1;
1006 }
1007
1008 vsub->sub_dataconf_by_hlr_ind = false;
1009 if (assoc_lfp_with_sub(fi, vsub)) {
1010 vlr_subscr_put(vsub);
1011 return -1; /* error, fsm failure invoked in assoc_lfp_with_sub() */
1012 }
1013 vlr_subscr_put(vsub);
1014 }
1015 return 0;
1016}
1017
Harald Welteb8b85a12016-06-17 00:06:42 +02001018/* 4.1.2.1: Subscriber (via MSC/SGSN) requests location update */
1019static void _start_lu_main(struct osmo_fsm_inst *fi)
1020{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001021 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001022 struct vlr_instance *vlr = lfp->vlr;
Harald Welteb8b85a12016-06-17 00:06:42 +02001023
1024 /* TODO: PUESBINE related handling */
1025
1026 /* Is previous LAI in this VLR? */
1027 if (!lai_in_this_vlr(vlr, &lfp->old_lai)) {
1028#if 0
1029 /* FIXME: check previous VLR, (3) */
1030 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_PVLR,
1031 LU_TIMEOUT_LONG, 0);
1032 return;
1033#endif
1034 LOGPFSML(fi, LOGL_NOTICE, "LAI change from %s,"
1035 " but checking previous VLR not implemented\n",
Neels Hofmeyr379d5792018-02-22 04:04:54 +01001036 osmo_lai_name(&lfp->old_lai));
Harald Welteb8b85a12016-06-17 00:06:42 +02001037 }
1038
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001039 /* If this is a TMSI based LU, we may not have the IMSI. Make sure that
1040 * we know the IMSI, either on record, or request it. */
1041 if (!lfp->vsub->imsi[0])
1042 vlr_loc_upd_want_imsi(fi);
1043 else
Harald Welteb8b85a12016-06-17 00:06:42 +02001044 vlr_loc_upd_node1(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001045}
1046
Harald Welteb8b85a12016-06-17 00:06:42 +02001047static void lu_fsm_idle(struct osmo_fsm_inst *fi, uint32_t event,
1048 void *data)
1049{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001050 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001051 struct vlr_instance *vlr = lfp->vlr;
1052
1053 OSMO_ASSERT(event == VLR_ULA_E_UPDATE_LA);
1054
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001055 if (_lu_fsm_associate_vsub(fi))
1056 return; /* error. FSM already terminated. */
1057
1058 OSMO_ASSERT(lfp->vsub);
1059
Harald Welte0df904d2018-12-03 11:00:04 +01001060 /* At this point we know for which subscriber the location update is,
1061 * we now must inform SGs-UE FSM that we received a location update
1062 * via A, IU or Gs interface. */
1063 osmo_fsm_inst_dispatch(lfp->vsub->sgs_fsm, SGS_UE_E_RX_LU_FROM_A_IU_GS, NULL);
1064
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001065 /* See 3GPP TS 23.012, procedure Retrieve_IMEISV_If_Required */
1066 if ((!vlr->cfg.retrieve_imeisv_early)
1067 || (lfp->type == VLR_LU_TYPE_PERIODIC && lfp->vsub->imeisv[0])) {
Harald Welteb8b85a12016-06-17 00:06:42 +02001068 /* R_IMEISV_IR1 passed */
1069 _start_lu_main(fi);
1070 } else {
1071 vlr->ops.tx_id_req(lfp->msc_conn_ref, GSM_MI_TYPE_IMEISV);
1072 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_IMEISV,
1073 vlr_timer(vlr, 3270), 3270);
1074 }
1075}
1076
1077static void lu_fsm_wait_imeisv(struct osmo_fsm_inst *fi, uint32_t event,
1078 void *data)
1079{
1080 switch (event) {
1081 case VLR_ULA_E_ID_IMEISV:
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001082 /* IMEISV was copied in vlr_subscr_rx_id_resp(), and that's
1083 * where we received this event from. */
Harald Welteb8b85a12016-06-17 00:06:42 +02001084 _start_lu_main(fi);
1085 break;
1086 default:
1087 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1088 osmo_fsm_event_name(fi->fsm, event));
1089 break;
1090 }
1091}
1092
1093/* Wait for response from Send_Identification to PVLR */
1094static void lu_fsm_wait_pvlr(struct osmo_fsm_inst *fi, uint32_t event,
1095 void *data)
1096{
1097 switch (event) {
1098 case VLR_ULA_E_SEND_ID_ACK:
1099 vlr_loc_upd_node1(fi);
1100 break;
1101 case VLR_ULA_E_SEND_ID_NACK:
1102 vlr_loc_upd_want_imsi(fi);
1103 break;
1104 default:
1105 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1106 osmo_fsm_event_name(fi->fsm, event));
1107 break;
1108 }
1109}
1110
1111/* Wait for result of Authenticate_VLR procedure */
1112static void lu_fsm_wait_auth(struct osmo_fsm_inst *fi, uint32_t event,
1113 void *data)
1114{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001115 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Neels Hofmeyr15809592018-04-06 02:57:51 +02001116 enum gsm48_reject_value *res = data;
Harald Welteb8b85a12016-06-17 00:06:42 +02001117
1118 OSMO_ASSERT(event == VLR_ULA_E_AUTH_RES);
1119
1120 lfp->upd_hlr_vlr_fsm = NULL;
1121
Neels Hofmeyr15809592018-04-06 02:57:51 +02001122 if (!res || *res) {
1123 lu_fsm_failure(fi, res? *res : GSM48_REJECT_NETWORK_FAILURE);
1124 return;
1125 }
Harald Welteb8b85a12016-06-17 00:06:42 +02001126
Neels Hofmeyr15809592018-04-06 02:57:51 +02001127 /* Result == Pass */
1128 vlr_loc_upd_post_auth(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001129}
1130
1131static void lu_fsm_wait_ciph(struct osmo_fsm_inst *fi, uint32_t event,
1132 void *data)
1133{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001134 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001135 struct vlr_subscr *vsub = lfp->vsub;
1136 struct vlr_ciph_result res = { .cause = VLR_CIPH_REJECT };
1137
1138 OSMO_ASSERT(event == VLR_ULA_E_CIPH_RES);
1139
1140 if (!data)
1141 LOGPFSML(fi, LOGL_ERROR, "invalid ciphering result: NULL\n");
1142 else
1143 res = *(struct vlr_ciph_result*)data;
1144
1145 switch (res.cause) {
1146 case VLR_CIPH_COMPL:
1147 break;
1148 case VLR_CIPH_REJECT:
1149 LOGPFSM(fi, "ciphering rejected\n");
1150 lu_fsm_failure(fi, GSM48_REJECT_INVALID_MANDANTORY_INF);
1151 return;
1152 default:
1153 LOGPFSML(fi, LOGL_ERROR, "invalid ciphering result: %d\n",
1154 res.cause);
1155 lu_fsm_failure(fi, GSM48_REJECT_INVALID_MANDANTORY_INF);
1156 return;
1157 }
1158
Neels Hofmeyrfa10eda2018-03-13 01:22:01 +01001159 if (*res.imeisv) {
Harald Welteb8b85a12016-06-17 00:06:42 +02001160 LOGPFSM(fi, "got IMEISV: %s\n", res.imeisv);
1161 vlr_subscr_set_imeisv(vsub, res.imeisv);
1162 }
1163 vlr_loc_upd_post_ciph(fi);
1164}
1165
1166static void lu_fsm_wait_imsi(struct osmo_fsm_inst *fi, uint32_t event,
1167 void *data)
1168{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001169 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001170 struct vlr_subscr *vsub = lfp->vsub;
1171 char *mi_string = data;
1172
1173 switch (event) {
1174 case VLR_ULA_E_ID_IMSI:
1175 vlr_subscr_set_imsi(vsub, mi_string);
1176 vlr_loc_upd_node1(fi);
1177 break;
1178 default:
1179 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1180 osmo_fsm_event_name(fi->fsm, event));
1181 break;
1182 }
1183}
1184
1185/* At the end of Update_HLR_VLR */
1186static void lu_fsm_wait_hlr_ul_res(struct osmo_fsm_inst *fi, uint32_t event,
1187 void *data)
1188{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001189 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001190
1191 switch (event) {
1192 case VLR_ULA_E_HLR_LU_RES:
1193 /* pass-through this event to Update_HLR_VLR */
1194 if (data == NULL)
1195 osmo_fsm_inst_dispatch(lfp->upd_hlr_vlr_fsm, UPD_HLR_VLR_E_UPD_LOC_ACK, NULL);
1196 else
1197 osmo_fsm_inst_dispatch(lfp->upd_hlr_vlr_fsm, UPD_HLR_VLR_E_UPD_LOC_NACK, data);
1198 break;
1199 case VLR_ULA_E_UPD_HLR_COMPL:
1200 if (data == NULL) {
1201 /* successful case */
1202 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_LU_COMPL,
1203 LU_TIMEOUT_LONG, 0);
1204 vlr_loc_upd_start_lu_compl_fsm(fi);
1205 /* continue in MSC ?!? */
1206 } else {
1207 /* unsuccessful case */
Neels Hofmeyrdd2aeba2018-10-30 19:47:01 +01001208 enum gsm48_reject_value cause =
1209 *(enum gsm48_reject_value *)data;
Neels Hofmeyref9126c2017-07-18 15:38:39 +02001210 /* Ignoring standalone mode for now. */
Harald Welteb8b85a12016-06-17 00:06:42 +02001211 if (0 /* procedure_error && vlr->cfg.standalone_mode */) {
1212 osmo_fsm_inst_state_chg(fi,
1213 VLR_ULA_S_WAIT_LU_COMPL_STANDALONE,
1214 LU_TIMEOUT_LONG, 0);
1215 vlr_loc_upd_start_lu_compl_fsm(fi);
1216 } else {
1217 lu_fsm_failure(fi, cause);
1218 }
1219 }
1220 break;
1221 default:
1222 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1223 osmo_fsm_event_name(fi->fsm, event));
1224 break;
1225 }
1226}
1227
1228/* Wait for end of Location_Update_Completion_VLR */
1229static void lu_fsm_wait_lu_compl(struct osmo_fsm_inst *fi, uint32_t event,
1230 void *data)
1231{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001232 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001233 uint8_t cause;
1234
1235 switch (event) {
1236 case VLR_ULA_E_NEW_TMSI_ACK:
1237 osmo_fsm_inst_dispatch(lfp->lu_compl_vlr_fsm,
1238 LU_COMPL_VLR_E_NEW_TMSI_ACK, NULL);
1239 break;
1240 case VLR_ULA_E_ID_IMEI:
Oliver Smith7d053092018-12-14 17:37:38 +01001241 /* Got the IMEI from ME, now send it to HLR */
1242 vlr_subscr_tx_req_check_imei(lfp->vsub);
1243 break;
1244 case VLR_ULA_E_HLR_IMEI_ACK:
Harald Welteb8b85a12016-06-17 00:06:42 +02001245 osmo_fsm_inst_dispatch(lfp->lu_compl_vlr_fsm,
1246 LU_COMPL_VLR_E_IMEI_CHECK_ACK, NULL);
1247 break;
Oliver Smith7d053092018-12-14 17:37:38 +01001248 case VLR_ULA_E_HLR_IMEI_NACK:
1249 osmo_fsm_inst_dispatch(lfp->lu_compl_vlr_fsm,
1250 LU_COMPL_VLR_E_IMEI_CHECK_NACK, NULL);
1251 break;
Harald Welteb8b85a12016-06-17 00:06:42 +02001252 case VLR_ULA_E_LU_COMPL_SUCCESS:
1253 lu_fsm_discard_lu_compl_fsm(fi);
1254
1255 /* Update Register */
1256 /* TODO: Set_Notification_Type 23.078 */
1257 /* TODO: Notify_gsmSCF 23.078 */
1258 /* TODO: Authenticated Radio Contact Established -> ARC */
Stefan Sperling3a741282018-03-13 21:11:49 +01001259
1260 if (lfp->type == VLR_LU_TYPE_IMSI_ATTACH)
1261 lfp->vlr->ops.tx_mm_info(lfp->msc_conn_ref);
1262
Harald Welteb8b85a12016-06-17 00:06:42 +02001263 lu_fsm_success(fi);
1264 break;
1265 case VLR_ULA_E_LU_COMPL_FAILURE:
1266 cause = GSM48_REJECT_NETWORK_FAILURE;
1267 if (data)
1268 cause = *(uint8_t*)data;
1269 lu_fsm_discard_lu_compl_fsm(fi);
1270 lu_fsm_failure(fi, cause);
1271 break;
1272 default:
1273 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1274 osmo_fsm_event_name(fi->fsm, event));
1275 break;
1276 }
1277}
1278
1279/* Wait for end of Location_Update_Completion_VLR (standalone case) */
1280static void lu_fsm_wait_lu_compl_standalone(struct osmo_fsm_inst *fi,
1281 uint32_t event, void *data)
1282{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001283 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001284 struct vlr_subscr *vsub = lfp->vsub;
1285 uint8_t cause;
1286
1287 switch (event) {
1288 case VLR_ULA_E_NEW_TMSI_ACK:
1289 osmo_fsm_inst_dispatch(lfp->lu_compl_vlr_fsm,
1290 LU_COMPL_VLR_E_NEW_TMSI_ACK, NULL);
1291 break;
1292 case VLR_ULA_E_LU_COMPL_SUCCESS:
1293 lu_fsm_discard_lu_compl_fsm(fi);
1294 vsub->sub_dataconf_by_hlr_ind = false;
1295 lu_fsm_success(fi);
1296 break;
1297 case VLR_ULA_E_LU_COMPL_FAILURE:
1298 vsub->sub_dataconf_by_hlr_ind = false;
1299 cause = GSM48_REJECT_NETWORK_FAILURE;
1300 if (data)
1301 cause = *(uint8_t*)data;
1302 lu_fsm_discard_lu_compl_fsm(fi);
1303 lu_fsm_failure(fi, cause);
1304 break;
1305 default:
1306 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1307 osmo_fsm_event_name(fi->fsm, event));
1308 break;
1309 }
1310}
1311
1312static const struct osmo_fsm_state vlr_lu_fsm_states[] = {
1313 [VLR_ULA_S_IDLE] = {
1314 .in_event_mask = S(VLR_ULA_E_UPDATE_LA),
1315 .out_state_mask = S(VLR_ULA_S_WAIT_IMEISV) |
1316 S(VLR_ULA_S_WAIT_PVLR) |
1317 S(VLR_ULA_S_WAIT_IMSI) |
1318 S(VLR_ULA_S_WAIT_AUTH) |
1319 S(VLR_ULA_S_WAIT_HLR_UPD) |
1320 S(VLR_ULA_S_DONE),
1321 .name = OSMO_STRINGIFY(VLR_ULA_S_IDLE),
1322 .action = lu_fsm_idle,
1323 },
1324 [VLR_ULA_S_WAIT_IMEISV] = {
1325 .in_event_mask = S(VLR_ULA_E_ID_IMEISV),
1326 .out_state_mask = S(VLR_ULA_S_WAIT_PVLR) |
1327 S(VLR_ULA_S_WAIT_IMSI) |
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001328 S(VLR_ULA_S_WAIT_AUTH) |
1329 S(VLR_ULA_S_WAIT_HLR_UPD) |
Harald Welteb8b85a12016-06-17 00:06:42 +02001330 S(VLR_ULA_S_DONE),
1331 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_IMEISV),
1332 .action = lu_fsm_wait_imeisv,
1333 },
1334 [VLR_ULA_S_WAIT_PVLR] = {
1335 .in_event_mask = S(VLR_ULA_E_SEND_ID_ACK) |
1336 S(VLR_ULA_E_SEND_ID_NACK),
1337 .out_state_mask = S(VLR_ULA_S_WAIT_IMSI) |
1338 S(VLR_ULA_S_WAIT_AUTH) |
1339 S(VLR_ULA_S_DONE),
1340 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_PVLR),
1341 .action = lu_fsm_wait_pvlr,
1342 },
1343 [VLR_ULA_S_WAIT_AUTH] = {
1344 .in_event_mask = S(VLR_ULA_E_AUTH_RES),
1345 .out_state_mask = S(VLR_ULA_S_WAIT_CIPH) |
1346 S(VLR_ULA_S_WAIT_LU_COMPL) |
1347 S(VLR_ULA_S_WAIT_HLR_UPD) |
1348 S(VLR_ULA_S_DONE),
1349 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_AUTH),
1350 .action = lu_fsm_wait_auth,
1351 },
1352 [VLR_ULA_S_WAIT_CIPH] = {
1353 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_CIPH),
1354 .in_event_mask = S(VLR_ULA_E_CIPH_RES),
1355 .out_state_mask = S(VLR_ULA_S_WAIT_LU_COMPL) |
1356 S(VLR_ULA_S_WAIT_HLR_UPD) |
1357 S(VLR_ULA_S_DONE),
1358 .action = lu_fsm_wait_ciph,
1359 },
1360 [VLR_ULA_S_WAIT_IMSI] = {
1361 .in_event_mask = S(VLR_ULA_E_ID_IMSI),
1362 .out_state_mask = S(VLR_ULA_S_WAIT_AUTH) |
1363 S(VLR_ULA_S_WAIT_HLR_UPD) |
1364 S(VLR_ULA_S_DONE),
1365 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_IMSI),
1366 .action = lu_fsm_wait_imsi,
1367 },
1368 [VLR_ULA_S_WAIT_HLR_UPD] = {
1369 .in_event_mask = S(VLR_ULA_E_HLR_LU_RES) |
1370 S(VLR_ULA_E_UPD_HLR_COMPL),
1371 .out_state_mask = S(VLR_ULA_S_WAIT_LU_COMPL) |
1372 S(VLR_ULA_S_WAIT_LU_COMPL_STANDALONE) |
1373 S(VLR_ULA_S_DONE),
1374 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_HLR_UPD),
1375 .action = lu_fsm_wait_hlr_ul_res,
1376 },
1377 [VLR_ULA_S_WAIT_LU_COMPL] = {
1378 .in_event_mask = S(VLR_ULA_E_LU_COMPL_SUCCESS) |
1379 S(VLR_ULA_E_LU_COMPL_FAILURE) |
1380 S(VLR_ULA_E_NEW_TMSI_ACK) |
1381 S(VLR_ULA_E_ID_IMEI) |
Oliver Smith7d053092018-12-14 17:37:38 +01001382 S(VLR_ULA_E_ID_IMEISV) |
1383 S(VLR_ULA_E_HLR_IMEI_ACK) |
1384 S(VLR_ULA_E_HLR_IMEI_NACK),
Harald Welteb8b85a12016-06-17 00:06:42 +02001385 .out_state_mask = S(VLR_ULA_S_DONE),
1386 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_LU_COMPL),
1387 .action = lu_fsm_wait_lu_compl,
1388 },
1389 [VLR_ULA_S_WAIT_LU_COMPL_STANDALONE] = {
1390 .in_event_mask = S(VLR_ULA_E_LU_COMPL_SUCCESS) |
1391 S(VLR_ULA_E_LU_COMPL_FAILURE) |
1392 S(VLR_ULA_E_NEW_TMSI_ACK),
1393 .out_state_mask = S(VLR_ULA_S_DONE),
1394 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_LU_COMPL_STANDALONE),
1395 .action = lu_fsm_wait_lu_compl_standalone,
1396 },
1397 [VLR_ULA_S_DONE] = {
1398 .name = OSMO_STRINGIFY(VLR_ULA_S_DONE),
1399 .onenter = lu_fsm_dispatch_result,
1400 },
1401};
1402
1403static void fsm_lu_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
1404{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001405 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001406 struct vlr_subscr *vsub = lfp->vsub;
1407
1408 LOGPFSM(fi, "fsm_lu_cleanup called with cause %s\n",
1409 osmo_fsm_term_cause_name(cause));
1410 if (vsub && vsub->lu_fsm == fi)
1411 vsub->lu_fsm = NULL;
1412}
1413
1414static struct osmo_fsm vlr_lu_fsm = {
1415 .name = "vlr_lu_fsm",
1416 .states = vlr_lu_fsm_states,
1417 .num_states = ARRAY_SIZE(vlr_lu_fsm_states),
1418 .allstate_event_mask = 0,
1419 .allstate_action = NULL,
1420 .log_subsys = DVLR,
1421 .event_names = fsm_lu_event_names,
1422 .cleanup = fsm_lu_cleanup,
1423};
1424
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001425static inline struct lu_fsm_priv *lu_fsm_fi_priv(struct osmo_fsm_inst *fi)
1426{
1427 OSMO_ASSERT(fi->fsm == &vlr_lu_fsm);
1428 return (struct lu_fsm_priv*)fi->priv;
1429}
1430
Harald Welteb8b85a12016-06-17 00:06:42 +02001431struct osmo_fsm_inst *
1432vlr_loc_update(struct osmo_fsm_inst *parent,
1433 uint32_t parent_event_success,
1434 uint32_t parent_event_failure,
1435 void *parent_event_data,
1436 struct vlr_instance *vlr, void *msc_conn_ref,
1437 enum vlr_lu_type type, uint32_t tmsi, const char *imsi,
1438 const struct osmo_location_area_id *old_lai,
1439 const struct osmo_location_area_id *new_lai,
1440 bool authentication_required,
Harald Welte71c51df2017-12-23 18:51:48 +01001441 bool ciphering_required,
Harald Welteb8b85a12016-06-17 00:06:42 +02001442 bool is_r99, bool is_utran,
1443 bool assign_tmsi)
1444{
1445 struct osmo_fsm_inst *fi;
1446 struct lu_fsm_priv *lfp;
1447
1448 fi = osmo_fsm_inst_alloc_child(&vlr_lu_fsm, parent, parent_event_failure);
1449 if (!fi)
1450 return NULL;
1451
1452 lfp = talloc_zero(fi, struct lu_fsm_priv);
1453 lfp->vlr = vlr;
1454 lfp->msc_conn_ref = msc_conn_ref;
1455 lfp->tmsi = tmsi;
1456 lfp->type = type;
1457 lfp->old_lai = *old_lai;
1458 lfp->new_lai = *new_lai;
1459 lfp->lu_by_tmsi = true;
1460 lfp->parent_event_success = parent_event_success;
1461 lfp->parent_event_failure = parent_event_failure;
1462 lfp->parent_event_data = parent_event_data;
1463 lfp->authentication_required = authentication_required;
1464 lfp->ciphering_required = ciphering_required;
1465 lfp->is_r99 = is_r99;
1466 lfp->is_utran = is_utran;
1467 lfp->assign_tmsi = assign_tmsi;
1468 if (imsi) {
1469 strncpy(lfp->imsi, imsi, sizeof(lfp->imsi)-1);
1470 lfp->imsi[sizeof(lfp->imsi)-1] = '\0';
1471 lfp->lu_by_tmsi = false;
1472 }
1473 fi->priv = lfp;
1474
1475 LOGPFSM(fi, "rev=%s net=%s%s%s\n",
1476 is_r99 ? "R99" : "GSM",
1477 is_utran ? "UTRAN" : "GERAN",
1478 (authentication_required || ciphering_required)?
1479 " Auth" : " (no Auth)",
1480 (authentication_required || ciphering_required)?
1481 (ciphering_required? "+Ciph" : " (no Ciph)")
1482 : "");
1483
Neels Hofmeyr84da6b12016-05-20 21:59:55 +02001484 if (is_utran && !authentication_required)
1485 LOGPFSML(fi, LOGL_ERROR,
1486 "Authentication off on UTRAN network. Good luck.\n");
1487
Harald Welteb8b85a12016-06-17 00:06:42 +02001488 osmo_fsm_inst_dispatch(fi, VLR_ULA_E_UPDATE_LA, NULL);
1489
1490 return fi;
1491}
1492
Neels Hofmeyr15809592018-04-06 02:57:51 +02001493void vlr_loc_update_cancel(struct osmo_fsm_inst *fi,
1494 enum osmo_fsm_term_cause fsm_cause,
1495 uint8_t gsm48_cause)
Harald Welteb8b85a12016-06-17 00:06:42 +02001496{
Neels Hofmeyr15809592018-04-06 02:57:51 +02001497 struct lu_fsm_priv *lfp;
1498
1499 OSMO_ASSERT(fi);
1500 OSMO_ASSERT(fi->fsm == &vlr_lu_fsm);
1501
1502 lfp = fi->priv;
1503 lfp->rej_cause = gsm48_cause;
1504
1505 if (fi->state != VLR_ULA_S_DONE)
1506 lu_fsm_failure(fi, gsm48_cause);
Harald Welteb8b85a12016-06-17 00:06:42 +02001507}
1508
1509void vlr_lu_fsm_init(void)
1510{
1511 osmo_fsm_register(&vlr_lu_fsm);
1512 osmo_fsm_register(&upd_hlr_vlr_fsm);
1513 osmo_fsm_register(&sub_pres_vlr_fsm);
1514 osmo_fsm_register(&lu_compl_vlr_fsm);
1515}