blob: 0ac5b9ad1fba792029564d2dd57cbfeff676d51a [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"
30
31#define S(x) (1 << (x))
32
33#define LU_TIMEOUT_LONG 30
34
35enum vlr_fsm_result {
36 VLR_FSM_RESULT_NONE,
37 VLR_FSM_RESULT_SUCCESS,
38 VLR_FSM_RESULT_FAILURE,
39};
40
41
42/***********************************************************************
43 * Update_HLR_VLR, TS 23.012 Chapter 4.1.2.4
44 ***********************************************************************/
45
46enum upd_hlr_vlr_state {
47 UPD_HLR_VLR_S_INIT,
48 UPD_HLR_VLR_S_WAIT_FOR_DATA,
49 UPD_HLR_VLR_S_DONE,
50};
51
52enum upd_hlr_vlr_evt {
53 UPD_HLR_VLR_E_START,
54 UPD_HLR_VLR_E_INS_SUB_DATA,
55 UPD_HLR_VLR_E_ACT_TRACE_MODE,
56 UPD_HLR_VLR_E_FW_CHECK_SS_IND,
57 UPD_HLR_VLR_E_UPD_LOC_ACK,
58 UPD_HLR_VLR_E_UPD_LOC_NACK,
59};
60
61static const struct value_string upd_hlr_vlr_event_names[] = {
62 OSMO_VALUE_STRING(UPD_HLR_VLR_E_START),
63 OSMO_VALUE_STRING(UPD_HLR_VLR_E_INS_SUB_DATA),
64 OSMO_VALUE_STRING(UPD_HLR_VLR_E_ACT_TRACE_MODE),
65 OSMO_VALUE_STRING(UPD_HLR_VLR_E_FW_CHECK_SS_IND),
66 OSMO_VALUE_STRING(UPD_HLR_VLR_E_UPD_LOC_ACK),
67 OSMO_VALUE_STRING(UPD_HLR_VLR_E_UPD_LOC_NACK),
68 { 0, NULL }
69};
70
71static void upd_hlr_vlr_fsm_init(struct osmo_fsm_inst *fi, uint32_t event,
72 void *data)
73{
74 struct vlr_subscr *vsub = fi->priv;
Max770fbd22018-01-24 12:48:33 +010075 int rc;
Harald Welteb8b85a12016-06-17 00:06:42 +020076
77 OSMO_ASSERT(event == UPD_HLR_VLR_E_START);
78
79 /* Send UpdateLocation to HLR */
Max770fbd22018-01-24 12:48:33 +010080 rc = vlr_subscr_req_lu(vsub, vsub->vlr->cfg.is_ps);
81 if (rc < 0)
82 LOGPFSML(fi, LOGL_ERROR, "Failed to send UpdateLocation to HLR\n");
Harald Welteb8b85a12016-06-17 00:06:42 +020083 osmo_fsm_inst_state_chg(fi, UPD_HLR_VLR_S_WAIT_FOR_DATA,
84 LU_TIMEOUT_LONG, 0);
85}
86
87static void upd_hlr_vlr_fsm_wait_data(struct osmo_fsm_inst *fi, uint32_t event,
88 void *data)
89{
90 struct vlr_subscr *vsub = fi->priv;
91
92 switch (event) {
93 case UPD_HLR_VLR_E_INS_SUB_DATA:
94 /* FIXME: Insert_Subscr_Data_VLR */
95 break;
96 case UPD_HLR_VLR_E_ACT_TRACE_MODE:
97 /* TODO: Activate_Tracing_VLR */
98 break;
99 case UPD_HLR_VLR_E_FW_CHECK_SS_IND:
100 /* TODO: Forward Check SS Ind to MSC */
101 break;
102 case UPD_HLR_VLR_E_UPD_LOC_ACK:
103 /* Inside Update_HLR_VLR after UpdateLocationAck */
104 vsub->sub_dataconf_by_hlr_ind = true;
105 vsub->loc_conf_in_hlr_ind = true;
106 osmo_fsm_inst_state_chg(fi, UPD_HLR_VLR_S_DONE, 0, 0);
107 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
108 break;
109 case UPD_HLR_VLR_E_UPD_LOC_NACK:
110 /* Inside Update_HLR_VLR after UpdateLocationNack */
111 /* TODO: Check_User_Error_In_Serving_Network_Entity */
112 vsub->sub_dataconf_by_hlr_ind = false;
113 vsub->loc_conf_in_hlr_ind = false;
114 osmo_fsm_inst_state_chg(fi, UPD_HLR_VLR_S_DONE, 0, 0);
115 /* Data is a pointer to a gsm48_gmm_cause which we
116 * simply pass through */
117 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, data);
118 break;
119 }
120}
121
122static const struct osmo_fsm_state upd_hlr_vlr_states[] = {
123 [UPD_HLR_VLR_S_INIT] = {
124 .in_event_mask = S(UPD_HLR_VLR_E_START),
125 .out_state_mask = S(UPD_HLR_VLR_S_WAIT_FOR_DATA),
126 .name = OSMO_STRINGIFY(UPD_HLR_VLR_S_INIT),
127 .action = upd_hlr_vlr_fsm_init,
128 },
129 [UPD_HLR_VLR_S_WAIT_FOR_DATA] = {
130 .in_event_mask = S(UPD_HLR_VLR_E_INS_SUB_DATA) |
131 S(UPD_HLR_VLR_E_ACT_TRACE_MODE) |
132 S(UPD_HLR_VLR_E_FW_CHECK_SS_IND) |
133 S(UPD_HLR_VLR_E_UPD_LOC_ACK) |
134 S(UPD_HLR_VLR_E_UPD_LOC_NACK),
135 .out_state_mask = S(UPD_HLR_VLR_S_DONE),
136 .name = OSMO_STRINGIFY(UPD_HLR_VLR_S_WAIT_FOR_DATA),
137 .action = upd_hlr_vlr_fsm_wait_data,
138 },
139 [UPD_HLR_VLR_S_DONE] = {
140 .name = OSMO_STRINGIFY(UPD_HLR_VLR_S_DONE),
141 },
142};
143
144static struct osmo_fsm upd_hlr_vlr_fsm = {
145 .name = "upd_hlr_vlr_fsm",
146 .states = upd_hlr_vlr_states,
147 .num_states = ARRAY_SIZE(upd_hlr_vlr_states),
148 .allstate_event_mask = 0,
149 .allstate_action = NULL,
150 .log_subsys = DVLR,
151 .event_names = upd_hlr_vlr_event_names,
152};
153
154struct osmo_fsm_inst *
155upd_hlr_vlr_proc_start(struct osmo_fsm_inst *parent,
156 struct vlr_subscr *vsub,
157 uint32_t parent_event)
158{
159 struct osmo_fsm_inst *fi;
160
161 fi = osmo_fsm_inst_alloc_child(&upd_hlr_vlr_fsm, parent,
162 parent_event);
163 if (!fi)
164 return NULL;
165
166 fi->priv = vsub;
167 osmo_fsm_inst_dispatch(fi, UPD_HLR_VLR_E_START, NULL);
168
169 return fi;
170}
171
172
173/***********************************************************************
174 * Subscriber_Present_VLR, TS 29.002 Chapter 25.10.1
175 ***********************************************************************/
176
177enum sub_pres_vlr_state {
178 SUB_PRES_VLR_S_INIT,
179 SUB_PRES_VLR_S_WAIT_FOR_HLR,
180 SUB_PRES_VLR_S_DONE,
181};
182
183enum sub_pres_vlr_event {
184 SUB_PRES_VLR_E_START,
185 SUB_PRES_VLR_E_READY_SM_CNF,
186 SUB_PRES_VLR_E_READY_SM_ERR,
187};
188
189static const struct value_string sub_pres_vlr_event_names[] = {
190 OSMO_VALUE_STRING(SUB_PRES_VLR_E_START),
191 OSMO_VALUE_STRING(SUB_PRES_VLR_E_READY_SM_CNF),
192 OSMO_VALUE_STRING(SUB_PRES_VLR_E_READY_SM_ERR),
193 { 0, NULL }
194};
195
196static void sub_pres_vlr_fsm_init(struct osmo_fsm_inst *fi, uint32_t event,
197 void *data)
198{
199 struct vlr_subscr *vsub = fi->priv;
200 OSMO_ASSERT(event == SUB_PRES_VLR_E_START);
201
202 if (!vsub->ms_not_reachable_flag) {
203 osmo_fsm_inst_state_chg(fi, SUB_PRES_VLR_S_DONE, 0, 0);
204 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
205 return;
206 }
207 /* FIXME: Send READY_FOR_SM via GSUP */
208 osmo_fsm_inst_state_chg(fi, SUB_PRES_VLR_S_WAIT_FOR_HLR,
209 LU_TIMEOUT_LONG, 0);
210}
211
212static void sub_pres_vlr_fsm_wait_hlr(struct osmo_fsm_inst *fi, uint32_t event,
213 void *data)
214{
215 struct vlr_subscr *vsub = fi->priv;
216
217 switch (event) {
218 case SUB_PRES_VLR_E_READY_SM_CNF:
219 vsub->ms_not_reachable_flag = false;
220 break;
221 case SUB_PRES_VLR_E_READY_SM_ERR:
222 break;
223 }
224 osmo_fsm_inst_state_chg(fi, SUB_PRES_VLR_S_DONE, 0, 0);
225 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
226}
227
228static const struct osmo_fsm_state sub_pres_vlr_states[] = {
229 [SUB_PRES_VLR_S_INIT] = {
230 .in_event_mask = S(SUB_PRES_VLR_E_START),
231 .out_state_mask = S(SUB_PRES_VLR_S_WAIT_FOR_HLR) |
232 S(SUB_PRES_VLR_S_DONE),
233 .name = OSMO_STRINGIFY(SUB_PRES_VLR_S_INIT),
234 .action = sub_pres_vlr_fsm_init,
235 },
236 [SUB_PRES_VLR_S_WAIT_FOR_HLR] = {
237 .in_event_mask = S(SUB_PRES_VLR_E_READY_SM_CNF) |
238 S(SUB_PRES_VLR_E_READY_SM_ERR),
239 .out_state_mask = S(SUB_PRES_VLR_S_DONE),
240 .name = OSMO_STRINGIFY(SUB_PRES_VLR_S_WAIT_FOR_HLR),
241 .action = sub_pres_vlr_fsm_wait_hlr,
242 },
243 [SUB_PRES_VLR_S_DONE] = {
244 .name = OSMO_STRINGIFY(SUB_PRES_VLR_S_DONE),
245 },
246};
247
248static struct osmo_fsm sub_pres_vlr_fsm = {
249 .name = "sub_pres_vlr_fsm",
250 .states = sub_pres_vlr_states,
251 .num_states = ARRAY_SIZE(sub_pres_vlr_states),
252 .allstate_event_mask = 0,
253 .allstate_action = NULL,
254 .log_subsys = DVLR,
255 .event_names = sub_pres_vlr_event_names,
256};
257
Neels Hofmeyr1a5bcd52017-11-18 22:19:55 +0100258/* Note that the start event is dispatched right away, so in case the FSM immediately concludes from that
259 * event, the created FSM struct may no longer be valid as it already deallocated again, and it may
260 * furthermore already have invoked the parent FSM instance's deallocation as well. Hence, instead of
261 * returning, store the created FSM instance address in *fi_p before dispatching the event. It is thus
262 * possible to store the instance's pointer in a parent FSM instance without running danger of using
263 * already freed memory. */
264void sub_pres_vlr_fsm_start(struct osmo_fsm_inst **fi_p,
265 struct osmo_fsm_inst *parent,
266 struct vlr_subscr *vsub,
267 uint32_t term_event)
Harald Welteb8b85a12016-06-17 00:06:42 +0200268{
269 struct osmo_fsm_inst *fi;
270
Neels Hofmeyr1a5bcd52017-11-18 22:19:55 +0100271 OSMO_ASSERT(fi_p);
272
Harald Welteb8b85a12016-06-17 00:06:42 +0200273 fi = osmo_fsm_inst_alloc_child(&sub_pres_vlr_fsm, parent,
274 term_event);
Neels Hofmeyr1a5bcd52017-11-18 22:19:55 +0100275 *fi_p = fi;
Harald Welteb8b85a12016-06-17 00:06:42 +0200276 if (!fi)
Neels Hofmeyr1a5bcd52017-11-18 22:19:55 +0100277 return;
Harald Welteb8b85a12016-06-17 00:06:42 +0200278
279 fi->priv = vsub;
280 osmo_fsm_inst_dispatch(fi, SUB_PRES_VLR_E_START, NULL);
Harald Welteb8b85a12016-06-17 00:06:42 +0200281}
282
283/***********************************************************************
284 * Location_Update_Completion_VLR, TS 23.012 Chapter 4.1.2.3
285 ***********************************************************************/
286
287enum lu_compl_vlr_state {
288 LU_COMPL_VLR_S_INIT,
289 LU_COMPL_VLR_S_WAIT_SUB_PRES,
290 LU_COMPL_VLR_S_WAIT_IMEI,
291 LU_COMPL_VLR_S_WAIT_IMEI_TMSI,
292 LU_COMPL_VLR_S_WAIT_TMSI_CNF,
293 LU_COMPL_VLR_S_DONE,
294};
295
296enum lu_compl_vlr_event {
297 LU_COMPL_VLR_E_START,
298 LU_COMPL_VLR_E_SUB_PRES_COMPL,
299 LU_COMPL_VLR_E_IMEI_CHECK_ACK,
300 LU_COMPL_VLR_E_IMEI_CHECK_NACK,
301 LU_COMPL_VLR_E_NEW_TMSI_ACK,
302};
303
304static const struct value_string lu_compl_vlr_event_names[] = {
305 OSMO_VALUE_STRING(LU_COMPL_VLR_E_START),
306 OSMO_VALUE_STRING(LU_COMPL_VLR_E_SUB_PRES_COMPL),
307 OSMO_VALUE_STRING(LU_COMPL_VLR_E_IMEI_CHECK_ACK),
308 OSMO_VALUE_STRING(LU_COMPL_VLR_E_IMEI_CHECK_NACK),
309 OSMO_VALUE_STRING(LU_COMPL_VLR_E_NEW_TMSI_ACK),
310 { 0, NULL }
311};
312
313struct lu_compl_vlr_priv {
314 struct vlr_subscr *vsub;
315 void *msc_conn_ref;
316 struct osmo_fsm_inst *sub_pres_vlr_fsm;
317 uint32_t parent_event_success;
318 uint32_t parent_event_failure;
319 void *parent_event_data;
320 enum vlr_fsm_result result;
321 uint8_t cause;
322 bool assign_tmsi;
323};
324
325static void _vlr_lu_compl_fsm_done(struct osmo_fsm_inst *fi,
326 enum vlr_fsm_result result,
327 uint8_t cause)
328{
329 struct lu_compl_vlr_priv *lcvp = fi->priv;
330 lcvp->result = result;
331 lcvp->cause = cause;
332 osmo_fsm_inst_state_chg(fi, LU_COMPL_VLR_S_DONE, 0, 0);
333}
334
335static void vlr_lu_compl_fsm_success(struct osmo_fsm_inst *fi)
336{
337 struct lu_compl_vlr_priv *lcvp = fi->priv;
338 struct vlr_subscr *vsub = lcvp->vsub;
339 if (!vsub->lu_complete) {
340 vsub->lu_complete = true;
341 /* Balanced by vlr_subscr_rx_imsi_detach() */
342 vlr_subscr_get(vsub);
343 }
344 _vlr_lu_compl_fsm_done(fi, VLR_FSM_RESULT_SUCCESS, 0);
345}
346
347static void vlr_lu_compl_fsm_failure(struct osmo_fsm_inst *fi, uint8_t cause)
348{
349 struct lu_compl_vlr_priv *lcvp = fi->priv;
350 lcvp->vsub->vlr->ops.tx_lu_rej(lcvp->msc_conn_ref, cause);
351 _vlr_lu_compl_fsm_done(fi, VLR_FSM_RESULT_FAILURE, cause);
352}
353
354static void vlr_lu_compl_fsm_dispatch_result(struct osmo_fsm_inst *fi,
355 uint32_t prev_state)
356{
357 struct lu_compl_vlr_priv *lcvp = fi->priv;
358 if (!fi->proc.parent) {
359 LOGPFSML(fi, LOGL_ERROR, "No parent FSM\n");
360 return;
361 }
362 osmo_fsm_inst_dispatch(fi->proc.parent,
363 (lcvp->result == VLR_FSM_RESULT_SUCCESS)
364 ? lcvp->parent_event_success
365 : lcvp->parent_event_failure,
366 &lcvp->cause);
367}
368
369static void lu_compl_vlr_init(struct osmo_fsm_inst *fi, uint32_t event,
370 void *data)
371{
372 struct lu_compl_vlr_priv *lcvp = fi->priv;
373 struct vlr_subscr *vsub = lcvp->vsub;
374 struct vlr_instance *vlr;
375 OSMO_ASSERT(vsub);
376 vlr = vsub->vlr;
377 OSMO_ASSERT(vlr);
378
379 OSMO_ASSERT(event == LU_COMPL_VLR_E_START);
380
381 /* TODO: National Roaming restrictions? */
382 /* TODO: Roaming restriction due to unsupported feature in subscriber
383 * data? */
384 /* TODO: Regional subscription restriction? */
385 /* TODO: Administrative restriction of subscribres' access feature? */
386 /* TODO: AccessRestrictuionData parameter available? */
387 /* TODO: AccessRestrictionData permits RAT? */
388 /* Node 1 */
389 /* TODO: Autonomous CSG supported in VPLMN and allowed by HPLMN? */
390 /* TODO: Hybrid Cel / CSG Cell */
391 /* Node 2 */
392 vsub->la_allowed = true;
393 vsub->imsi_detached_flag = false;
394 /* Start Subscriber_Present_VLR Procedure */
395 osmo_fsm_inst_state_chg(fi, LU_COMPL_VLR_S_WAIT_SUB_PRES,
396 LU_TIMEOUT_LONG, 0);
397
Neels Hofmeyr1a5bcd52017-11-18 22:19:55 +0100398 sub_pres_vlr_fsm_start(&lcvp->sub_pres_vlr_fsm, fi, vsub, LU_COMPL_VLR_E_SUB_PRES_COMPL);
Harald Welteb8b85a12016-06-17 00:06:42 +0200399}
400
401static void lu_compl_vlr_new_tmsi(struct osmo_fsm_inst *fi)
402{
403 struct lu_compl_vlr_priv *lcvp = fi->priv;
404 struct vlr_subscr *vsub = lcvp->vsub;
405 struct vlr_instance *vlr = vsub->vlr;
406
407 LOGPFSM(fi, "%s()\n", __func__);
408
409 if (vlr_subscr_alloc_tmsi(vsub)) {
410 vlr_lu_compl_fsm_failure(fi,
411 GSM48_REJECT_SRV_OPT_TMP_OUT_OF_ORDER);
412 return;
413 }
414
415 osmo_fsm_inst_state_chg(fi, LU_COMPL_VLR_S_WAIT_TMSI_CNF,
416 vlr_timer(vlr, 3250), 3250);
417
418 vlr->ops.tx_lu_acc(lcvp->msc_conn_ref, vsub->tmsi_new);
419}
420
421/* After completion of Subscriber_Present_VLR */
422static void lu_compl_vlr_wait_subscr_pres(struct osmo_fsm_inst *fi,
423 uint32_t event,
424 void *data)
425{
426 struct lu_compl_vlr_priv *lcvp = fi->priv;
427 struct vlr_subscr *vsub = lcvp->vsub;
428 struct vlr_instance *vlr = vsub->vlr;
429
430 OSMO_ASSERT(event == LU_COMPL_VLR_E_SUB_PRES_COMPL);
431
432 lcvp->sub_pres_vlr_fsm = NULL;
433
434 /* TODO: Trace_Subscriber_Activity_VLR */
435
436 if (vlr->cfg.check_imei_rqd) {
437 /* Check IMEI VLR */
438 osmo_fsm_inst_state_chg(fi,
439 lcvp->assign_tmsi ?
440 LU_COMPL_VLR_S_WAIT_IMEI_TMSI
441 : LU_COMPL_VLR_S_WAIT_IMEI,
442 vlr_timer(vlr, 3270), 3270);
443 vlr->ops.tx_id_req(lcvp->msc_conn_ref, GSM_MI_TYPE_IMEI);
444 return;
445 }
446
447 /* Do we need to allocate a TMSI? */
448 if (lcvp->assign_tmsi) {
449 lu_compl_vlr_new_tmsi(fi);
450 return;
451 }
452
453 /* Location Updating Accept */
454 vlr->ops.tx_lu_acc(lcvp->msc_conn_ref, GSM_RESERVED_TMSI);
455 vlr_lu_compl_fsm_success(fi);
456}
457
458/* Waiting for completion of CHECK_IMEI_VLR */
459static void lu_compl_vlr_wait_imei(struct osmo_fsm_inst *fi, uint32_t event,
460 void *data)
461{
462 struct lu_compl_vlr_priv *lcvp = fi->priv;
463 struct vlr_subscr *vsub = lcvp->vsub;
464 struct vlr_instance *vlr = vsub->vlr;
465
466 switch (event) {
467 case LU_COMPL_VLR_E_IMEI_CHECK_ACK:
468 if (!vsub->imei[0]) {
469 /* Abort: Do nothing */
470 vlr_lu_compl_fsm_failure(fi,
471 GSM48_REJECT_PROTOCOL_ERROR);
472 return;
473 }
474 /* Pass */
475 break;
476
477 case LU_COMPL_VLR_E_IMEI_CHECK_NACK:
478 vlr_lu_compl_fsm_failure(fi, GSM48_REJECT_ILLEGAL_ME);
479 /* FIXME: IMEI Check Fail to VLR Application (Detach IMSI VLR) */
480 return;
481 }
482
483 /* IMEI is available. Allocate TMSI if needed. */
484 if (lcvp->assign_tmsi) {
485 if (fi->state != LU_COMPL_VLR_S_WAIT_IMEI_TMSI)
486 LOGPFSML(fi, LOGL_ERROR,
487 "TMSI required, expected to be in state"
488 " LU_COMPL_VLR_S_WAIT_IMEI_TMSI,"
489 " am in %s instead\n",
490 osmo_fsm_state_name(fi->fsm, fi->state));
491 /* Logged an error, continue anyway. */
492
493 lu_compl_vlr_new_tmsi(fi);
494
495 /* Wait for TMSI ack */
496 return;
497 }
498
499 /* No TMSI needed, accept now. */
500 vlr->ops.tx_lu_acc(lcvp->msc_conn_ref, GSM_RESERVED_TMSI);
501 vlr_lu_compl_fsm_success(fi);
502}
503
504/* Waiting for TMSI confirmation */
505static void lu_compl_vlr_wait_tmsi(struct osmo_fsm_inst *fi, uint32_t event,
506 void *data)
507{
508 struct lu_compl_vlr_priv *lcvp = fi->priv;
509 struct vlr_subscr *vsub = lcvp->vsub;
510
511 OSMO_ASSERT(event == LU_COMPL_VLR_E_NEW_TMSI_ACK);
512
513 if (!vsub || vsub->tmsi_new == GSM_RESERVED_TMSI) {
514 LOGPFSML(fi, LOGL_ERROR, "TMSI Realloc Compl implies that"
515 " the subscriber has a new TMSI allocated, but"
516 " the new TMSI is unset.\n");
517 vlr_lu_compl_fsm_failure(fi, GSM48_REJECT_NETWORK_FAILURE);
518 return;
519 }
520
521 vsub->tmsi = vsub->tmsi_new;
522 vsub->tmsi_new = GSM_RESERVED_TMSI;
523
524 vlr_lu_compl_fsm_success(fi);
525}
526
527static const struct osmo_fsm_state lu_compl_vlr_states[] = {
528 [LU_COMPL_VLR_S_INIT] = {
529 .in_event_mask = S(LU_COMPL_VLR_E_START),
530 .out_state_mask = S(LU_COMPL_VLR_S_DONE) |
531 S(LU_COMPL_VLR_S_WAIT_SUB_PRES) |
532 S(LU_COMPL_VLR_S_WAIT_IMEI),
533 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_INIT),
534 .action = lu_compl_vlr_init,
535 },
536 [LU_COMPL_VLR_S_WAIT_SUB_PRES] = {
537 .in_event_mask = S(LU_COMPL_VLR_E_SUB_PRES_COMPL),
538 .out_state_mask = S(LU_COMPL_VLR_S_WAIT_IMEI) |
539 S(LU_COMPL_VLR_S_WAIT_IMEI_TMSI) |
540 S(LU_COMPL_VLR_S_WAIT_TMSI_CNF) |
541 S(LU_COMPL_VLR_S_DONE),
542 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_SUB_PRES),
543 .action = lu_compl_vlr_wait_subscr_pres,
544 },
545 [LU_COMPL_VLR_S_WAIT_IMEI] = {
546 .in_event_mask = S(LU_COMPL_VLR_E_IMEI_CHECK_ACK) |
547 S(LU_COMPL_VLR_E_IMEI_CHECK_NACK),
548 .out_state_mask = S(LU_COMPL_VLR_S_DONE),
549 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_IMEI),
550 .action = lu_compl_vlr_wait_imei,
551 },
552 [LU_COMPL_VLR_S_WAIT_IMEI_TMSI] = {
553 .in_event_mask = S(LU_COMPL_VLR_E_IMEI_CHECK_ACK) |
554 S(LU_COMPL_VLR_E_IMEI_CHECK_NACK),
555 .out_state_mask = S(LU_COMPL_VLR_S_DONE) |
556 S(LU_COMPL_VLR_S_WAIT_TMSI_CNF),
557 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_IMEI_TMSI),
558 .action = lu_compl_vlr_wait_imei,
559 },
560 [LU_COMPL_VLR_S_WAIT_TMSI_CNF] = {
561 .in_event_mask = S(LU_COMPL_VLR_E_NEW_TMSI_ACK),
562 .out_state_mask = S(LU_COMPL_VLR_S_DONE),
563 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_TMSI_CNF),
564 .action = lu_compl_vlr_wait_tmsi,
565 },
566 [LU_COMPL_VLR_S_DONE] = {
567 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_DONE),
568 .onenter = vlr_lu_compl_fsm_dispatch_result,
569 },
570};
571
572static struct osmo_fsm lu_compl_vlr_fsm = {
573 .name = "lu_compl_vlr_fsm",
574 .states = lu_compl_vlr_states,
575 .num_states = ARRAY_SIZE(lu_compl_vlr_states),
576 .allstate_event_mask = 0,
577 .allstate_action = NULL,
578 .log_subsys = DVLR,
579 .event_names = lu_compl_vlr_event_names,
580};
581
582struct osmo_fsm_inst *
583lu_compl_vlr_proc_alloc(struct osmo_fsm_inst *parent,
584 struct vlr_subscr *vsub,
585 void *msc_conn_ref,
586 uint32_t parent_event_success,
587 uint32_t parent_event_failure,
588 bool assign_tmsi)
589{
590 struct osmo_fsm_inst *fi;
591 struct lu_compl_vlr_priv *lcvp;
592
593 fi = osmo_fsm_inst_alloc_child(&lu_compl_vlr_fsm, parent,
594 parent_event_failure);
595 if (!fi)
596 return NULL;
597
598 lcvp = talloc_zero(fi, struct lu_compl_vlr_priv);
599 lcvp->vsub = vsub;
600 lcvp->msc_conn_ref = msc_conn_ref;
601 lcvp->parent_event_success = parent_event_success;
602 lcvp->parent_event_failure = parent_event_failure;
603 lcvp->assign_tmsi = assign_tmsi;
604 fi->priv = lcvp;
605
606 return fi;
607}
608
609
610/***********************************************************************
611 * Update_Location_Area_VLR, TS 23.012 Chapter 4.1.2.1
612 ***********************************************************************/
613
614static const struct value_string fsm_lu_event_names[] = {
615 OSMO_VALUE_STRING(VLR_ULA_E_UPDATE_LA),
616 OSMO_VALUE_STRING(VLR_ULA_E_SEND_ID_ACK),
617 OSMO_VALUE_STRING(VLR_ULA_E_SEND_ID_NACK),
618 OSMO_VALUE_STRING(VLR_ULA_E_AUTH_RES),
619 OSMO_VALUE_STRING(VLR_ULA_E_CIPH_RES),
620 OSMO_VALUE_STRING(VLR_ULA_E_ID_IMSI),
621 OSMO_VALUE_STRING(VLR_ULA_E_ID_IMEI),
622 OSMO_VALUE_STRING(VLR_ULA_E_ID_IMEISV),
623 OSMO_VALUE_STRING(VLR_ULA_E_HLR_LU_RES),
624 OSMO_VALUE_STRING(VLR_ULA_E_UPD_HLR_COMPL),
625 OSMO_VALUE_STRING(VLR_ULA_E_LU_COMPL_SUCCESS),
626 OSMO_VALUE_STRING(VLR_ULA_E_LU_COMPL_FAILURE),
627 OSMO_VALUE_STRING(VLR_ULA_E_NEW_TMSI_ACK),
628 { 0, NULL }
629};
630
631struct lu_fsm_priv {
632 struct vlr_instance *vlr;
633 struct vlr_subscr *vsub;
634 void *msc_conn_ref;
635 struct osmo_fsm_inst *upd_hlr_vlr_fsm;
636 struct osmo_fsm_inst *lu_compl_vlr_fsm;
637 uint32_t parent_event_success;
638 uint32_t parent_event_failure;
639 void *parent_event_data;
640 enum vlr_fsm_result result;
641 uint8_t rej_cause;
642
643 enum vlr_lu_type type;
644 bool lu_by_tmsi;
645 char imsi[16];
646 uint32_t tmsi;
647 struct osmo_location_area_id old_lai;
648 struct osmo_location_area_id new_lai;
649 bool authentication_required;
Harald Welte71c51df2017-12-23 18:51:48 +0100650 bool ciphering_required;
Harald Welteb8b85a12016-06-17 00:06:42 +0200651 bool is_r99;
652 bool is_utran;
653 bool assign_tmsi;
654};
655
656
657/* Determine if given location area is served by this VLR */
658static bool lai_in_this_vlr(struct vlr_instance *vlr,
659 const struct osmo_location_area_id *lai)
660{
661 /* TODO: VLR needs to keep a locally configued list of LAIs */
662 return true;
663}
664
665/* Determine if authentication is required */
666static bool is_auth_required(struct lu_fsm_priv *lfp)
667{
668 /* The cases where the authentication procedure should be used
669 * are defined in 3GPP TS 33.102 */
670 /* For now we use a default value passed in to vlr_lu_fsm(). */
Harald Welte71c51df2017-12-23 18:51:48 +0100671 return lfp->authentication_required || lfp->ciphering_required;
Harald Welteb8b85a12016-06-17 00:06:42 +0200672}
673
674/* Determine if ciphering is required */
675static bool is_ciph_required(struct lu_fsm_priv *lfp)
676{
Harald Welte71c51df2017-12-23 18:51:48 +0100677 return lfp->ciphering_required;
Harald Welteb8b85a12016-06-17 00:06:42 +0200678}
679
680/* Determine if a HLR Update is required */
681static bool hlr_update_needed(struct vlr_subscr *vsub)
682{
683 /* TODO: properly decide this, rather than always assuming we
684 * need to update the HLR. */
685 return true;
686}
687
688static void lu_fsm_dispatch_result(struct osmo_fsm_inst *fi,
689 uint32_t prev_state)
690{
691 struct lu_fsm_priv *lfp = fi->priv;
692 if (!fi->proc.parent) {
693 LOGPFSML(fi, LOGL_ERROR, "No parent FSM\n");
694 return;
695 }
696 osmo_fsm_inst_dispatch(fi->proc.parent,
697 (lfp->result == VLR_FSM_RESULT_SUCCESS)
698 ? lfp->parent_event_success
699 : lfp->parent_event_failure,
700 lfp->parent_event_data);
701}
702
703static void _lu_fsm_done(struct osmo_fsm_inst *fi,
704 enum vlr_fsm_result result)
705{
706 struct lu_fsm_priv *lfp = fi->priv;
707 lfp->result = result;
708 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_DONE, 0, 0);
709}
710
711static void lu_fsm_success(struct osmo_fsm_inst *fi)
712{
713 _lu_fsm_done(fi, VLR_FSM_RESULT_SUCCESS);
714}
715
716static void lu_fsm_failure(struct osmo_fsm_inst *fi, uint8_t rej_cause)
717{
718 struct lu_fsm_priv *lfp = fi->priv;
719 if (rej_cause)
720 lfp->vlr->ops.tx_lu_rej(lfp->msc_conn_ref, rej_cause);
721 _lu_fsm_done(fi, VLR_FSM_RESULT_FAILURE);
722}
723
724static void vlr_loc_upd_start_lu_compl_fsm(struct osmo_fsm_inst *fi)
725{
726 struct lu_fsm_priv *lfp = fi->priv;
727 lfp->lu_compl_vlr_fsm =
728 lu_compl_vlr_proc_alloc(fi, lfp->vsub, lfp->msc_conn_ref,
729 VLR_ULA_E_LU_COMPL_SUCCESS,
730 VLR_ULA_E_LU_COMPL_FAILURE,
731 lfp->assign_tmsi);
732
733 osmo_fsm_inst_dispatch(lfp->lu_compl_vlr_fsm, LU_COMPL_VLR_E_START, NULL);
734}
735
736static void lu_fsm_discard_lu_compl_fsm(struct osmo_fsm_inst *fi)
737{
738 struct lu_fsm_priv *lfp = fi->priv;
739 if (!lfp->lu_compl_vlr_fsm)
740 return;
741 osmo_fsm_inst_term(lfp->lu_compl_vlr_fsm, OSMO_FSM_TERM_PARENT, NULL);
742}
743
744/* 4.1.2.1 Node 4 */
745static void vlr_loc_upd_node_4(struct osmo_fsm_inst *fi)
746{
747 struct lu_fsm_priv *lfp = fi->priv;
748 struct vlr_subscr *vsub = lfp->vsub;
749 bool hlr_unknown = false;
750
751 LOGPFSM(fi, "%s()\n", __func__);
752
753 if (hlr_unknown) {
754 /* FIXME: Delete subscriber record */
755 /* LU REJ: Roaming not allowed */
756 lu_fsm_failure(fi, GSM48_REJECT_ROAMING_NOT_ALLOWED);
757 } else {
758 /* Update_HLR_VLR */
759 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_HLR_UPD,
760 LU_TIMEOUT_LONG, 0);
761 lfp->upd_hlr_vlr_fsm =
762 upd_hlr_vlr_proc_start(fi, vsub, VLR_ULA_E_UPD_HLR_COMPL);
763 }
764}
765
766/* 4.1.2.1 Node B */
767static void vlr_loc_upd_node_b(struct osmo_fsm_inst *fi)
768{
769 LOGPFSM(fi, "%s()\n", __func__);
770
Neels Hofmeyref9126c2017-07-18 15:38:39 +0200771 /* OsmoHLR does not support PgA, neither stores the IMEISV, so we have no need to update the HLR
772 * with either. TODO: depend on actual HLR configuration. See 3GPP TS 23.012 Release 14, process
773 * Update_Location_Area_VLR (ULA_VLR2). */
Harald Welteb8b85a12016-06-17 00:06:42 +0200774 if (0) { /* IMEISV or PgA to send */
775 vlr_loc_upd_node_4(fi);
776 } else {
777 /* Location_Update_Completion */
778 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_LU_COMPL,
779 LU_TIMEOUT_LONG, 0);
780 vlr_loc_upd_start_lu_compl_fsm(fi);
781 }
782}
783
784/* Non-standard: after Ciphering Mode Complete (or no ciph required) */
785static void vlr_loc_upd_post_ciph(struct osmo_fsm_inst *fi)
786{
787 struct lu_fsm_priv *lfp = fi->priv;
788 struct vlr_subscr *vsub = lfp->vsub;
789
790 LOGPFSM(fi, "%s()\n", __func__);
791
792 OSMO_ASSERT(vsub);
793
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200794 if (lfp->is_utran) {
795 int rc;
796 rc = lfp->vlr->ops.tx_common_id(lfp->msc_conn_ref);
797 if (rc)
798 LOGPFSML(fi, LOGL_ERROR,
799 "Error while sending Common ID (%d)\n", rc);
800 }
801
Harald Welteb8b85a12016-06-17 00:06:42 +0200802 vsub->conf_by_radio_contact_ind = true;
803 /* Update LAI */
804 vsub->cgi.lai = lfp->new_lai;
805 vsub->dormant_ind = false;
806 vsub->cancel_loc_rx = false;
807 if (hlr_update_needed(vsub)) {
808 vlr_loc_upd_node_4(fi);
809 } else {
810 /* TODO: ADD Support */
811 /* TODO: Node A: PgA Support */
812 vlr_loc_upd_node_b(fi);
813 }
814}
815
816/* 4.1.2.1 after Authentication successful (or no auth rqd) */
817static void vlr_loc_upd_post_auth(struct osmo_fsm_inst *fi)
818{
819 struct lu_fsm_priv *lfp = fi->priv;
820 struct vlr_subscr *vsub = lfp->vsub;
821
822 LOGPFSM(fi, "%s()\n", __func__);
823
824 OSMO_ASSERT(vsub);
825
826 if (!is_ciph_required(lfp)) {
827 vlr_loc_upd_post_ciph(fi);
828 return;
829 }
830
Neels Hofmeyr2ef2da52017-12-18 01:23:42 +0100831 if (!vsub->last_tuple) {
832 LOGPFSML(fi, LOGL_ERROR, "No auth tuple available\n");
833 vlr_lu_compl_fsm_failure(fi, GSM48_REJECT_NETWORK_FAILURE);
834 return;
835 }
836
Harald Welteb8b85a12016-06-17 00:06:42 +0200837 if (vlr_set_ciph_mode(vsub->vlr, fi, lfp->msc_conn_ref,
838 lfp->ciphering_required,
Neels Hofmeyr2ef2da52017-12-18 01:23:42 +0100839 vlr_use_umts_aka(&vsub->last_tuple->vec, lfp->is_r99),
Neels Hofmeyr54a706c2017-07-18 15:39:27 +0200840 vsub->vlr->cfg.retrieve_imeisv_ciphered)) {
Harald Welteb8b85a12016-06-17 00:06:42 +0200841 LOGPFSML(fi, LOGL_ERROR,
842 "Failed to send Ciphering Mode Command\n");
843 vlr_lu_compl_fsm_failure(fi, GSM48_REJECT_NETWORK_FAILURE);
844 return;
845 }
846
847 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_CIPH, LU_TIMEOUT_LONG, 0);
848}
849
850static void vlr_loc_upd_node1(struct osmo_fsm_inst *fi)
851{
852 struct lu_fsm_priv *lfp = fi->priv;
853 struct vlr_subscr *vsub = lfp->vsub;
854
855 LOGPFSM(fi, "%s()\n", __func__);
856
857 OSMO_ASSERT(vsub);
858
859 if (is_auth_required(lfp)) {
860 /* Authenticate_VLR */
861 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_AUTH,
862 LU_TIMEOUT_LONG, 0);
863 vsub->auth_fsm = auth_fsm_start(lfp->vsub, fi->log_level,
864 fi, VLR_ULA_E_AUTH_RES,
865 lfp->is_r99,
866 lfp->is_utran);
867 } else {
868 /* no need for authentication */
869 vlr_loc_upd_post_auth(fi);
870 }
871}
872
873static void vlr_loc_upd_want_imsi(struct osmo_fsm_inst *fi)
874{
875 struct lu_fsm_priv *lfp = fi->priv;
876 struct vlr_instance *vlr = lfp->vlr;
877
878 LOGPFSM(fi, "%s()\n", __func__);
879
880 OSMO_ASSERT(lfp->vsub);
881
882 /* Obtain_IMSI_VLR */
883 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_IMSI,
884 vlr_timer(vlr, 3270), 3270);
885 vlr->ops.tx_id_req(lfp->msc_conn_ref, GSM_MI_TYPE_IMSI);
886 /* will continue at vlr_loc_upd_node1() once IMSI arrives */
887}
888
889static int assoc_lfp_with_sub(struct osmo_fsm_inst *fi, struct vlr_subscr *vsub)
890{
891 struct lu_fsm_priv *lfp = fi->priv;
892 struct vlr_instance *vlr = lfp->vlr;
893
894 if (vsub->lu_fsm) {
895 LOGPFSML(fi, LOGL_ERROR,
896 "A Location Updating process is already pending for"
897 " this subscriber. Aborting.\n");
898 /* Also get rid of the other pending LU attempt? */
899 /*lu_fsm_failure(vsub->lu_fsm, GSM48_REJECT_CONGESTION);*/
900 lu_fsm_failure(fi, GSM48_REJECT_CONGESTION);
901 return -EINVAL;
902 }
903 vsub->lu_fsm = fi;
904 vsub->msc_conn_ref = lfp->msc_conn_ref;
905 /* FIXME: send new LAC to HLR? */
906 vsub->lac = lfp->new_lai.lac;
907 lfp->vsub = vsub;
908 /* Tell MSC to associate this subscriber with the given
909 * connection */
910 vlr->ops.subscr_assoc(lfp->msc_conn_ref, lfp->vsub);
911 return 0;
912}
913
914static const char *lai_name(struct osmo_location_area_id *lai)
915{
916 static char buf[64];
917 snprintf(buf, sizeof(buf),"MCC:%u, MNC:%u, LAC:%u",
918 lai->plmn.mcc, lai->plmn.mnc, lai->lac);
919 return buf;
920}
921
Neels Hofmeyr54a706c2017-07-18 15:39:27 +0200922static int _lu_fsm_associate_vsub(struct osmo_fsm_inst *fi)
923{
924 struct lu_fsm_priv *lfp = fi->priv;
925 struct vlr_instance *vlr = lfp->vlr;
926 struct vlr_subscr *vsub = NULL;
927
928 if (!lfp->imsi[0]) {
929 /* TMSI was used */
930 lfp->lu_by_tmsi = true;
931 /* TMSI clash: if a different subscriber already has this TMSI,
932 * we will find that other subscriber in the VLR. So the IMSIs
933 * would mismatch, but we don't know about it. Theoretically,
934 * an authentication process would thwart any attempt to use
935 * someone else's TMSI.
936 * TODO: Otherwise we can ask for the IMSI and verify that it
937 * matches the IMSI on record. */
938 vsub = vlr_subscr_find_or_create_by_tmsi(vlr, lfp->tmsi, NULL);
939
940 if (!vsub) {
941 LOGPFSML(fi, LOGL_ERROR, "VLR subscriber allocation failed\n");
942 lu_fsm_failure(fi, GSM48_REJECT_SRV_OPT_TMP_OUT_OF_ORDER);
943 return -1;
944 }
945
946 vsub->sub_dataconf_by_hlr_ind = false;
947 if (assoc_lfp_with_sub(fi, vsub)) {
948 vlr_subscr_put(vsub);
949 return -1; /* error, fsm failure invoked in assoc_lfp_with_sub() */
950 }
951 vlr_subscr_put(vsub);
952 } else {
953 /* IMSI was used */
954 vsub = vlr_subscr_find_or_create_by_imsi(vlr, lfp->imsi, NULL);
955
956 if (!vsub) {
957 LOGPFSML(fi, LOGL_ERROR, "VLR subscriber allocation failed\n");
958 lu_fsm_failure(fi, GSM48_REJECT_SRV_OPT_TMP_OUT_OF_ORDER);
959 vlr_subscr_put(vsub);
960 return -1;
961 }
962
963 vsub->sub_dataconf_by_hlr_ind = false;
964 if (assoc_lfp_with_sub(fi, vsub)) {
965 vlr_subscr_put(vsub);
966 return -1; /* error, fsm failure invoked in assoc_lfp_with_sub() */
967 }
968 vlr_subscr_put(vsub);
969 }
970 return 0;
971}
972
Harald Welteb8b85a12016-06-17 00:06:42 +0200973/* 4.1.2.1: Subscriber (via MSC/SGSN) requests location update */
974static void _start_lu_main(struct osmo_fsm_inst *fi)
975{
976 struct lu_fsm_priv *lfp = fi->priv;
977 struct vlr_instance *vlr = lfp->vlr;
Harald Welteb8b85a12016-06-17 00:06:42 +0200978
979 /* TODO: PUESBINE related handling */
980
981 /* Is previous LAI in this VLR? */
982 if (!lai_in_this_vlr(vlr, &lfp->old_lai)) {
983#if 0
984 /* FIXME: check previous VLR, (3) */
985 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_PVLR,
986 LU_TIMEOUT_LONG, 0);
987 return;
988#endif
989 LOGPFSML(fi, LOGL_NOTICE, "LAI change from %s,"
990 " but checking previous VLR not implemented\n",
991 lai_name(&lfp->old_lai));
992 }
993
Neels Hofmeyr54a706c2017-07-18 15:39:27 +0200994 /* If this is a TMSI based LU, we may not have the IMSI. Make sure that
995 * we know the IMSI, either on record, or request it. */
996 if (!lfp->vsub->imsi[0])
997 vlr_loc_upd_want_imsi(fi);
998 else
Harald Welteb8b85a12016-06-17 00:06:42 +0200999 vlr_loc_upd_node1(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001000}
1001
Harald Welteb8b85a12016-06-17 00:06:42 +02001002static void lu_fsm_idle(struct osmo_fsm_inst *fi, uint32_t event,
1003 void *data)
1004{
1005 struct lu_fsm_priv *lfp = fi->priv;
1006 struct vlr_instance *vlr = lfp->vlr;
1007
1008 OSMO_ASSERT(event == VLR_ULA_E_UPDATE_LA);
1009
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001010 if (_lu_fsm_associate_vsub(fi))
1011 return; /* error. FSM already terminated. */
1012
1013 OSMO_ASSERT(lfp->vsub);
1014
1015 /* See 3GPP TS 23.012, procedure Retrieve_IMEISV_If_Required */
1016 if ((!vlr->cfg.retrieve_imeisv_early)
1017 || (lfp->type == VLR_LU_TYPE_PERIODIC && lfp->vsub->imeisv[0])) {
Harald Welteb8b85a12016-06-17 00:06:42 +02001018 /* R_IMEISV_IR1 passed */
1019 _start_lu_main(fi);
1020 } else {
1021 vlr->ops.tx_id_req(lfp->msc_conn_ref, GSM_MI_TYPE_IMEISV);
1022 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_IMEISV,
1023 vlr_timer(vlr, 3270), 3270);
1024 }
1025}
1026
1027static void lu_fsm_wait_imeisv(struct osmo_fsm_inst *fi, uint32_t event,
1028 void *data)
1029{
1030 switch (event) {
1031 case VLR_ULA_E_ID_IMEISV:
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001032 /* IMEISV was copied in vlr_subscr_rx_id_resp(), and that's
1033 * where we received this event from. */
Harald Welteb8b85a12016-06-17 00:06:42 +02001034 _start_lu_main(fi);
1035 break;
1036 default:
1037 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1038 osmo_fsm_event_name(fi->fsm, event));
1039 break;
1040 }
1041}
1042
1043/* Wait for response from Send_Identification to PVLR */
1044static void lu_fsm_wait_pvlr(struct osmo_fsm_inst *fi, uint32_t event,
1045 void *data)
1046{
1047 switch (event) {
1048 case VLR_ULA_E_SEND_ID_ACK:
1049 vlr_loc_upd_node1(fi);
1050 break;
1051 case VLR_ULA_E_SEND_ID_NACK:
1052 vlr_loc_upd_want_imsi(fi);
1053 break;
1054 default:
1055 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1056 osmo_fsm_event_name(fi->fsm, event));
1057 break;
1058 }
1059}
1060
1061/* Wait for result of Authenticate_VLR procedure */
1062static void lu_fsm_wait_auth(struct osmo_fsm_inst *fi, uint32_t event,
1063 void *data)
1064{
1065 struct lu_fsm_priv *lfp = fi->priv;
1066 enum vlr_auth_fsm_result *res = data;
1067 uint8_t rej_cause = 0;
1068
1069 OSMO_ASSERT(event == VLR_ULA_E_AUTH_RES);
1070
1071 lfp->upd_hlr_vlr_fsm = NULL;
1072
1073 if (res) {
1074 switch (*res) {
1075 case VLR_AUTH_RES_PASSED:
1076 /* Result == Pass */
1077 vlr_loc_upd_post_auth(fi);
1078 return;
1079 case VLR_AUTH_RES_ABORTED:
1080 /* go to Idle with no response */
1081 rej_cause = 0;
1082 break;
1083 case VLR_AUTH_RES_UNKNOWN_SUBSCR:
1084 /* FIXME: delete subscribe record */
1085 rej_cause = GSM48_REJECT_IMSI_UNKNOWN_IN_HLR;
1086 break;
1087 case VLR_AUTH_RES_AUTH_FAILED:
1088 /* cause = illegal subscriber */
1089 rej_cause = GSM48_REJECT_ILLEGAL_MS;
1090 break;
1091 case VLR_AUTH_RES_PROC_ERR:
1092 /* cause = system failure */
1093 rej_cause = GSM48_REJECT_NETWORK_FAILURE;
1094 break;
1095 default:
1096 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1097 osmo_fsm_event_name(fi->fsm, event));
1098 break;
1099 }
1100 } else
1101 rej_cause = GSM48_REJECT_NETWORK_FAILURE;
1102
1103 lu_fsm_failure(fi, rej_cause);
1104}
1105
1106static void lu_fsm_wait_ciph(struct osmo_fsm_inst *fi, uint32_t event,
1107 void *data)
1108{
1109 struct lu_fsm_priv *lfp = fi->priv;
1110 struct vlr_subscr *vsub = lfp->vsub;
1111 struct vlr_ciph_result res = { .cause = VLR_CIPH_REJECT };
1112
1113 OSMO_ASSERT(event == VLR_ULA_E_CIPH_RES);
1114
1115 if (!data)
1116 LOGPFSML(fi, LOGL_ERROR, "invalid ciphering result: NULL\n");
1117 else
1118 res = *(struct vlr_ciph_result*)data;
1119
1120 switch (res.cause) {
1121 case VLR_CIPH_COMPL:
1122 break;
1123 case VLR_CIPH_REJECT:
1124 LOGPFSM(fi, "ciphering rejected\n");
1125 lu_fsm_failure(fi, GSM48_REJECT_INVALID_MANDANTORY_INF);
1126 return;
1127 default:
1128 LOGPFSML(fi, LOGL_ERROR, "invalid ciphering result: %d\n",
1129 res.cause);
1130 lu_fsm_failure(fi, GSM48_REJECT_INVALID_MANDANTORY_INF);
1131 return;
1132 }
1133
1134 if (res.imeisv) {
1135 LOGPFSM(fi, "got IMEISV: %s\n", res.imeisv);
1136 vlr_subscr_set_imeisv(vsub, res.imeisv);
1137 }
1138 vlr_loc_upd_post_ciph(fi);
1139}
1140
1141static void lu_fsm_wait_imsi(struct osmo_fsm_inst *fi, uint32_t event,
1142 void *data)
1143{
1144 struct lu_fsm_priv *lfp = fi->priv;
1145 struct vlr_subscr *vsub = lfp->vsub;
1146 char *mi_string = data;
1147
1148 switch (event) {
1149 case VLR_ULA_E_ID_IMSI:
1150 vlr_subscr_set_imsi(vsub, mi_string);
1151 vlr_loc_upd_node1(fi);
1152 break;
1153 default:
1154 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1155 osmo_fsm_event_name(fi->fsm, event));
1156 break;
1157 }
1158}
1159
1160/* At the end of Update_HLR_VLR */
1161static void lu_fsm_wait_hlr_ul_res(struct osmo_fsm_inst *fi, uint32_t event,
1162 void *data)
1163{
1164 struct lu_fsm_priv *lfp = fi->priv;
1165
1166 switch (event) {
1167 case VLR_ULA_E_HLR_LU_RES:
1168 /* pass-through this event to Update_HLR_VLR */
1169 if (data == NULL)
1170 osmo_fsm_inst_dispatch(lfp->upd_hlr_vlr_fsm, UPD_HLR_VLR_E_UPD_LOC_ACK, NULL);
1171 else
1172 osmo_fsm_inst_dispatch(lfp->upd_hlr_vlr_fsm, UPD_HLR_VLR_E_UPD_LOC_NACK, data);
1173 break;
1174 case VLR_ULA_E_UPD_HLR_COMPL:
1175 if (data == NULL) {
1176 /* successful case */
1177 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_LU_COMPL,
1178 LU_TIMEOUT_LONG, 0);
1179 vlr_loc_upd_start_lu_compl_fsm(fi);
1180 /* continue in MSC ?!? */
1181 } else {
1182 /* unsuccessful case */
1183 enum gsm48_gmm_cause cause =
1184 *(enum gsm48_gmm_cause *)data;
Neels Hofmeyref9126c2017-07-18 15:38:39 +02001185 /* Ignoring standalone mode for now. */
Harald Welteb8b85a12016-06-17 00:06:42 +02001186 if (0 /* procedure_error && vlr->cfg.standalone_mode */) {
1187 osmo_fsm_inst_state_chg(fi,
1188 VLR_ULA_S_WAIT_LU_COMPL_STANDALONE,
1189 LU_TIMEOUT_LONG, 0);
1190 vlr_loc_upd_start_lu_compl_fsm(fi);
1191 } else {
1192 lu_fsm_failure(fi, cause);
1193 }
1194 }
1195 break;
1196 default:
1197 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1198 osmo_fsm_event_name(fi->fsm, event));
1199 break;
1200 }
1201}
1202
1203/* Wait for end of Location_Update_Completion_VLR */
1204static void lu_fsm_wait_lu_compl(struct osmo_fsm_inst *fi, uint32_t event,
1205 void *data)
1206{
1207 struct lu_fsm_priv *lfp = fi->priv;
1208 uint8_t cause;
1209
1210 switch (event) {
1211 case VLR_ULA_E_NEW_TMSI_ACK:
1212 osmo_fsm_inst_dispatch(lfp->lu_compl_vlr_fsm,
1213 LU_COMPL_VLR_E_NEW_TMSI_ACK, NULL);
1214 break;
1215 case VLR_ULA_E_ID_IMEI:
1216 osmo_fsm_inst_dispatch(lfp->lu_compl_vlr_fsm,
1217 LU_COMPL_VLR_E_IMEI_CHECK_ACK, NULL);
1218 break;
1219 case VLR_ULA_E_LU_COMPL_SUCCESS:
1220 lu_fsm_discard_lu_compl_fsm(fi);
1221
1222 /* Update Register */
1223 /* TODO: Set_Notification_Type 23.078 */
1224 /* TODO: Notify_gsmSCF 23.078 */
1225 /* TODO: Authenticated Radio Contact Established -> ARC */
1226 lu_fsm_success(fi);
1227 break;
1228 case VLR_ULA_E_LU_COMPL_FAILURE:
1229 cause = GSM48_REJECT_NETWORK_FAILURE;
1230 if (data)
1231 cause = *(uint8_t*)data;
1232 lu_fsm_discard_lu_compl_fsm(fi);
1233 lu_fsm_failure(fi, cause);
1234 break;
1235 default:
1236 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1237 osmo_fsm_event_name(fi->fsm, event));
1238 break;
1239 }
1240}
1241
1242/* Wait for end of Location_Update_Completion_VLR (standalone case) */
1243static void lu_fsm_wait_lu_compl_standalone(struct osmo_fsm_inst *fi,
1244 uint32_t event, void *data)
1245{
1246 struct lu_fsm_priv *lfp = fi->priv;
1247 struct vlr_subscr *vsub = lfp->vsub;
1248 uint8_t cause;
1249
1250 switch (event) {
1251 case VLR_ULA_E_NEW_TMSI_ACK:
1252 osmo_fsm_inst_dispatch(lfp->lu_compl_vlr_fsm,
1253 LU_COMPL_VLR_E_NEW_TMSI_ACK, NULL);
1254 break;
1255 case VLR_ULA_E_LU_COMPL_SUCCESS:
1256 lu_fsm_discard_lu_compl_fsm(fi);
1257 vsub->sub_dataconf_by_hlr_ind = false;
1258 lu_fsm_success(fi);
1259 break;
1260 case VLR_ULA_E_LU_COMPL_FAILURE:
1261 vsub->sub_dataconf_by_hlr_ind = false;
1262 cause = GSM48_REJECT_NETWORK_FAILURE;
1263 if (data)
1264 cause = *(uint8_t*)data;
1265 lu_fsm_discard_lu_compl_fsm(fi);
1266 lu_fsm_failure(fi, cause);
1267 break;
1268 default:
1269 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1270 osmo_fsm_event_name(fi->fsm, event));
1271 break;
1272 }
1273}
1274
1275static const struct osmo_fsm_state vlr_lu_fsm_states[] = {
1276 [VLR_ULA_S_IDLE] = {
1277 .in_event_mask = S(VLR_ULA_E_UPDATE_LA),
1278 .out_state_mask = S(VLR_ULA_S_WAIT_IMEISV) |
1279 S(VLR_ULA_S_WAIT_PVLR) |
1280 S(VLR_ULA_S_WAIT_IMSI) |
1281 S(VLR_ULA_S_WAIT_AUTH) |
1282 S(VLR_ULA_S_WAIT_HLR_UPD) |
1283 S(VLR_ULA_S_DONE),
1284 .name = OSMO_STRINGIFY(VLR_ULA_S_IDLE),
1285 .action = lu_fsm_idle,
1286 },
1287 [VLR_ULA_S_WAIT_IMEISV] = {
1288 .in_event_mask = S(VLR_ULA_E_ID_IMEISV),
1289 .out_state_mask = S(VLR_ULA_S_WAIT_PVLR) |
1290 S(VLR_ULA_S_WAIT_IMSI) |
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001291 S(VLR_ULA_S_WAIT_AUTH) |
1292 S(VLR_ULA_S_WAIT_HLR_UPD) |
Harald Welteb8b85a12016-06-17 00:06:42 +02001293 S(VLR_ULA_S_DONE),
1294 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_IMEISV),
1295 .action = lu_fsm_wait_imeisv,
1296 },
1297 [VLR_ULA_S_WAIT_PVLR] = {
1298 .in_event_mask = S(VLR_ULA_E_SEND_ID_ACK) |
1299 S(VLR_ULA_E_SEND_ID_NACK),
1300 .out_state_mask = S(VLR_ULA_S_WAIT_IMSI) |
1301 S(VLR_ULA_S_WAIT_AUTH) |
1302 S(VLR_ULA_S_DONE),
1303 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_PVLR),
1304 .action = lu_fsm_wait_pvlr,
1305 },
1306 [VLR_ULA_S_WAIT_AUTH] = {
1307 .in_event_mask = S(VLR_ULA_E_AUTH_RES),
1308 .out_state_mask = S(VLR_ULA_S_WAIT_CIPH) |
1309 S(VLR_ULA_S_WAIT_LU_COMPL) |
1310 S(VLR_ULA_S_WAIT_HLR_UPD) |
1311 S(VLR_ULA_S_DONE),
1312 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_AUTH),
1313 .action = lu_fsm_wait_auth,
1314 },
1315 [VLR_ULA_S_WAIT_CIPH] = {
1316 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_CIPH),
1317 .in_event_mask = S(VLR_ULA_E_CIPH_RES),
1318 .out_state_mask = S(VLR_ULA_S_WAIT_LU_COMPL) |
1319 S(VLR_ULA_S_WAIT_HLR_UPD) |
1320 S(VLR_ULA_S_DONE),
1321 .action = lu_fsm_wait_ciph,
1322 },
1323 [VLR_ULA_S_WAIT_IMSI] = {
1324 .in_event_mask = S(VLR_ULA_E_ID_IMSI),
1325 .out_state_mask = S(VLR_ULA_S_WAIT_AUTH) |
1326 S(VLR_ULA_S_WAIT_HLR_UPD) |
1327 S(VLR_ULA_S_DONE),
1328 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_IMSI),
1329 .action = lu_fsm_wait_imsi,
1330 },
1331 [VLR_ULA_S_WAIT_HLR_UPD] = {
1332 .in_event_mask = S(VLR_ULA_E_HLR_LU_RES) |
1333 S(VLR_ULA_E_UPD_HLR_COMPL),
1334 .out_state_mask = S(VLR_ULA_S_WAIT_LU_COMPL) |
1335 S(VLR_ULA_S_WAIT_LU_COMPL_STANDALONE) |
1336 S(VLR_ULA_S_DONE),
1337 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_HLR_UPD),
1338 .action = lu_fsm_wait_hlr_ul_res,
1339 },
1340 [VLR_ULA_S_WAIT_LU_COMPL] = {
1341 .in_event_mask = S(VLR_ULA_E_LU_COMPL_SUCCESS) |
1342 S(VLR_ULA_E_LU_COMPL_FAILURE) |
1343 S(VLR_ULA_E_NEW_TMSI_ACK) |
1344 S(VLR_ULA_E_ID_IMEI) |
1345 S(VLR_ULA_E_ID_IMEISV),
1346 .out_state_mask = S(VLR_ULA_S_DONE),
1347 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_LU_COMPL),
1348 .action = lu_fsm_wait_lu_compl,
1349 },
1350 [VLR_ULA_S_WAIT_LU_COMPL_STANDALONE] = {
1351 .in_event_mask = S(VLR_ULA_E_LU_COMPL_SUCCESS) |
1352 S(VLR_ULA_E_LU_COMPL_FAILURE) |
1353 S(VLR_ULA_E_NEW_TMSI_ACK),
1354 .out_state_mask = S(VLR_ULA_S_DONE),
1355 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_LU_COMPL_STANDALONE),
1356 .action = lu_fsm_wait_lu_compl_standalone,
1357 },
1358 [VLR_ULA_S_DONE] = {
1359 .name = OSMO_STRINGIFY(VLR_ULA_S_DONE),
1360 .onenter = lu_fsm_dispatch_result,
1361 },
1362};
1363
1364static void fsm_lu_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
1365{
1366 struct lu_fsm_priv *lfp = fi->priv;
1367 struct vlr_subscr *vsub = lfp->vsub;
1368
1369 LOGPFSM(fi, "fsm_lu_cleanup called with cause %s\n",
1370 osmo_fsm_term_cause_name(cause));
1371 if (vsub && vsub->lu_fsm == fi)
1372 vsub->lu_fsm = NULL;
1373}
1374
1375static struct osmo_fsm vlr_lu_fsm = {
1376 .name = "vlr_lu_fsm",
1377 .states = vlr_lu_fsm_states,
1378 .num_states = ARRAY_SIZE(vlr_lu_fsm_states),
1379 .allstate_event_mask = 0,
1380 .allstate_action = NULL,
1381 .log_subsys = DVLR,
1382 .event_names = fsm_lu_event_names,
1383 .cleanup = fsm_lu_cleanup,
1384};
1385
1386struct osmo_fsm_inst *
1387vlr_loc_update(struct osmo_fsm_inst *parent,
1388 uint32_t parent_event_success,
1389 uint32_t parent_event_failure,
1390 void *parent_event_data,
1391 struct vlr_instance *vlr, void *msc_conn_ref,
1392 enum vlr_lu_type type, uint32_t tmsi, const char *imsi,
1393 const struct osmo_location_area_id *old_lai,
1394 const struct osmo_location_area_id *new_lai,
1395 bool authentication_required,
Harald Welte71c51df2017-12-23 18:51:48 +01001396 bool ciphering_required,
Harald Welteb8b85a12016-06-17 00:06:42 +02001397 bool is_r99, bool is_utran,
1398 bool assign_tmsi)
1399{
1400 struct osmo_fsm_inst *fi;
1401 struct lu_fsm_priv *lfp;
1402
1403 fi = osmo_fsm_inst_alloc_child(&vlr_lu_fsm, parent, parent_event_failure);
1404 if (!fi)
1405 return NULL;
1406
1407 lfp = talloc_zero(fi, struct lu_fsm_priv);
1408 lfp->vlr = vlr;
1409 lfp->msc_conn_ref = msc_conn_ref;
1410 lfp->tmsi = tmsi;
1411 lfp->type = type;
1412 lfp->old_lai = *old_lai;
1413 lfp->new_lai = *new_lai;
1414 lfp->lu_by_tmsi = true;
1415 lfp->parent_event_success = parent_event_success;
1416 lfp->parent_event_failure = parent_event_failure;
1417 lfp->parent_event_data = parent_event_data;
1418 lfp->authentication_required = authentication_required;
1419 lfp->ciphering_required = ciphering_required;
1420 lfp->is_r99 = is_r99;
1421 lfp->is_utran = is_utran;
1422 lfp->assign_tmsi = assign_tmsi;
1423 if (imsi) {
1424 strncpy(lfp->imsi, imsi, sizeof(lfp->imsi)-1);
1425 lfp->imsi[sizeof(lfp->imsi)-1] = '\0';
1426 lfp->lu_by_tmsi = false;
1427 }
1428 fi->priv = lfp;
1429
1430 LOGPFSM(fi, "rev=%s net=%s%s%s\n",
1431 is_r99 ? "R99" : "GSM",
1432 is_utran ? "UTRAN" : "GERAN",
1433 (authentication_required || ciphering_required)?
1434 " Auth" : " (no Auth)",
1435 (authentication_required || ciphering_required)?
1436 (ciphering_required? "+Ciph" : " (no Ciph)")
1437 : "");
1438
Neels Hofmeyr84da6b12016-05-20 21:59:55 +02001439 if (is_utran && !authentication_required)
1440 LOGPFSML(fi, LOGL_ERROR,
1441 "Authentication off on UTRAN network. Good luck.\n");
1442
Harald Welteb8b85a12016-06-17 00:06:42 +02001443 osmo_fsm_inst_dispatch(fi, VLR_ULA_E_UPDATE_LA, NULL);
1444
1445 return fi;
1446}
1447
1448/* Gracefully terminate an FSM created by vlr_loc_update() in case of external
1449 * timeout (i.e. from MSC). */
1450void vlr_loc_update_conn_timeout(struct osmo_fsm_inst *fi)
1451{
1452 if (!fi || fi->state == VLR_ULA_S_DONE)
1453 return;
1454 LOGPFSM(fi, "Connection timed out\n");
1455 lu_fsm_failure(fi, GSM48_REJECT_CONGESTION);
1456}
1457
1458void vlr_lu_fsm_init(void)
1459{
1460 osmo_fsm_register(&vlr_lu_fsm);
1461 osmo_fsm_register(&upd_hlr_vlr_fsm);
1462 osmo_fsm_register(&sub_pres_vlr_fsm);
1463 osmo_fsm_register(&lu_compl_vlr_fsm);
1464}