blob: 02e49e065503d9b6910a21d9928abbb0212e8a31 [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
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +010071static inline struct vlr_subscr *upd_hlr_vlr_fi_priv(struct osmo_fsm_inst *fi);
72
Harald Welteb8b85a12016-06-17 00:06:42 +020073static void upd_hlr_vlr_fsm_init(struct osmo_fsm_inst *fi, uint32_t event,
74 void *data)
75{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +010076 struct vlr_subscr *vsub = upd_hlr_vlr_fi_priv(fi);
Max770fbd22018-01-24 12:48:33 +010077 int rc;
Harald Welteb8b85a12016-06-17 00:06:42 +020078
79 OSMO_ASSERT(event == UPD_HLR_VLR_E_START);
80
81 /* Send UpdateLocation to HLR */
Philipp Maier6038ad42018-11-13 13:55:09 +010082 rc = vlr_subscr_req_lu(vsub);
Max770fbd22018-01-24 12:48:33 +010083 if (rc < 0)
84 LOGPFSML(fi, LOGL_ERROR, "Failed to send UpdateLocation to HLR\n");
Harald Welteb8b85a12016-06-17 00:06:42 +020085 osmo_fsm_inst_state_chg(fi, UPD_HLR_VLR_S_WAIT_FOR_DATA,
86 LU_TIMEOUT_LONG, 0);
87}
88
89static void upd_hlr_vlr_fsm_wait_data(struct osmo_fsm_inst *fi, uint32_t event,
90 void *data)
91{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +010092 struct vlr_subscr *vsub = upd_hlr_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +020093
94 switch (event) {
95 case UPD_HLR_VLR_E_INS_SUB_DATA:
96 /* FIXME: Insert_Subscr_Data_VLR */
97 break;
98 case UPD_HLR_VLR_E_ACT_TRACE_MODE:
99 /* TODO: Activate_Tracing_VLR */
100 break;
101 case UPD_HLR_VLR_E_FW_CHECK_SS_IND:
102 /* TODO: Forward Check SS Ind to MSC */
103 break;
104 case UPD_HLR_VLR_E_UPD_LOC_ACK:
105 /* Inside Update_HLR_VLR after UpdateLocationAck */
106 vsub->sub_dataconf_by_hlr_ind = true;
107 vsub->loc_conf_in_hlr_ind = true;
108 osmo_fsm_inst_state_chg(fi, UPD_HLR_VLR_S_DONE, 0, 0);
109 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
110 break;
111 case UPD_HLR_VLR_E_UPD_LOC_NACK:
112 /* Inside Update_HLR_VLR after UpdateLocationNack */
113 /* TODO: Check_User_Error_In_Serving_Network_Entity */
114 vsub->sub_dataconf_by_hlr_ind = false;
115 vsub->loc_conf_in_hlr_ind = false;
116 osmo_fsm_inst_state_chg(fi, UPD_HLR_VLR_S_DONE, 0, 0);
117 /* Data is a pointer to a gsm48_gmm_cause which we
118 * simply pass through */
119 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, data);
120 break;
121 }
122}
123
124static const struct osmo_fsm_state upd_hlr_vlr_states[] = {
125 [UPD_HLR_VLR_S_INIT] = {
126 .in_event_mask = S(UPD_HLR_VLR_E_START),
127 .out_state_mask = S(UPD_HLR_VLR_S_WAIT_FOR_DATA),
128 .name = OSMO_STRINGIFY(UPD_HLR_VLR_S_INIT),
129 .action = upd_hlr_vlr_fsm_init,
130 },
131 [UPD_HLR_VLR_S_WAIT_FOR_DATA] = {
132 .in_event_mask = S(UPD_HLR_VLR_E_INS_SUB_DATA) |
133 S(UPD_HLR_VLR_E_ACT_TRACE_MODE) |
134 S(UPD_HLR_VLR_E_FW_CHECK_SS_IND) |
135 S(UPD_HLR_VLR_E_UPD_LOC_ACK) |
136 S(UPD_HLR_VLR_E_UPD_LOC_NACK),
137 .out_state_mask = S(UPD_HLR_VLR_S_DONE),
138 .name = OSMO_STRINGIFY(UPD_HLR_VLR_S_WAIT_FOR_DATA),
139 .action = upd_hlr_vlr_fsm_wait_data,
140 },
141 [UPD_HLR_VLR_S_DONE] = {
142 .name = OSMO_STRINGIFY(UPD_HLR_VLR_S_DONE),
143 },
144};
145
146static struct osmo_fsm upd_hlr_vlr_fsm = {
147 .name = "upd_hlr_vlr_fsm",
148 .states = upd_hlr_vlr_states,
149 .num_states = ARRAY_SIZE(upd_hlr_vlr_states),
150 .allstate_event_mask = 0,
151 .allstate_action = NULL,
152 .log_subsys = DVLR,
153 .event_names = upd_hlr_vlr_event_names,
154};
155
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100156static inline struct vlr_subscr *upd_hlr_vlr_fi_priv(struct osmo_fsm_inst *fi)
157{
158 OSMO_ASSERT(fi->fsm == &upd_hlr_vlr_fsm);
159 return (struct vlr_subscr*)fi->priv;
160}
161
Harald Welteb8b85a12016-06-17 00:06:42 +0200162struct osmo_fsm_inst *
163upd_hlr_vlr_proc_start(struct osmo_fsm_inst *parent,
164 struct vlr_subscr *vsub,
165 uint32_t parent_event)
166{
167 struct osmo_fsm_inst *fi;
168
169 fi = osmo_fsm_inst_alloc_child(&upd_hlr_vlr_fsm, parent,
170 parent_event);
171 if (!fi)
172 return NULL;
173
174 fi->priv = vsub;
175 osmo_fsm_inst_dispatch(fi, UPD_HLR_VLR_E_START, NULL);
176
177 return fi;
178}
179
180
181/***********************************************************************
182 * Subscriber_Present_VLR, TS 29.002 Chapter 25.10.1
183 ***********************************************************************/
184
185enum sub_pres_vlr_state {
186 SUB_PRES_VLR_S_INIT,
187 SUB_PRES_VLR_S_WAIT_FOR_HLR,
188 SUB_PRES_VLR_S_DONE,
189};
190
191enum sub_pres_vlr_event {
192 SUB_PRES_VLR_E_START,
193 SUB_PRES_VLR_E_READY_SM_CNF,
194 SUB_PRES_VLR_E_READY_SM_ERR,
195};
196
197static const struct value_string sub_pres_vlr_event_names[] = {
198 OSMO_VALUE_STRING(SUB_PRES_VLR_E_START),
199 OSMO_VALUE_STRING(SUB_PRES_VLR_E_READY_SM_CNF),
200 OSMO_VALUE_STRING(SUB_PRES_VLR_E_READY_SM_ERR),
201 { 0, NULL }
202};
203
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100204static inline struct vlr_subscr *sub_pres_vlr_fi_priv(struct osmo_fsm_inst *fi);
205
Harald Welteb8b85a12016-06-17 00:06:42 +0200206static void sub_pres_vlr_fsm_init(struct osmo_fsm_inst *fi, uint32_t event,
207 void *data)
208{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100209 struct vlr_subscr *vsub = sub_pres_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200210 OSMO_ASSERT(event == SUB_PRES_VLR_E_START);
211
212 if (!vsub->ms_not_reachable_flag) {
213 osmo_fsm_inst_state_chg(fi, SUB_PRES_VLR_S_DONE, 0, 0);
214 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
215 return;
216 }
217 /* FIXME: Send READY_FOR_SM via GSUP */
218 osmo_fsm_inst_state_chg(fi, SUB_PRES_VLR_S_WAIT_FOR_HLR,
219 LU_TIMEOUT_LONG, 0);
220}
221
222static void sub_pres_vlr_fsm_wait_hlr(struct osmo_fsm_inst *fi, uint32_t event,
223 void *data)
224{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100225 struct vlr_subscr *vsub = sub_pres_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200226
227 switch (event) {
228 case SUB_PRES_VLR_E_READY_SM_CNF:
229 vsub->ms_not_reachable_flag = false;
230 break;
231 case SUB_PRES_VLR_E_READY_SM_ERR:
232 break;
233 }
234 osmo_fsm_inst_state_chg(fi, SUB_PRES_VLR_S_DONE, 0, 0);
235 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
236}
237
238static const struct osmo_fsm_state sub_pres_vlr_states[] = {
239 [SUB_PRES_VLR_S_INIT] = {
240 .in_event_mask = S(SUB_PRES_VLR_E_START),
241 .out_state_mask = S(SUB_PRES_VLR_S_WAIT_FOR_HLR) |
242 S(SUB_PRES_VLR_S_DONE),
243 .name = OSMO_STRINGIFY(SUB_PRES_VLR_S_INIT),
244 .action = sub_pres_vlr_fsm_init,
245 },
246 [SUB_PRES_VLR_S_WAIT_FOR_HLR] = {
247 .in_event_mask = S(SUB_PRES_VLR_E_READY_SM_CNF) |
248 S(SUB_PRES_VLR_E_READY_SM_ERR),
249 .out_state_mask = S(SUB_PRES_VLR_S_DONE),
250 .name = OSMO_STRINGIFY(SUB_PRES_VLR_S_WAIT_FOR_HLR),
251 .action = sub_pres_vlr_fsm_wait_hlr,
252 },
253 [SUB_PRES_VLR_S_DONE] = {
254 .name = OSMO_STRINGIFY(SUB_PRES_VLR_S_DONE),
255 },
256};
257
258static struct osmo_fsm sub_pres_vlr_fsm = {
259 .name = "sub_pres_vlr_fsm",
260 .states = sub_pres_vlr_states,
261 .num_states = ARRAY_SIZE(sub_pres_vlr_states),
262 .allstate_event_mask = 0,
263 .allstate_action = NULL,
264 .log_subsys = DVLR,
265 .event_names = sub_pres_vlr_event_names,
266};
267
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100268static inline struct vlr_subscr *sub_pres_vlr_fi_priv(struct osmo_fsm_inst *fi)
269{
270 OSMO_ASSERT(fi->fsm == &sub_pres_vlr_fsm);
271 return (struct vlr_subscr*)fi->priv;
272}
273
Neels Hofmeyr1a5bcd52017-11-18 22:19:55 +0100274/* Note that the start event is dispatched right away, so in case the FSM immediately concludes from that
275 * event, the created FSM struct may no longer be valid as it already deallocated again, and it may
276 * furthermore already have invoked the parent FSM instance's deallocation as well. Hence, instead of
277 * returning, store the created FSM instance address in *fi_p before dispatching the event. It is thus
278 * possible to store the instance's pointer in a parent FSM instance without running danger of using
279 * already freed memory. */
280void sub_pres_vlr_fsm_start(struct osmo_fsm_inst **fi_p,
281 struct osmo_fsm_inst *parent,
282 struct vlr_subscr *vsub,
283 uint32_t term_event)
Harald Welteb8b85a12016-06-17 00:06:42 +0200284{
285 struct osmo_fsm_inst *fi;
286
Neels Hofmeyr1a5bcd52017-11-18 22:19:55 +0100287 OSMO_ASSERT(fi_p);
288
Harald Welteb8b85a12016-06-17 00:06:42 +0200289 fi = osmo_fsm_inst_alloc_child(&sub_pres_vlr_fsm, parent,
290 term_event);
Neels Hofmeyr1a5bcd52017-11-18 22:19:55 +0100291 *fi_p = fi;
Harald Welteb8b85a12016-06-17 00:06:42 +0200292 if (!fi)
Neels Hofmeyr1a5bcd52017-11-18 22:19:55 +0100293 return;
Harald Welteb8b85a12016-06-17 00:06:42 +0200294
295 fi->priv = vsub;
296 osmo_fsm_inst_dispatch(fi, SUB_PRES_VLR_E_START, NULL);
Harald Welteb8b85a12016-06-17 00:06:42 +0200297}
298
299/***********************************************************************
300 * Location_Update_Completion_VLR, TS 23.012 Chapter 4.1.2.3
301 ***********************************************************************/
302
303enum lu_compl_vlr_state {
304 LU_COMPL_VLR_S_INIT,
305 LU_COMPL_VLR_S_WAIT_SUB_PRES,
306 LU_COMPL_VLR_S_WAIT_IMEI,
307 LU_COMPL_VLR_S_WAIT_IMEI_TMSI,
308 LU_COMPL_VLR_S_WAIT_TMSI_CNF,
309 LU_COMPL_VLR_S_DONE,
310};
311
312enum lu_compl_vlr_event {
313 LU_COMPL_VLR_E_START,
314 LU_COMPL_VLR_E_SUB_PRES_COMPL,
315 LU_COMPL_VLR_E_IMEI_CHECK_ACK,
316 LU_COMPL_VLR_E_IMEI_CHECK_NACK,
317 LU_COMPL_VLR_E_NEW_TMSI_ACK,
318};
319
320static const struct value_string lu_compl_vlr_event_names[] = {
321 OSMO_VALUE_STRING(LU_COMPL_VLR_E_START),
322 OSMO_VALUE_STRING(LU_COMPL_VLR_E_SUB_PRES_COMPL),
323 OSMO_VALUE_STRING(LU_COMPL_VLR_E_IMEI_CHECK_ACK),
324 OSMO_VALUE_STRING(LU_COMPL_VLR_E_IMEI_CHECK_NACK),
325 OSMO_VALUE_STRING(LU_COMPL_VLR_E_NEW_TMSI_ACK),
326 { 0, NULL }
327};
328
329struct lu_compl_vlr_priv {
330 struct vlr_subscr *vsub;
331 void *msc_conn_ref;
332 struct osmo_fsm_inst *sub_pres_vlr_fsm;
333 uint32_t parent_event_success;
334 uint32_t parent_event_failure;
335 void *parent_event_data;
336 enum vlr_fsm_result result;
337 uint8_t cause;
338 bool assign_tmsi;
339};
340
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100341static inline struct lu_compl_vlr_priv *lu_compl_vlr_fi_priv(struct osmo_fsm_inst *fi);
342
Harald Welteb8b85a12016-06-17 00:06:42 +0200343static void _vlr_lu_compl_fsm_done(struct osmo_fsm_inst *fi,
344 enum vlr_fsm_result result,
345 uint8_t cause)
346{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100347 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200348 lcvp->result = result;
349 lcvp->cause = cause;
350 osmo_fsm_inst_state_chg(fi, LU_COMPL_VLR_S_DONE, 0, 0);
351}
352
353static void vlr_lu_compl_fsm_success(struct osmo_fsm_inst *fi)
354{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100355 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200356 struct vlr_subscr *vsub = lcvp->vsub;
357 if (!vsub->lu_complete) {
358 vsub->lu_complete = true;
Stefan Sperlingdefc3c82018-05-15 14:48:04 +0200359 /* Balanced by vlr_subscr_expire() */
Harald Welteb8b85a12016-06-17 00:06:42 +0200360 vlr_subscr_get(vsub);
361 }
362 _vlr_lu_compl_fsm_done(fi, VLR_FSM_RESULT_SUCCESS, 0);
363}
364
365static void vlr_lu_compl_fsm_failure(struct osmo_fsm_inst *fi, uint8_t cause)
366{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100367 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200368 lcvp->vsub->vlr->ops.tx_lu_rej(lcvp->msc_conn_ref, cause);
369 _vlr_lu_compl_fsm_done(fi, VLR_FSM_RESULT_FAILURE, cause);
370}
371
372static void vlr_lu_compl_fsm_dispatch_result(struct osmo_fsm_inst *fi,
373 uint32_t prev_state)
374{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100375 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200376 if (!fi->proc.parent) {
377 LOGPFSML(fi, LOGL_ERROR, "No parent FSM\n");
378 return;
379 }
380 osmo_fsm_inst_dispatch(fi->proc.parent,
381 (lcvp->result == VLR_FSM_RESULT_SUCCESS)
382 ? lcvp->parent_event_success
383 : lcvp->parent_event_failure,
384 &lcvp->cause);
385}
386
387static void lu_compl_vlr_init(struct osmo_fsm_inst *fi, uint32_t event,
388 void *data)
389{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100390 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200391 struct vlr_subscr *vsub = lcvp->vsub;
392 struct vlr_instance *vlr;
393 OSMO_ASSERT(vsub);
394 vlr = vsub->vlr;
395 OSMO_ASSERT(vlr);
396
397 OSMO_ASSERT(event == LU_COMPL_VLR_E_START);
398
399 /* TODO: National Roaming restrictions? */
400 /* TODO: Roaming restriction due to unsupported feature in subscriber
401 * data? */
402 /* TODO: Regional subscription restriction? */
403 /* TODO: Administrative restriction of subscribres' access feature? */
404 /* TODO: AccessRestrictuionData parameter available? */
405 /* TODO: AccessRestrictionData permits RAT? */
406 /* Node 1 */
407 /* TODO: Autonomous CSG supported in VPLMN and allowed by HPLMN? */
408 /* TODO: Hybrid Cel / CSG Cell */
409 /* Node 2 */
410 vsub->la_allowed = true;
411 vsub->imsi_detached_flag = false;
412 /* Start Subscriber_Present_VLR Procedure */
413 osmo_fsm_inst_state_chg(fi, LU_COMPL_VLR_S_WAIT_SUB_PRES,
414 LU_TIMEOUT_LONG, 0);
415
Neels Hofmeyr1a5bcd52017-11-18 22:19:55 +0100416 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 +0200417}
418
419static void lu_compl_vlr_new_tmsi(struct osmo_fsm_inst *fi)
420{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100421 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200422 struct vlr_subscr *vsub = lcvp->vsub;
423 struct vlr_instance *vlr = vsub->vlr;
424
425 LOGPFSM(fi, "%s()\n", __func__);
426
427 if (vlr_subscr_alloc_tmsi(vsub)) {
428 vlr_lu_compl_fsm_failure(fi,
429 GSM48_REJECT_SRV_OPT_TMP_OUT_OF_ORDER);
430 return;
431 }
432
433 osmo_fsm_inst_state_chg(fi, LU_COMPL_VLR_S_WAIT_TMSI_CNF,
434 vlr_timer(vlr, 3250), 3250);
435
436 vlr->ops.tx_lu_acc(lcvp->msc_conn_ref, vsub->tmsi_new);
437}
438
439/* After completion of Subscriber_Present_VLR */
440static void lu_compl_vlr_wait_subscr_pres(struct osmo_fsm_inst *fi,
441 uint32_t event,
442 void *data)
443{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100444 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200445 struct vlr_subscr *vsub = lcvp->vsub;
446 struct vlr_instance *vlr = vsub->vlr;
447
448 OSMO_ASSERT(event == LU_COMPL_VLR_E_SUB_PRES_COMPL);
449
450 lcvp->sub_pres_vlr_fsm = NULL;
451
452 /* TODO: Trace_Subscriber_Activity_VLR */
453
454 if (vlr->cfg.check_imei_rqd) {
455 /* Check IMEI VLR */
456 osmo_fsm_inst_state_chg(fi,
457 lcvp->assign_tmsi ?
458 LU_COMPL_VLR_S_WAIT_IMEI_TMSI
459 : LU_COMPL_VLR_S_WAIT_IMEI,
460 vlr_timer(vlr, 3270), 3270);
461 vlr->ops.tx_id_req(lcvp->msc_conn_ref, GSM_MI_TYPE_IMEI);
462 return;
463 }
464
465 /* Do we need to allocate a TMSI? */
466 if (lcvp->assign_tmsi) {
467 lu_compl_vlr_new_tmsi(fi);
468 return;
469 }
470
471 /* Location Updating Accept */
472 vlr->ops.tx_lu_acc(lcvp->msc_conn_ref, GSM_RESERVED_TMSI);
473 vlr_lu_compl_fsm_success(fi);
474}
475
476/* Waiting for completion of CHECK_IMEI_VLR */
477static void lu_compl_vlr_wait_imei(struct osmo_fsm_inst *fi, uint32_t event,
478 void *data)
479{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100480 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200481 struct vlr_subscr *vsub = lcvp->vsub;
482 struct vlr_instance *vlr = vsub->vlr;
483
484 switch (event) {
485 case LU_COMPL_VLR_E_IMEI_CHECK_ACK:
486 if (!vsub->imei[0]) {
487 /* Abort: Do nothing */
488 vlr_lu_compl_fsm_failure(fi,
489 GSM48_REJECT_PROTOCOL_ERROR);
490 return;
491 }
492 /* Pass */
493 break;
494
495 case LU_COMPL_VLR_E_IMEI_CHECK_NACK:
496 vlr_lu_compl_fsm_failure(fi, GSM48_REJECT_ILLEGAL_ME);
497 /* FIXME: IMEI Check Fail to VLR Application (Detach IMSI VLR) */
498 return;
499 }
500
501 /* IMEI is available. Allocate TMSI if needed. */
502 if (lcvp->assign_tmsi) {
503 if (fi->state != LU_COMPL_VLR_S_WAIT_IMEI_TMSI)
504 LOGPFSML(fi, LOGL_ERROR,
505 "TMSI required, expected to be in state"
506 " LU_COMPL_VLR_S_WAIT_IMEI_TMSI,"
507 " am in %s instead\n",
508 osmo_fsm_state_name(fi->fsm, fi->state));
509 /* Logged an error, continue anyway. */
510
511 lu_compl_vlr_new_tmsi(fi);
512
513 /* Wait for TMSI ack */
514 return;
515 }
516
517 /* No TMSI needed, accept now. */
518 vlr->ops.tx_lu_acc(lcvp->msc_conn_ref, GSM_RESERVED_TMSI);
519 vlr_lu_compl_fsm_success(fi);
520}
521
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100522static inline struct lu_compl_vlr_priv *lu_compl_vlr_fi_priv(struct osmo_fsm_inst *fi);
523
Harald Welteb8b85a12016-06-17 00:06:42 +0200524/* Waiting for TMSI confirmation */
525static void lu_compl_vlr_wait_tmsi(struct osmo_fsm_inst *fi, uint32_t event,
526 void *data)
527{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100528 struct lu_compl_vlr_priv *lcvp = lu_compl_vlr_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200529 struct vlr_subscr *vsub = lcvp->vsub;
530
531 OSMO_ASSERT(event == LU_COMPL_VLR_E_NEW_TMSI_ACK);
532
533 if (!vsub || vsub->tmsi_new == GSM_RESERVED_TMSI) {
534 LOGPFSML(fi, LOGL_ERROR, "TMSI Realloc Compl implies that"
535 " the subscriber has a new TMSI allocated, but"
536 " the new TMSI is unset.\n");
537 vlr_lu_compl_fsm_failure(fi, GSM48_REJECT_NETWORK_FAILURE);
538 return;
539 }
540
541 vsub->tmsi = vsub->tmsi_new;
542 vsub->tmsi_new = GSM_RESERVED_TMSI;
543
544 vlr_lu_compl_fsm_success(fi);
545}
546
547static const struct osmo_fsm_state lu_compl_vlr_states[] = {
548 [LU_COMPL_VLR_S_INIT] = {
549 .in_event_mask = S(LU_COMPL_VLR_E_START),
550 .out_state_mask = S(LU_COMPL_VLR_S_DONE) |
551 S(LU_COMPL_VLR_S_WAIT_SUB_PRES) |
552 S(LU_COMPL_VLR_S_WAIT_IMEI),
553 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_INIT),
554 .action = lu_compl_vlr_init,
555 },
556 [LU_COMPL_VLR_S_WAIT_SUB_PRES] = {
557 .in_event_mask = S(LU_COMPL_VLR_E_SUB_PRES_COMPL),
558 .out_state_mask = S(LU_COMPL_VLR_S_WAIT_IMEI) |
559 S(LU_COMPL_VLR_S_WAIT_IMEI_TMSI) |
560 S(LU_COMPL_VLR_S_WAIT_TMSI_CNF) |
561 S(LU_COMPL_VLR_S_DONE),
562 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_SUB_PRES),
563 .action = lu_compl_vlr_wait_subscr_pres,
564 },
565 [LU_COMPL_VLR_S_WAIT_IMEI] = {
566 .in_event_mask = S(LU_COMPL_VLR_E_IMEI_CHECK_ACK) |
567 S(LU_COMPL_VLR_E_IMEI_CHECK_NACK),
568 .out_state_mask = S(LU_COMPL_VLR_S_DONE),
569 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_IMEI),
570 .action = lu_compl_vlr_wait_imei,
571 },
572 [LU_COMPL_VLR_S_WAIT_IMEI_TMSI] = {
573 .in_event_mask = S(LU_COMPL_VLR_E_IMEI_CHECK_ACK) |
574 S(LU_COMPL_VLR_E_IMEI_CHECK_NACK),
575 .out_state_mask = S(LU_COMPL_VLR_S_DONE) |
576 S(LU_COMPL_VLR_S_WAIT_TMSI_CNF),
577 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_IMEI_TMSI),
578 .action = lu_compl_vlr_wait_imei,
579 },
580 [LU_COMPL_VLR_S_WAIT_TMSI_CNF] = {
581 .in_event_mask = S(LU_COMPL_VLR_E_NEW_TMSI_ACK),
582 .out_state_mask = S(LU_COMPL_VLR_S_DONE),
583 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_WAIT_TMSI_CNF),
584 .action = lu_compl_vlr_wait_tmsi,
585 },
586 [LU_COMPL_VLR_S_DONE] = {
587 .name = OSMO_STRINGIFY(LU_COMPL_VLR_S_DONE),
588 .onenter = vlr_lu_compl_fsm_dispatch_result,
589 },
590};
591
592static struct osmo_fsm lu_compl_vlr_fsm = {
593 .name = "lu_compl_vlr_fsm",
594 .states = lu_compl_vlr_states,
595 .num_states = ARRAY_SIZE(lu_compl_vlr_states),
596 .allstate_event_mask = 0,
597 .allstate_action = NULL,
598 .log_subsys = DVLR,
599 .event_names = lu_compl_vlr_event_names,
600};
601
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100602static inline struct lu_compl_vlr_priv *lu_compl_vlr_fi_priv(struct osmo_fsm_inst *fi)
603{
604 OSMO_ASSERT(fi->fsm == &lu_compl_vlr_fsm);
605 return (struct lu_compl_vlr_priv*)fi->priv;
606}
607
Harald Welteb8b85a12016-06-17 00:06:42 +0200608struct osmo_fsm_inst *
609lu_compl_vlr_proc_alloc(struct osmo_fsm_inst *parent,
610 struct vlr_subscr *vsub,
611 void *msc_conn_ref,
612 uint32_t parent_event_success,
613 uint32_t parent_event_failure,
614 bool assign_tmsi)
615{
616 struct osmo_fsm_inst *fi;
617 struct lu_compl_vlr_priv *lcvp;
618
619 fi = osmo_fsm_inst_alloc_child(&lu_compl_vlr_fsm, parent,
620 parent_event_failure);
621 if (!fi)
622 return NULL;
623
624 lcvp = talloc_zero(fi, struct lu_compl_vlr_priv);
625 lcvp->vsub = vsub;
626 lcvp->msc_conn_ref = msc_conn_ref;
627 lcvp->parent_event_success = parent_event_success;
628 lcvp->parent_event_failure = parent_event_failure;
629 lcvp->assign_tmsi = assign_tmsi;
630 fi->priv = lcvp;
631
632 return fi;
633}
634
635
636/***********************************************************************
637 * Update_Location_Area_VLR, TS 23.012 Chapter 4.1.2.1
638 ***********************************************************************/
639
640static const struct value_string fsm_lu_event_names[] = {
641 OSMO_VALUE_STRING(VLR_ULA_E_UPDATE_LA),
642 OSMO_VALUE_STRING(VLR_ULA_E_SEND_ID_ACK),
643 OSMO_VALUE_STRING(VLR_ULA_E_SEND_ID_NACK),
644 OSMO_VALUE_STRING(VLR_ULA_E_AUTH_RES),
645 OSMO_VALUE_STRING(VLR_ULA_E_CIPH_RES),
646 OSMO_VALUE_STRING(VLR_ULA_E_ID_IMSI),
647 OSMO_VALUE_STRING(VLR_ULA_E_ID_IMEI),
648 OSMO_VALUE_STRING(VLR_ULA_E_ID_IMEISV),
649 OSMO_VALUE_STRING(VLR_ULA_E_HLR_LU_RES),
650 OSMO_VALUE_STRING(VLR_ULA_E_UPD_HLR_COMPL),
651 OSMO_VALUE_STRING(VLR_ULA_E_LU_COMPL_SUCCESS),
652 OSMO_VALUE_STRING(VLR_ULA_E_LU_COMPL_FAILURE),
653 OSMO_VALUE_STRING(VLR_ULA_E_NEW_TMSI_ACK),
654 { 0, NULL }
655};
656
657struct lu_fsm_priv {
658 struct vlr_instance *vlr;
659 struct vlr_subscr *vsub;
660 void *msc_conn_ref;
661 struct osmo_fsm_inst *upd_hlr_vlr_fsm;
662 struct osmo_fsm_inst *lu_compl_vlr_fsm;
663 uint32_t parent_event_success;
664 uint32_t parent_event_failure;
665 void *parent_event_data;
666 enum vlr_fsm_result result;
667 uint8_t rej_cause;
668
669 enum vlr_lu_type type;
670 bool lu_by_tmsi;
671 char imsi[16];
672 uint32_t tmsi;
673 struct osmo_location_area_id old_lai;
674 struct osmo_location_area_id new_lai;
675 bool authentication_required;
Harald Welte71c51df2017-12-23 18:51:48 +0100676 bool ciphering_required;
Harald Welteb8b85a12016-06-17 00:06:42 +0200677 bool is_r99;
678 bool is_utran;
679 bool assign_tmsi;
680};
681
682
683/* Determine if given location area is served by this VLR */
684static bool lai_in_this_vlr(struct vlr_instance *vlr,
685 const struct osmo_location_area_id *lai)
686{
687 /* TODO: VLR needs to keep a locally configued list of LAIs */
688 return true;
689}
690
691/* Determine if authentication is required */
692static bool is_auth_required(struct lu_fsm_priv *lfp)
693{
694 /* The cases where the authentication procedure should be used
695 * are defined in 3GPP TS 33.102 */
696 /* For now we use a default value passed in to vlr_lu_fsm(). */
Harald Welte71c51df2017-12-23 18:51:48 +0100697 return lfp->authentication_required || lfp->ciphering_required;
Harald Welteb8b85a12016-06-17 00:06:42 +0200698}
699
700/* Determine if ciphering is required */
701static bool is_ciph_required(struct lu_fsm_priv *lfp)
702{
Harald Welte71c51df2017-12-23 18:51:48 +0100703 return lfp->ciphering_required;
Harald Welteb8b85a12016-06-17 00:06:42 +0200704}
705
706/* Determine if a HLR Update is required */
707static bool hlr_update_needed(struct vlr_subscr *vsub)
708{
709 /* TODO: properly decide this, rather than always assuming we
710 * need to update the HLR. */
711 return true;
712}
713
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100714static inline struct lu_fsm_priv *lu_fsm_fi_priv(struct osmo_fsm_inst *fi);
715
Harald Welteb8b85a12016-06-17 00:06:42 +0200716static void lu_fsm_dispatch_result(struct osmo_fsm_inst *fi,
717 uint32_t prev_state)
718{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100719 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200720 if (!fi->proc.parent) {
721 LOGPFSML(fi, LOGL_ERROR, "No parent FSM\n");
722 return;
723 }
724 osmo_fsm_inst_dispatch(fi->proc.parent,
725 (lfp->result == VLR_FSM_RESULT_SUCCESS)
726 ? lfp->parent_event_success
727 : lfp->parent_event_failure,
728 lfp->parent_event_data);
729}
730
731static void _lu_fsm_done(struct osmo_fsm_inst *fi,
732 enum vlr_fsm_result result)
733{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100734 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200735 lfp->result = result;
736 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_DONE, 0, 0);
737}
738
739static void lu_fsm_success(struct osmo_fsm_inst *fi)
740{
741 _lu_fsm_done(fi, VLR_FSM_RESULT_SUCCESS);
742}
743
Neels Hofmeyr15809592018-04-06 02:57:51 +0200744static void lu_fsm_failure(struct osmo_fsm_inst *fi, enum gsm48_reject_value rej_cause)
Harald Welteb8b85a12016-06-17 00:06:42 +0200745{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100746 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Neels Hofmeyr15809592018-04-06 02:57:51 +0200747 lfp->vlr->ops.tx_lu_rej(lfp->msc_conn_ref, rej_cause ? : GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200748 _lu_fsm_done(fi, VLR_FSM_RESULT_FAILURE);
749}
750
751static void vlr_loc_upd_start_lu_compl_fsm(struct osmo_fsm_inst *fi)
752{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100753 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200754 lfp->lu_compl_vlr_fsm =
755 lu_compl_vlr_proc_alloc(fi, lfp->vsub, lfp->msc_conn_ref,
756 VLR_ULA_E_LU_COMPL_SUCCESS,
757 VLR_ULA_E_LU_COMPL_FAILURE,
758 lfp->assign_tmsi);
759
760 osmo_fsm_inst_dispatch(lfp->lu_compl_vlr_fsm, LU_COMPL_VLR_E_START, NULL);
761}
762
763static void lu_fsm_discard_lu_compl_fsm(struct osmo_fsm_inst *fi)
764{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100765 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200766 if (!lfp->lu_compl_vlr_fsm)
767 return;
768 osmo_fsm_inst_term(lfp->lu_compl_vlr_fsm, OSMO_FSM_TERM_PARENT, NULL);
769}
770
771/* 4.1.2.1 Node 4 */
772static void vlr_loc_upd_node_4(struct osmo_fsm_inst *fi)
773{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100774 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200775 struct vlr_subscr *vsub = lfp->vsub;
776 bool hlr_unknown = false;
777
778 LOGPFSM(fi, "%s()\n", __func__);
779
780 if (hlr_unknown) {
781 /* FIXME: Delete subscriber record */
782 /* LU REJ: Roaming not allowed */
783 lu_fsm_failure(fi, GSM48_REJECT_ROAMING_NOT_ALLOWED);
784 } else {
785 /* Update_HLR_VLR */
786 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_HLR_UPD,
787 LU_TIMEOUT_LONG, 0);
788 lfp->upd_hlr_vlr_fsm =
789 upd_hlr_vlr_proc_start(fi, vsub, VLR_ULA_E_UPD_HLR_COMPL);
790 }
791}
792
793/* 4.1.2.1 Node B */
794static void vlr_loc_upd_node_b(struct osmo_fsm_inst *fi)
795{
796 LOGPFSM(fi, "%s()\n", __func__);
797
Neels Hofmeyref9126c2017-07-18 15:38:39 +0200798 /* OsmoHLR does not support PgA, neither stores the IMEISV, so we have no need to update the HLR
799 * with either. TODO: depend on actual HLR configuration. See 3GPP TS 23.012 Release 14, process
800 * Update_Location_Area_VLR (ULA_VLR2). */
Harald Welteb8b85a12016-06-17 00:06:42 +0200801 if (0) { /* IMEISV or PgA to send */
802 vlr_loc_upd_node_4(fi);
803 } else {
804 /* Location_Update_Completion */
805 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_LU_COMPL,
806 LU_TIMEOUT_LONG, 0);
807 vlr_loc_upd_start_lu_compl_fsm(fi);
808 }
809}
810
811/* Non-standard: after Ciphering Mode Complete (or no ciph required) */
812static void vlr_loc_upd_post_ciph(struct osmo_fsm_inst *fi)
813{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100814 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200815 struct vlr_subscr *vsub = lfp->vsub;
816
817 LOGPFSM(fi, "%s()\n", __func__);
818
819 OSMO_ASSERT(vsub);
820
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200821 if (lfp->is_utran) {
822 int rc;
823 rc = lfp->vlr->ops.tx_common_id(lfp->msc_conn_ref);
824 if (rc)
825 LOGPFSML(fi, LOGL_ERROR,
826 "Error while sending Common ID (%d)\n", rc);
827 }
828
Harald Welteb8b85a12016-06-17 00:06:42 +0200829 vsub->conf_by_radio_contact_ind = true;
830 /* Update LAI */
831 vsub->cgi.lai = lfp->new_lai;
832 vsub->dormant_ind = false;
833 vsub->cancel_loc_rx = false;
834 if (hlr_update_needed(vsub)) {
835 vlr_loc_upd_node_4(fi);
836 } else {
837 /* TODO: ADD Support */
838 /* TODO: Node A: PgA Support */
839 vlr_loc_upd_node_b(fi);
840 }
841}
842
843/* 4.1.2.1 after Authentication successful (or no auth rqd) */
844static void vlr_loc_upd_post_auth(struct osmo_fsm_inst *fi)
845{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100846 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200847 struct vlr_subscr *vsub = lfp->vsub;
Neels Hofmeyr7795a192018-03-10 00:26:36 +0100848 bool umts_aka;
Harald Welteb8b85a12016-06-17 00:06:42 +0200849
850 LOGPFSM(fi, "%s()\n", __func__);
851
852 OSMO_ASSERT(vsub);
853
854 if (!is_ciph_required(lfp)) {
855 vlr_loc_upd_post_ciph(fi);
856 return;
857 }
858
Neels Hofmeyr2ef2da52017-12-18 01:23:42 +0100859 if (!vsub->last_tuple) {
860 LOGPFSML(fi, LOGL_ERROR, "No auth tuple available\n");
Neels Hofmeyrd2278ec2018-03-02 02:44:05 +0100861 lu_fsm_failure(fi, GSM48_REJECT_NETWORK_FAILURE);
Neels Hofmeyr2ef2da52017-12-18 01:23:42 +0100862 return;
863 }
864
Neels Hofmeyr7795a192018-03-10 00:26:36 +0100865 switch (vsub->sec_ctx) {
866 case VLR_SEC_CTX_GSM:
867 umts_aka = false;
868 break;
869 case VLR_SEC_CTX_UMTS:
870 umts_aka = true;
871 break;
872 default:
873 LOGPFSML(fi, LOGL_ERROR, "Cannot start ciphering, security context is not established\n");
874 lu_fsm_failure(fi, GSM48_REJECT_NETWORK_FAILURE);
875 return;
876 }
877
Harald Welteb8b85a12016-06-17 00:06:42 +0200878 if (vlr_set_ciph_mode(vsub->vlr, fi, lfp->msc_conn_ref,
879 lfp->ciphering_required,
Neels Hofmeyr7795a192018-03-10 00:26:36 +0100880 umts_aka,
Neels Hofmeyr54a706c2017-07-18 15:39:27 +0200881 vsub->vlr->cfg.retrieve_imeisv_ciphered)) {
Harald Welteb8b85a12016-06-17 00:06:42 +0200882 LOGPFSML(fi, LOGL_ERROR,
883 "Failed to send Ciphering Mode Command\n");
Neels Hofmeyrd2278ec2018-03-02 02:44:05 +0100884 lu_fsm_failure(fi, GSM48_REJECT_NETWORK_FAILURE);
Harald Welteb8b85a12016-06-17 00:06:42 +0200885 return;
886 }
887
888 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_CIPH, LU_TIMEOUT_LONG, 0);
889}
890
891static void vlr_loc_upd_node1(struct osmo_fsm_inst *fi)
892{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100893 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200894 struct vlr_subscr *vsub = lfp->vsub;
895
896 LOGPFSM(fi, "%s()\n", __func__);
897
898 OSMO_ASSERT(vsub);
899
900 if (is_auth_required(lfp)) {
901 /* Authenticate_VLR */
902 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_AUTH,
903 LU_TIMEOUT_LONG, 0);
904 vsub->auth_fsm = auth_fsm_start(lfp->vsub, fi->log_level,
905 fi, VLR_ULA_E_AUTH_RES,
906 lfp->is_r99,
907 lfp->is_utran);
908 } else {
909 /* no need for authentication */
910 vlr_loc_upd_post_auth(fi);
911 }
912}
913
914static void vlr_loc_upd_want_imsi(struct osmo_fsm_inst *fi)
915{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100916 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200917 struct vlr_instance *vlr = lfp->vlr;
918
919 LOGPFSM(fi, "%s()\n", __func__);
920
921 OSMO_ASSERT(lfp->vsub);
922
923 /* Obtain_IMSI_VLR */
924 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_IMSI,
925 vlr_timer(vlr, 3270), 3270);
926 vlr->ops.tx_id_req(lfp->msc_conn_ref, GSM_MI_TYPE_IMSI);
927 /* will continue at vlr_loc_upd_node1() once IMSI arrives */
928}
929
930static int assoc_lfp_with_sub(struct osmo_fsm_inst *fi, struct vlr_subscr *vsub)
931{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100932 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +0200933 struct vlr_instance *vlr = lfp->vlr;
934
935 if (vsub->lu_fsm) {
936 LOGPFSML(fi, LOGL_ERROR,
937 "A Location Updating process is already pending for"
938 " this subscriber. Aborting.\n");
939 /* Also get rid of the other pending LU attempt? */
940 /*lu_fsm_failure(vsub->lu_fsm, GSM48_REJECT_CONGESTION);*/
941 lu_fsm_failure(fi, GSM48_REJECT_CONGESTION);
942 return -EINVAL;
943 }
944 vsub->lu_fsm = fi;
945 vsub->msc_conn_ref = lfp->msc_conn_ref;
946 /* FIXME: send new LAC to HLR? */
947 vsub->lac = lfp->new_lai.lac;
948 lfp->vsub = vsub;
949 /* Tell MSC to associate this subscriber with the given
950 * connection */
951 vlr->ops.subscr_assoc(lfp->msc_conn_ref, lfp->vsub);
952 return 0;
953}
954
Neels Hofmeyr54a706c2017-07-18 15:39:27 +0200955static int _lu_fsm_associate_vsub(struct osmo_fsm_inst *fi)
956{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +0100957 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Neels Hofmeyr54a706c2017-07-18 15:39:27 +0200958 struct vlr_instance *vlr = lfp->vlr;
959 struct vlr_subscr *vsub = NULL;
960
961 if (!lfp->imsi[0]) {
962 /* TMSI was used */
963 lfp->lu_by_tmsi = true;
964 /* TMSI clash: if a different subscriber already has this TMSI,
965 * we will find that other subscriber in the VLR. So the IMSIs
966 * would mismatch, but we don't know about it. Theoretically,
967 * an authentication process would thwart any attempt to use
968 * someone else's TMSI.
969 * TODO: Otherwise we can ask for the IMSI and verify that it
970 * matches the IMSI on record. */
971 vsub = vlr_subscr_find_or_create_by_tmsi(vlr, lfp->tmsi, NULL);
972
973 if (!vsub) {
974 LOGPFSML(fi, LOGL_ERROR, "VLR subscriber allocation failed\n");
975 lu_fsm_failure(fi, GSM48_REJECT_SRV_OPT_TMP_OUT_OF_ORDER);
976 return -1;
977 }
978
979 vsub->sub_dataconf_by_hlr_ind = false;
980 if (assoc_lfp_with_sub(fi, vsub)) {
981 vlr_subscr_put(vsub);
982 return -1; /* error, fsm failure invoked in assoc_lfp_with_sub() */
983 }
984 vlr_subscr_put(vsub);
985 } else {
986 /* IMSI was used */
987 vsub = vlr_subscr_find_or_create_by_imsi(vlr, lfp->imsi, NULL);
988
989 if (!vsub) {
990 LOGPFSML(fi, LOGL_ERROR, "VLR subscriber allocation failed\n");
991 lu_fsm_failure(fi, GSM48_REJECT_SRV_OPT_TMP_OUT_OF_ORDER);
992 vlr_subscr_put(vsub);
993 return -1;
994 }
995
996 vsub->sub_dataconf_by_hlr_ind = false;
997 if (assoc_lfp_with_sub(fi, vsub)) {
998 vlr_subscr_put(vsub);
999 return -1; /* error, fsm failure invoked in assoc_lfp_with_sub() */
1000 }
1001 vlr_subscr_put(vsub);
1002 }
1003 return 0;
1004}
1005
Harald Welteb8b85a12016-06-17 00:06:42 +02001006/* 4.1.2.1: Subscriber (via MSC/SGSN) requests location update */
1007static void _start_lu_main(struct osmo_fsm_inst *fi)
1008{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001009 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001010 struct vlr_instance *vlr = lfp->vlr;
Harald Welteb8b85a12016-06-17 00:06:42 +02001011
1012 /* TODO: PUESBINE related handling */
1013
1014 /* Is previous LAI in this VLR? */
1015 if (!lai_in_this_vlr(vlr, &lfp->old_lai)) {
1016#if 0
1017 /* FIXME: check previous VLR, (3) */
1018 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_PVLR,
1019 LU_TIMEOUT_LONG, 0);
1020 return;
1021#endif
1022 LOGPFSML(fi, LOGL_NOTICE, "LAI change from %s,"
1023 " but checking previous VLR not implemented\n",
Neels Hofmeyr379d5792018-02-22 04:04:54 +01001024 osmo_lai_name(&lfp->old_lai));
Harald Welteb8b85a12016-06-17 00:06:42 +02001025 }
1026
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001027 /* If this is a TMSI based LU, we may not have the IMSI. Make sure that
1028 * we know the IMSI, either on record, or request it. */
1029 if (!lfp->vsub->imsi[0])
1030 vlr_loc_upd_want_imsi(fi);
1031 else
Harald Welteb8b85a12016-06-17 00:06:42 +02001032 vlr_loc_upd_node1(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001033}
1034
Harald Welteb8b85a12016-06-17 00:06:42 +02001035static void lu_fsm_idle(struct osmo_fsm_inst *fi, uint32_t event,
1036 void *data)
1037{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001038 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001039 struct vlr_instance *vlr = lfp->vlr;
1040
1041 OSMO_ASSERT(event == VLR_ULA_E_UPDATE_LA);
1042
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001043 if (_lu_fsm_associate_vsub(fi))
1044 return; /* error. FSM already terminated. */
1045
1046 OSMO_ASSERT(lfp->vsub);
1047
1048 /* See 3GPP TS 23.012, procedure Retrieve_IMEISV_If_Required */
1049 if ((!vlr->cfg.retrieve_imeisv_early)
1050 || (lfp->type == VLR_LU_TYPE_PERIODIC && lfp->vsub->imeisv[0])) {
Harald Welteb8b85a12016-06-17 00:06:42 +02001051 /* R_IMEISV_IR1 passed */
1052 _start_lu_main(fi);
1053 } else {
1054 vlr->ops.tx_id_req(lfp->msc_conn_ref, GSM_MI_TYPE_IMEISV);
1055 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_IMEISV,
1056 vlr_timer(vlr, 3270), 3270);
1057 }
1058}
1059
1060static void lu_fsm_wait_imeisv(struct osmo_fsm_inst *fi, uint32_t event,
1061 void *data)
1062{
1063 switch (event) {
1064 case VLR_ULA_E_ID_IMEISV:
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001065 /* IMEISV was copied in vlr_subscr_rx_id_resp(), and that's
1066 * where we received this event from. */
Harald Welteb8b85a12016-06-17 00:06:42 +02001067 _start_lu_main(fi);
1068 break;
1069 default:
1070 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1071 osmo_fsm_event_name(fi->fsm, event));
1072 break;
1073 }
1074}
1075
1076/* Wait for response from Send_Identification to PVLR */
1077static void lu_fsm_wait_pvlr(struct osmo_fsm_inst *fi, uint32_t event,
1078 void *data)
1079{
1080 switch (event) {
1081 case VLR_ULA_E_SEND_ID_ACK:
1082 vlr_loc_upd_node1(fi);
1083 break;
1084 case VLR_ULA_E_SEND_ID_NACK:
1085 vlr_loc_upd_want_imsi(fi);
1086 break;
1087 default:
1088 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1089 osmo_fsm_event_name(fi->fsm, event));
1090 break;
1091 }
1092}
1093
1094/* Wait for result of Authenticate_VLR procedure */
1095static void lu_fsm_wait_auth(struct osmo_fsm_inst *fi, uint32_t event,
1096 void *data)
1097{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001098 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Neels Hofmeyr15809592018-04-06 02:57:51 +02001099 enum gsm48_reject_value *res = data;
Harald Welteb8b85a12016-06-17 00:06:42 +02001100
1101 OSMO_ASSERT(event == VLR_ULA_E_AUTH_RES);
1102
1103 lfp->upd_hlr_vlr_fsm = NULL;
1104
Neels Hofmeyr15809592018-04-06 02:57:51 +02001105 if (!res || *res) {
1106 lu_fsm_failure(fi, res? *res : GSM48_REJECT_NETWORK_FAILURE);
1107 return;
1108 }
Harald Welteb8b85a12016-06-17 00:06:42 +02001109
Neels Hofmeyr15809592018-04-06 02:57:51 +02001110 /* Result == Pass */
1111 vlr_loc_upd_post_auth(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001112}
1113
1114static void lu_fsm_wait_ciph(struct osmo_fsm_inst *fi, uint32_t event,
1115 void *data)
1116{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001117 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001118 struct vlr_subscr *vsub = lfp->vsub;
1119 struct vlr_ciph_result res = { .cause = VLR_CIPH_REJECT };
1120
1121 OSMO_ASSERT(event == VLR_ULA_E_CIPH_RES);
1122
1123 if (!data)
1124 LOGPFSML(fi, LOGL_ERROR, "invalid ciphering result: NULL\n");
1125 else
1126 res = *(struct vlr_ciph_result*)data;
1127
1128 switch (res.cause) {
1129 case VLR_CIPH_COMPL:
1130 break;
1131 case VLR_CIPH_REJECT:
1132 LOGPFSM(fi, "ciphering rejected\n");
1133 lu_fsm_failure(fi, GSM48_REJECT_INVALID_MANDANTORY_INF);
1134 return;
1135 default:
1136 LOGPFSML(fi, LOGL_ERROR, "invalid ciphering result: %d\n",
1137 res.cause);
1138 lu_fsm_failure(fi, GSM48_REJECT_INVALID_MANDANTORY_INF);
1139 return;
1140 }
1141
Neels Hofmeyrfa10eda2018-03-13 01:22:01 +01001142 if (*res.imeisv) {
Harald Welteb8b85a12016-06-17 00:06:42 +02001143 LOGPFSM(fi, "got IMEISV: %s\n", res.imeisv);
1144 vlr_subscr_set_imeisv(vsub, res.imeisv);
1145 }
1146 vlr_loc_upd_post_ciph(fi);
1147}
1148
1149static void lu_fsm_wait_imsi(struct osmo_fsm_inst *fi, uint32_t event,
1150 void *data)
1151{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001152 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001153 struct vlr_subscr *vsub = lfp->vsub;
1154 char *mi_string = data;
1155
1156 switch (event) {
1157 case VLR_ULA_E_ID_IMSI:
1158 vlr_subscr_set_imsi(vsub, mi_string);
1159 vlr_loc_upd_node1(fi);
1160 break;
1161 default:
1162 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1163 osmo_fsm_event_name(fi->fsm, event));
1164 break;
1165 }
1166}
1167
1168/* At the end of Update_HLR_VLR */
1169static void lu_fsm_wait_hlr_ul_res(struct osmo_fsm_inst *fi, uint32_t event,
1170 void *data)
1171{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001172 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001173
1174 switch (event) {
1175 case VLR_ULA_E_HLR_LU_RES:
1176 /* pass-through this event to Update_HLR_VLR */
1177 if (data == NULL)
1178 osmo_fsm_inst_dispatch(lfp->upd_hlr_vlr_fsm, UPD_HLR_VLR_E_UPD_LOC_ACK, NULL);
1179 else
1180 osmo_fsm_inst_dispatch(lfp->upd_hlr_vlr_fsm, UPD_HLR_VLR_E_UPD_LOC_NACK, data);
1181 break;
1182 case VLR_ULA_E_UPD_HLR_COMPL:
1183 if (data == NULL) {
1184 /* successful case */
1185 osmo_fsm_inst_state_chg(fi, VLR_ULA_S_WAIT_LU_COMPL,
1186 LU_TIMEOUT_LONG, 0);
1187 vlr_loc_upd_start_lu_compl_fsm(fi);
1188 /* continue in MSC ?!? */
1189 } else {
1190 /* unsuccessful case */
Neels Hofmeyrdd2aeba2018-10-30 19:47:01 +01001191 enum gsm48_reject_value cause =
1192 *(enum gsm48_reject_value *)data;
Neels Hofmeyref9126c2017-07-18 15:38:39 +02001193 /* Ignoring standalone mode for now. */
Harald Welteb8b85a12016-06-17 00:06:42 +02001194 if (0 /* procedure_error && vlr->cfg.standalone_mode */) {
1195 osmo_fsm_inst_state_chg(fi,
1196 VLR_ULA_S_WAIT_LU_COMPL_STANDALONE,
1197 LU_TIMEOUT_LONG, 0);
1198 vlr_loc_upd_start_lu_compl_fsm(fi);
1199 } else {
1200 lu_fsm_failure(fi, cause);
1201 }
1202 }
1203 break;
1204 default:
1205 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1206 osmo_fsm_event_name(fi->fsm, event));
1207 break;
1208 }
1209}
1210
1211/* Wait for end of Location_Update_Completion_VLR */
1212static void lu_fsm_wait_lu_compl(struct osmo_fsm_inst *fi, uint32_t event,
1213 void *data)
1214{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001215 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001216 uint8_t cause;
1217
1218 switch (event) {
1219 case VLR_ULA_E_NEW_TMSI_ACK:
1220 osmo_fsm_inst_dispatch(lfp->lu_compl_vlr_fsm,
1221 LU_COMPL_VLR_E_NEW_TMSI_ACK, NULL);
1222 break;
1223 case VLR_ULA_E_ID_IMEI:
1224 osmo_fsm_inst_dispatch(lfp->lu_compl_vlr_fsm,
1225 LU_COMPL_VLR_E_IMEI_CHECK_ACK, NULL);
1226 break;
1227 case VLR_ULA_E_LU_COMPL_SUCCESS:
1228 lu_fsm_discard_lu_compl_fsm(fi);
1229
1230 /* Update Register */
1231 /* TODO: Set_Notification_Type 23.078 */
1232 /* TODO: Notify_gsmSCF 23.078 */
1233 /* TODO: Authenticated Radio Contact Established -> ARC */
Stefan Sperling3a741282018-03-13 21:11:49 +01001234
1235 if (lfp->type == VLR_LU_TYPE_IMSI_ATTACH)
1236 lfp->vlr->ops.tx_mm_info(lfp->msc_conn_ref);
1237
Harald Welteb8b85a12016-06-17 00:06:42 +02001238 lu_fsm_success(fi);
1239 break;
1240 case VLR_ULA_E_LU_COMPL_FAILURE:
1241 cause = GSM48_REJECT_NETWORK_FAILURE;
1242 if (data)
1243 cause = *(uint8_t*)data;
1244 lu_fsm_discard_lu_compl_fsm(fi);
1245 lu_fsm_failure(fi, cause);
1246 break;
1247 default:
1248 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1249 osmo_fsm_event_name(fi->fsm, event));
1250 break;
1251 }
1252}
1253
1254/* Wait for end of Location_Update_Completion_VLR (standalone case) */
1255static void lu_fsm_wait_lu_compl_standalone(struct osmo_fsm_inst *fi,
1256 uint32_t event, void *data)
1257{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001258 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001259 struct vlr_subscr *vsub = lfp->vsub;
1260 uint8_t cause;
1261
1262 switch (event) {
1263 case VLR_ULA_E_NEW_TMSI_ACK:
1264 osmo_fsm_inst_dispatch(lfp->lu_compl_vlr_fsm,
1265 LU_COMPL_VLR_E_NEW_TMSI_ACK, NULL);
1266 break;
1267 case VLR_ULA_E_LU_COMPL_SUCCESS:
1268 lu_fsm_discard_lu_compl_fsm(fi);
1269 vsub->sub_dataconf_by_hlr_ind = false;
1270 lu_fsm_success(fi);
1271 break;
1272 case VLR_ULA_E_LU_COMPL_FAILURE:
1273 vsub->sub_dataconf_by_hlr_ind = false;
1274 cause = GSM48_REJECT_NETWORK_FAILURE;
1275 if (data)
1276 cause = *(uint8_t*)data;
1277 lu_fsm_discard_lu_compl_fsm(fi);
1278 lu_fsm_failure(fi, cause);
1279 break;
1280 default:
1281 LOGPFSML(fi, LOGL_ERROR, "event without effect: %s\n",
1282 osmo_fsm_event_name(fi->fsm, event));
1283 break;
1284 }
1285}
1286
1287static const struct osmo_fsm_state vlr_lu_fsm_states[] = {
1288 [VLR_ULA_S_IDLE] = {
1289 .in_event_mask = S(VLR_ULA_E_UPDATE_LA),
1290 .out_state_mask = S(VLR_ULA_S_WAIT_IMEISV) |
1291 S(VLR_ULA_S_WAIT_PVLR) |
1292 S(VLR_ULA_S_WAIT_IMSI) |
1293 S(VLR_ULA_S_WAIT_AUTH) |
1294 S(VLR_ULA_S_WAIT_HLR_UPD) |
1295 S(VLR_ULA_S_DONE),
1296 .name = OSMO_STRINGIFY(VLR_ULA_S_IDLE),
1297 .action = lu_fsm_idle,
1298 },
1299 [VLR_ULA_S_WAIT_IMEISV] = {
1300 .in_event_mask = S(VLR_ULA_E_ID_IMEISV),
1301 .out_state_mask = S(VLR_ULA_S_WAIT_PVLR) |
1302 S(VLR_ULA_S_WAIT_IMSI) |
Neels Hofmeyr54a706c2017-07-18 15:39:27 +02001303 S(VLR_ULA_S_WAIT_AUTH) |
1304 S(VLR_ULA_S_WAIT_HLR_UPD) |
Harald Welteb8b85a12016-06-17 00:06:42 +02001305 S(VLR_ULA_S_DONE),
1306 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_IMEISV),
1307 .action = lu_fsm_wait_imeisv,
1308 },
1309 [VLR_ULA_S_WAIT_PVLR] = {
1310 .in_event_mask = S(VLR_ULA_E_SEND_ID_ACK) |
1311 S(VLR_ULA_E_SEND_ID_NACK),
1312 .out_state_mask = S(VLR_ULA_S_WAIT_IMSI) |
1313 S(VLR_ULA_S_WAIT_AUTH) |
1314 S(VLR_ULA_S_DONE),
1315 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_PVLR),
1316 .action = lu_fsm_wait_pvlr,
1317 },
1318 [VLR_ULA_S_WAIT_AUTH] = {
1319 .in_event_mask = S(VLR_ULA_E_AUTH_RES),
1320 .out_state_mask = S(VLR_ULA_S_WAIT_CIPH) |
1321 S(VLR_ULA_S_WAIT_LU_COMPL) |
1322 S(VLR_ULA_S_WAIT_HLR_UPD) |
1323 S(VLR_ULA_S_DONE),
1324 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_AUTH),
1325 .action = lu_fsm_wait_auth,
1326 },
1327 [VLR_ULA_S_WAIT_CIPH] = {
1328 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_CIPH),
1329 .in_event_mask = S(VLR_ULA_E_CIPH_RES),
1330 .out_state_mask = S(VLR_ULA_S_WAIT_LU_COMPL) |
1331 S(VLR_ULA_S_WAIT_HLR_UPD) |
1332 S(VLR_ULA_S_DONE),
1333 .action = lu_fsm_wait_ciph,
1334 },
1335 [VLR_ULA_S_WAIT_IMSI] = {
1336 .in_event_mask = S(VLR_ULA_E_ID_IMSI),
1337 .out_state_mask = S(VLR_ULA_S_WAIT_AUTH) |
1338 S(VLR_ULA_S_WAIT_HLR_UPD) |
1339 S(VLR_ULA_S_DONE),
1340 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_IMSI),
1341 .action = lu_fsm_wait_imsi,
1342 },
1343 [VLR_ULA_S_WAIT_HLR_UPD] = {
1344 .in_event_mask = S(VLR_ULA_E_HLR_LU_RES) |
1345 S(VLR_ULA_E_UPD_HLR_COMPL),
1346 .out_state_mask = S(VLR_ULA_S_WAIT_LU_COMPL) |
1347 S(VLR_ULA_S_WAIT_LU_COMPL_STANDALONE) |
1348 S(VLR_ULA_S_DONE),
1349 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_HLR_UPD),
1350 .action = lu_fsm_wait_hlr_ul_res,
1351 },
1352 [VLR_ULA_S_WAIT_LU_COMPL] = {
1353 .in_event_mask = S(VLR_ULA_E_LU_COMPL_SUCCESS) |
1354 S(VLR_ULA_E_LU_COMPL_FAILURE) |
1355 S(VLR_ULA_E_NEW_TMSI_ACK) |
1356 S(VLR_ULA_E_ID_IMEI) |
1357 S(VLR_ULA_E_ID_IMEISV),
1358 .out_state_mask = S(VLR_ULA_S_DONE),
1359 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_LU_COMPL),
1360 .action = lu_fsm_wait_lu_compl,
1361 },
1362 [VLR_ULA_S_WAIT_LU_COMPL_STANDALONE] = {
1363 .in_event_mask = S(VLR_ULA_E_LU_COMPL_SUCCESS) |
1364 S(VLR_ULA_E_LU_COMPL_FAILURE) |
1365 S(VLR_ULA_E_NEW_TMSI_ACK),
1366 .out_state_mask = S(VLR_ULA_S_DONE),
1367 .name = OSMO_STRINGIFY(VLR_ULA_S_WAIT_LU_COMPL_STANDALONE),
1368 .action = lu_fsm_wait_lu_compl_standalone,
1369 },
1370 [VLR_ULA_S_DONE] = {
1371 .name = OSMO_STRINGIFY(VLR_ULA_S_DONE),
1372 .onenter = lu_fsm_dispatch_result,
1373 },
1374};
1375
1376static void fsm_lu_cleanup(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause)
1377{
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001378 struct lu_fsm_priv *lfp = lu_fsm_fi_priv(fi);
Harald Welteb8b85a12016-06-17 00:06:42 +02001379 struct vlr_subscr *vsub = lfp->vsub;
1380
1381 LOGPFSM(fi, "fsm_lu_cleanup called with cause %s\n",
1382 osmo_fsm_term_cause_name(cause));
1383 if (vsub && vsub->lu_fsm == fi)
1384 vsub->lu_fsm = NULL;
1385}
1386
1387static struct osmo_fsm vlr_lu_fsm = {
1388 .name = "vlr_lu_fsm",
1389 .states = vlr_lu_fsm_states,
1390 .num_states = ARRAY_SIZE(vlr_lu_fsm_states),
1391 .allstate_event_mask = 0,
1392 .allstate_action = NULL,
1393 .log_subsys = DVLR,
1394 .event_names = fsm_lu_event_names,
1395 .cleanup = fsm_lu_cleanup,
1396};
1397
Neels Hofmeyrc5e0ace2018-03-02 03:12:22 +01001398static inline struct lu_fsm_priv *lu_fsm_fi_priv(struct osmo_fsm_inst *fi)
1399{
1400 OSMO_ASSERT(fi->fsm == &vlr_lu_fsm);
1401 return (struct lu_fsm_priv*)fi->priv;
1402}
1403
Harald Welteb8b85a12016-06-17 00:06:42 +02001404struct osmo_fsm_inst *
1405vlr_loc_update(struct osmo_fsm_inst *parent,
1406 uint32_t parent_event_success,
1407 uint32_t parent_event_failure,
1408 void *parent_event_data,
1409 struct vlr_instance *vlr, void *msc_conn_ref,
1410 enum vlr_lu_type type, uint32_t tmsi, const char *imsi,
1411 const struct osmo_location_area_id *old_lai,
1412 const struct osmo_location_area_id *new_lai,
1413 bool authentication_required,
Harald Welte71c51df2017-12-23 18:51:48 +01001414 bool ciphering_required,
Harald Welteb8b85a12016-06-17 00:06:42 +02001415 bool is_r99, bool is_utran,
1416 bool assign_tmsi)
1417{
1418 struct osmo_fsm_inst *fi;
1419 struct lu_fsm_priv *lfp;
1420
1421 fi = osmo_fsm_inst_alloc_child(&vlr_lu_fsm, parent, parent_event_failure);
1422 if (!fi)
1423 return NULL;
1424
1425 lfp = talloc_zero(fi, struct lu_fsm_priv);
1426 lfp->vlr = vlr;
1427 lfp->msc_conn_ref = msc_conn_ref;
1428 lfp->tmsi = tmsi;
1429 lfp->type = type;
1430 lfp->old_lai = *old_lai;
1431 lfp->new_lai = *new_lai;
1432 lfp->lu_by_tmsi = true;
1433 lfp->parent_event_success = parent_event_success;
1434 lfp->parent_event_failure = parent_event_failure;
1435 lfp->parent_event_data = parent_event_data;
1436 lfp->authentication_required = authentication_required;
1437 lfp->ciphering_required = ciphering_required;
1438 lfp->is_r99 = is_r99;
1439 lfp->is_utran = is_utran;
1440 lfp->assign_tmsi = assign_tmsi;
1441 if (imsi) {
1442 strncpy(lfp->imsi, imsi, sizeof(lfp->imsi)-1);
1443 lfp->imsi[sizeof(lfp->imsi)-1] = '\0';
1444 lfp->lu_by_tmsi = false;
1445 }
1446 fi->priv = lfp;
1447
1448 LOGPFSM(fi, "rev=%s net=%s%s%s\n",
1449 is_r99 ? "R99" : "GSM",
1450 is_utran ? "UTRAN" : "GERAN",
1451 (authentication_required || ciphering_required)?
1452 " Auth" : " (no Auth)",
1453 (authentication_required || ciphering_required)?
1454 (ciphering_required? "+Ciph" : " (no Ciph)")
1455 : "");
1456
Neels Hofmeyr84da6b12016-05-20 21:59:55 +02001457 if (is_utran && !authentication_required)
1458 LOGPFSML(fi, LOGL_ERROR,
1459 "Authentication off on UTRAN network. Good luck.\n");
1460
Harald Welteb8b85a12016-06-17 00:06:42 +02001461 osmo_fsm_inst_dispatch(fi, VLR_ULA_E_UPDATE_LA, NULL);
1462
1463 return fi;
1464}
1465
Neels Hofmeyr15809592018-04-06 02:57:51 +02001466void vlr_loc_update_cancel(struct osmo_fsm_inst *fi,
1467 enum osmo_fsm_term_cause fsm_cause,
1468 uint8_t gsm48_cause)
Harald Welteb8b85a12016-06-17 00:06:42 +02001469{
Neels Hofmeyr15809592018-04-06 02:57:51 +02001470 struct lu_fsm_priv *lfp;
1471
1472 OSMO_ASSERT(fi);
1473 OSMO_ASSERT(fi->fsm == &vlr_lu_fsm);
1474
1475 lfp = fi->priv;
1476 lfp->rej_cause = gsm48_cause;
1477
1478 if (fi->state != VLR_ULA_S_DONE)
1479 lu_fsm_failure(fi, gsm48_cause);
Harald Welteb8b85a12016-06-17 00:06:42 +02001480}
1481
1482void vlr_lu_fsm_init(void)
1483{
1484 osmo_fsm_register(&vlr_lu_fsm);
1485 osmo_fsm_register(&upd_hlr_vlr_fsm);
1486 osmo_fsm_register(&sub_pres_vlr_fsm);
1487 osmo_fsm_register(&lu_compl_vlr_fsm);
1488}