blob: 51e22c9dcd9e3f77b3503e022383165368ff963a [file] [log] [blame]
Harald Welteb8b85a12016-06-17 00:06:42 +02001/* Osmocom Visitor Location Register (VLR) Autentication FSM */
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
23#include <osmocom/core/fsm.h>
24#include <osmocom/core/utils.h>
25#include <osmocom/gsm/gsup.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020026#include <osmocom/msc/vlr.h>
27#include <osmocom/msc/debug.h>
Harald Welteb8b85a12016-06-17 00:06:42 +020028
29#include "vlr_core.h"
30#include "vlr_auth_fsm.h"
31
32#define S(x) (1 << (x))
33
34static const struct value_string fsm_auth_event_names[] = {
35 OSMO_VALUE_STRING(VLR_AUTH_E_START),
36 OSMO_VALUE_STRING(VLR_AUTH_E_HLR_SAI_ACK),
37 OSMO_VALUE_STRING(VLR_AUTH_E_HLR_SAI_NACK),
38 OSMO_VALUE_STRING(VLR_AUTH_E_HLR_SAI_ABORT),
39 OSMO_VALUE_STRING(VLR_AUTH_E_MS_AUTH_RESP),
40 OSMO_VALUE_STRING(VLR_AUTH_E_MS_AUTH_FAIL),
41 OSMO_VALUE_STRING(VLR_AUTH_E_MS_ID_IMSI),
42 { 0, NULL }
43};
44
45const struct value_string vlr_auth_fsm_result_names[] = {
46 OSMO_VALUE_STRING(VLR_AUTH_RES_ABORTED),
47 OSMO_VALUE_STRING(VLR_AUTH_RES_UNKNOWN_SUBSCR),
48 OSMO_VALUE_STRING(VLR_AUTH_RES_PROC_ERR),
49 OSMO_VALUE_STRING(VLR_AUTH_RES_AUTH_FAILED),
50 OSMO_VALUE_STRING(VLR_AUTH_RES_PASSED),
51 {0, NULL}
52};
53
54/* private state of the auth_fsm_instance */
55struct auth_fsm_priv {
56 struct vlr_subscr *vsub;
57 bool by_imsi;
58 bool is_r99;
59 bool is_utran;
60 bool auth_requested;
61
Neels Hofmeyr33f53412017-10-29 02:11:18 +010062 int auth_tuple_max_reuse_count; /* see vlr->cfg instead */
Harald Welteb8b85a12016-06-17 00:06:42 +020063};
64
65/***********************************************************************
66 * Utility functions
67 ***********************************************************************/
68
69/* Always use either vlr_subscr_get_auth_tuple() or vlr_subscr_has_auth_tuple()
70 * instead, to ensure proper use count.
71 * Return an auth tuple with the lowest use_count among the auth tuples. If
Neels Hofmeyr33f53412017-10-29 02:11:18 +010072 * max_reuse_count >= 0, return NULL if all available auth tuples have a use
73 * count > max_reuse_count. If max_reuse_count is negative, return a currently
Harald Welteb8b85a12016-06-17 00:06:42 +020074 * least used auth tuple without enforcing a maximum use count. If there are
75 * no auth tuples, return NULL.
76 */
77static struct gsm_auth_tuple *
Neels Hofmeyr33f53412017-10-29 02:11:18 +010078_vlr_subscr_next_auth_tuple(struct vlr_subscr *vsub, int max_reuse_count)
Harald Welteb8b85a12016-06-17 00:06:42 +020079{
80 unsigned int count;
81 unsigned int idx;
82 struct gsm_auth_tuple *at = NULL;
83 unsigned int key_seq = GSM_KEY_SEQ_INVAL;
84
85 if (!vsub)
86 return NULL;
87
88 if (vsub->last_tuple)
89 key_seq = vsub->last_tuple->key_seq;
90
91 if (key_seq == GSM_KEY_SEQ_INVAL)
92 /* Start with 0 after increment modulo array size */
93 idx = ARRAY_SIZE(vsub->auth_tuples) - 1;
94 else
95 idx = key_seq;
96
97 for (count = ARRAY_SIZE(vsub->auth_tuples); count > 0; count--) {
98 idx = (idx + 1) % ARRAY_SIZE(vsub->auth_tuples);
99
100 if (vsub->auth_tuples[idx].key_seq == GSM_KEY_SEQ_INVAL)
101 continue;
102
103 if (!at || vsub->auth_tuples[idx].use_count < at->use_count)
104 at = &vsub->auth_tuples[idx];
105 }
106
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100107 if (!at || (max_reuse_count >= 0 && at->use_count > max_reuse_count))
Harald Welteb8b85a12016-06-17 00:06:42 +0200108 return NULL;
109
110 return at;
111}
112
113/* Return an auth tuple and increment its use count. */
114static struct gsm_auth_tuple *
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100115vlr_subscr_get_auth_tuple(struct vlr_subscr *vsub, int max_reuse_count)
Harald Welteb8b85a12016-06-17 00:06:42 +0200116{
117 struct gsm_auth_tuple *at = _vlr_subscr_next_auth_tuple(vsub,
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100118 max_reuse_count);
Harald Welteb8b85a12016-06-17 00:06:42 +0200119 if (!at)
120 return NULL;
121 at->use_count++;
122 return at;
123}
124
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100125/* Return whether an auth tuple with a matching use_count is available. */
Harald Welteb8b85a12016-06-17 00:06:42 +0200126static bool vlr_subscr_has_auth_tuple(struct vlr_subscr *vsub,
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100127 int max_reuse_count)
Harald Welteb8b85a12016-06-17 00:06:42 +0200128{
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100129 return _vlr_subscr_next_auth_tuple(vsub, max_reuse_count) != NULL;
Harald Welteb8b85a12016-06-17 00:06:42 +0200130}
131
132static bool check_auth_resp(struct vlr_subscr *vsub, bool is_r99,
133 bool is_utran, const uint8_t *res,
134 uint8_t res_len)
135{
136 struct gsm_auth_tuple *at = vsub->last_tuple;
137 struct osmo_auth_vector *vec = &at->vec;
138 bool check_umts;
139 OSMO_ASSERT(at);
140
141 LOGVSUBP(LOGL_DEBUG, vsub, "received res: %s\n",
142 osmo_hexdump(res, res_len));
143
144 /* RES must be present and at least 32bit */
145 if (!res || res_len < sizeof(vec->sres)) {
146 LOGVSUBP(LOGL_NOTICE, vsub, "AUTH RES missing or too short "
147 "(%u)\n", res_len);
148 goto out_false;
149 }
150
151 check_umts = false;
152 if (is_r99 && (vec->auth_types & OSMO_AUTH_TYPE_UMTS)) {
153 check_umts = true;
154 /* We have a R99 capable UE and have a UMTS AKA capable USIM.
155 * However, the ME may still choose to only perform GSM AKA, as
156 * long as the bearer is GERAN */
157 if (res_len != vec->res_len) {
158 if (is_utran) {
159 LOGVSUBP(LOGL_NOTICE, vsub,
160 "AUTH via UTRAN but "
161 "res_len(%u) != vec->res_len(%u)\n",
162 res_len, vec->res_len);
163 goto out_false;
164 }
165 check_umts = false;
166 }
167 }
168
169 if (check_umts) {
170 if (res_len != vec->res_len
171 || memcmp(res, vec->res, res_len)) {
172 LOGVSUBP(LOGL_INFO, vsub, "UMTS AUTH failure:"
173 " mismatching res (expected res=%s)\n",
174 osmo_hexdump(vec->res, vec->res_len));
175 goto out_false;
176 }
177
178 LOGVSUBP(LOGL_INFO, vsub, "AUTH established UMTS security"
179 " context\n");
180 vsub->sec_ctx = VLR_SEC_CTX_UMTS;
181 return true;
182 } else {
183 if (res_len != sizeof(vec->sres)
184 || memcmp(res, vec->sres, sizeof(vec->sres))) {
185 LOGVSUBP(LOGL_INFO, vsub, "GSM AUTH failure:"
186 " mismatching sres (expected sres=%s)\n",
187 osmo_hexdump(vec->sres, sizeof(vec->sres)));
188 goto out_false;
189 }
190
191 LOGVSUBP(LOGL_INFO, vsub, "AUTH established GSM security"
192 " context\n");
193 vsub->sec_ctx = VLR_SEC_CTX_GSM;
194 return true;
195 }
196
197out_false:
198 vsub->sec_ctx = VLR_SEC_CTX_NONE;
199 return false;
200}
201
202static void auth_fsm_onenter_failed(struct osmo_fsm_inst *fi, uint32_t prev_state)
203{
204 struct auth_fsm_priv *afp = fi->priv;
205 struct vlr_subscr *vsub = afp->vsub;
206
207 /* If authentication hasn't even started, e.g. the HLR sent no auth
208 * info, then we also don't need to tell the HLR about an auth failure.
209 */
Max770fbd22018-01-24 12:48:33 +0100210 if (afp->auth_requested) {
211 int rc = vlr_subscr_tx_auth_fail_rep(vsub);
212 if (rc < 0)
213 LOGVSUBP(LOGL_ERROR, vsub, "Failed to communicate AUTH failure to HLR\n");
214 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200215}
216
Harald Welteb8b85a12016-06-17 00:06:42 +0200217/* Terminate the Auth FSM Instance and notify parent */
218static void auth_fsm_term(struct osmo_fsm_inst *fi, enum vlr_auth_fsm_result res)
219{
220 struct auth_fsm_priv *afp = fi->priv;
221 struct vlr_subscr *vsub = afp->vsub;
222
223 LOGPFSM(fi, "Authentication terminating with result %s\n",
224 vlr_auth_fsm_result_name(res));
225
226 /* Do one final state transition (mostly for logging purpose) */
227 if (res == VLR_AUTH_RES_PASSED)
228 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_AUTHENTICATED, 0, 0);
229 else
230 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_AUTH_FAILED, 0, 0);
231
232 /* return the result to the parent FSM */
233 osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, &res);
234 vsub->auth_fsm = NULL;
235}
236
237/* back-end function transmitting authentication. Caller ensures we have valid
238 * tuple */
239static int _vlr_subscr_authenticate(struct osmo_fsm_inst *fi)
240{
241 struct auth_fsm_priv *afp = fi->priv;
242 struct vlr_subscr *vsub = afp->vsub;
243 struct gsm_auth_tuple *at;
244
245 /* Caller ensures we have vectors available */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100246 at = vlr_subscr_get_auth_tuple(vsub, afp->auth_tuple_max_reuse_count);
Harald Welteb8b85a12016-06-17 00:06:42 +0200247 if (!at) {
248 LOGPFSML(fi, LOGL_ERROR, "A previous check ensured that an"
249 " auth tuple was available, but now there is in fact"
250 " none.\n");
251 auth_fsm_term(fi, VLR_AUTH_RES_PROC_ERR);
252 return -1;
253 }
254
255 LOGPFSM(fi, "got auth tuple: use_count=%d key_seq=%d\n",
256 at->use_count, at->key_seq);
257
258 OSMO_ASSERT(at);
259
260 /* Transmit auth req to subscriber */
261 afp->auth_requested = true;
262 vsub->last_tuple = at;
263 vsub->vlr->ops.tx_auth_req(vsub->msc_conn_ref, at,
Neels Hofmeyre3d72d72017-12-18 02:06:44 +0100264 vlr_use_umts_aka(&at->vec, afp->is_r99));
Harald Welteb8b85a12016-06-17 00:06:42 +0200265 return 0;
266}
267
268/***********************************************************************
269 * FSM State Action functions
270 ***********************************************************************/
271
272/* Initial State of TS 23.018 AUT_VLR */
273static void auth_fsm_needs_auth(struct osmo_fsm_inst *fi, uint32_t event, void *data)
274{
275 struct auth_fsm_priv *afp = fi->priv;
276 struct vlr_subscr *vsub = afp->vsub;
277
278 OSMO_ASSERT(event == VLR_AUTH_E_START);
279
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100280 /* Start off with the default max_reuse_count, possibly change that if we
Harald Welteb8b85a12016-06-17 00:06:42 +0200281 * need to re-use an old tuple. */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100282 afp->auth_tuple_max_reuse_count = vsub->vlr->cfg.auth_tuple_max_reuse_count;
Harald Welteb8b85a12016-06-17 00:06:42 +0200283
284 /* Check if we have vectors available */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100285 if (!vlr_subscr_has_auth_tuple(vsub, afp->auth_tuple_max_reuse_count)) {
Harald Welteb8b85a12016-06-17 00:06:42 +0200286 /* Obtain_Authentication_Sets_VLR */
Max770fbd22018-01-24 12:48:33 +0100287 int rc = vlr_subscr_req_sai(vsub, NULL, NULL);
288 if (rc < 0)
289 LOGPFSM(fi, "Failed to request Authentication Sets from VLR\n");
Harald Welteb8b85a12016-06-17 00:06:42 +0200290 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_NEEDS_AUTH_WAIT_AI,
291 GSM_29002_TIMER_M, 0);
292 } else {
293 /* go straight ahead with sending auth request */
294 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP,
295 vlr_timer(vsub->vlr, 3260), 3260);
296 _vlr_subscr_authenticate(fi);
297 }
298}
299
300/* Waiting for Authentication Info from HLR */
301static void auth_fsm_wait_ai(struct osmo_fsm_inst *fi, uint32_t event,
302 void *data)
303{
304 struct auth_fsm_priv *afp = fi->priv;
305 struct vlr_subscr *vsub = afp->vsub;
306 struct osmo_gsup_message *gsup = data;
307
308 if (event == VLR_AUTH_E_HLR_SAI_NACK)
309 LOGPFSM(fi, "GSUP: rx Auth Info Error cause: %d: %s\n",
310 gsup->cause,
311 get_value_string(gsm48_gmm_cause_names, gsup->cause));
312
313 /* We are in what corresponds to the
314 * Wait_For_Authentication_Sets state of TS 23.018 OAS_VLR */
315 if ((event == VLR_AUTH_E_HLR_SAI_ACK && !gsup->num_auth_vectors)
316 || (event == VLR_AUTH_E_HLR_SAI_NACK &&
317 gsup->cause != GMM_CAUSE_IMSI_UNKNOWN)
318 || (event == VLR_AUTH_E_HLR_SAI_ABORT)) {
319 if (vsub->vlr->cfg.auth_reuse_old_sets_on_error
320 && vlr_subscr_has_auth_tuple(vsub, -1)) {
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100321 /* To re-use an old tuple, disable the max_reuse_count
Harald Welteb8b85a12016-06-17 00:06:42 +0200322 * constraint. */
Neels Hofmeyr33f53412017-10-29 02:11:18 +0100323 afp->auth_tuple_max_reuse_count = -1;
Harald Welteb8b85a12016-06-17 00:06:42 +0200324 goto pass;
325 }
326 /* result = procedure error */
327 auth_fsm_term(fi, VLR_AUTH_RES_PROC_ERR);
328 return;
329 }
330
331 switch (event) {
332 case VLR_AUTH_E_HLR_SAI_ACK:
333 vlr_subscr_update_tuples(vsub, gsup);
334 goto pass;
335 break;
336 case VLR_AUTH_E_HLR_SAI_NACK:
337 auth_fsm_term(fi,
338 gsup->cause == GMM_CAUSE_IMSI_UNKNOWN?
339 VLR_AUTH_RES_UNKNOWN_SUBSCR
340 : VLR_AUTH_RES_PROC_ERR);
341 break;
342 }
343
344 return;
345pass:
346 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP,
347 vlr_timer(vsub->vlr, 3260), 3260);
348 _vlr_subscr_authenticate(fi);
349}
350
351/* Waiting for Authentication Response from MS */
352static void auth_fsm_wait_auth_resp(struct osmo_fsm_inst *fi, uint32_t event,
353 void *data)
354{
355 struct auth_fsm_priv *afp = fi->priv;
356 struct vlr_subscr *vsub = afp->vsub;
357 struct vlr_instance *vlr = vsub->vlr;
358 struct vlr_auth_resp_par *par = data;
359 int rc;
360
361 switch (event) {
362 case VLR_AUTH_E_MS_AUTH_RESP:
363 rc = check_auth_resp(vsub, par->is_r99, par->is_utran,
364 par->res, par->res_len);
365 if (rc == false) {
366 if (!afp->by_imsi) {
367 vlr->ops.tx_id_req(vsub->msc_conn_ref,
368 GSM_MI_TYPE_IMSI);
369 osmo_fsm_inst_state_chg(fi,
370 VLR_SUB_AS_WAIT_ID_IMSI,
371 vlr_timer(vlr, 3270), 3270);
372 } else {
373 auth_fsm_term(fi, VLR_AUTH_RES_AUTH_FAILED);
374 }
375 } else {
376 auth_fsm_term(fi, VLR_AUTH_RES_PASSED);
377 }
378 break;
379 case VLR_AUTH_E_MS_AUTH_FAIL:
380 if (par->auts) {
381 /* First failure, start re-sync attempt */
Max770fbd22018-01-24 12:48:33 +0100382 rc = vlr_subscr_req_sai(vsub, par->auts,
Harald Welteb8b85a12016-06-17 00:06:42 +0200383 vsub->last_tuple->vec.rand);
384 osmo_fsm_inst_state_chg(fi,
385 VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC,
386 GSM_29002_TIMER_M, 0);
387 } else
388 auth_fsm_term(fi, VLR_AUTH_RES_AUTH_FAILED);
389 break;
390 }
391}
392
393/* Waiting for Authentication Info from HLR (resync case) */
394static void auth_fsm_wait_ai_resync(struct osmo_fsm_inst *fi,
395 uint32_t event, void *data)
396{
397 struct auth_fsm_priv *afp = fi->priv;
398 struct vlr_subscr *vsub = afp->vsub;
399 struct osmo_gsup_message *gsup = data;
400
401 /* We are in what corresponds to the
402 * Wait_For_Authentication_Sets state of TS 23.018 OAS_VLR */
403 if ((event == VLR_AUTH_E_HLR_SAI_ACK && !gsup->num_auth_vectors) ||
404 (event == VLR_AUTH_E_HLR_SAI_NACK &&
405 gsup->cause != GMM_CAUSE_IMSI_UNKNOWN) ||
406 (event == VLR_AUTH_E_HLR_SAI_ABORT)) {
407 /* result = procedure error */
408 auth_fsm_term(fi, VLR_AUTH_RES_PROC_ERR);
409 }
410 switch (event) {
411 case VLR_AUTH_E_HLR_SAI_ACK:
412 vlr_subscr_update_tuples(vsub, gsup);
413 goto pass;
414 break;
415 case VLR_AUTH_E_HLR_SAI_NACK:
416 auth_fsm_term(fi,
417 gsup->cause == GMM_CAUSE_IMSI_UNKNOWN?
418 VLR_AUTH_RES_UNKNOWN_SUBSCR
419 : VLR_AUTH_RES_PROC_ERR);
420 break;
421 }
422
423 return;
424pass:
425 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_WAIT_RESP_RESYNC,
426 vlr_timer(vsub->vlr, 3260), 3260);
427 _vlr_subscr_authenticate(fi);
428}
429
430/* Waiting for AUTH RESP from MS (re-sync case) */
431static void auth_fsm_wait_auth_resp_resync(struct osmo_fsm_inst *fi,
432 uint32_t event, void *data)
433{
434 struct auth_fsm_priv *afp = fi->priv;
435 struct vlr_subscr *vsub = afp->vsub;
436 struct vlr_auth_resp_par *par = data;
437 struct vlr_instance *vlr = vsub->vlr;
438 int rc;
439
440 switch (event) {
441 case VLR_AUTH_E_MS_AUTH_RESP:
442 rc = check_auth_resp(vsub, par->is_r99, par->is_utran,
443 par->res, par->res_len);
444 if (rc == false) {
445 if (!afp->by_imsi) {
446 vlr->ops.tx_id_req(vsub->msc_conn_ref,
447 GSM_MI_TYPE_IMSI);
448 osmo_fsm_inst_state_chg(fi,
449 VLR_SUB_AS_WAIT_ID_IMSI,
450 vlr_timer(vlr, 3270), 3270);
451 } else {
452 /* Result = Aborted */
453 auth_fsm_term(fi, VLR_AUTH_RES_ABORTED);
454 }
455 } else {
456 /* Result = Pass */
457 auth_fsm_term(fi, VLR_AUTH_RES_PASSED);
458 }
459 break;
460 case VLR_AUTH_E_MS_AUTH_FAIL:
461 /* Second failure: Result = Fail */
462 auth_fsm_term(fi, VLR_AUTH_RES_AUTH_FAILED);
463 break;
464 }
465}
466
467/* AUT_VLR waiting for Obtain_IMSI_VLR result */
468static void auth_fsm_wait_imsi(struct osmo_fsm_inst *fi, uint32_t event,
469 void *data)
470{
471 struct auth_fsm_priv *afp = fi->priv;
472 struct vlr_subscr *vsub = afp->vsub;
473 const char *mi_string = data;
474
475 switch (event) {
476 case VLR_AUTH_E_MS_ID_IMSI:
477 if (vsub->imsi[0]
478 && !vlr_subscr_matches_imsi(vsub, mi_string)) {
479 LOGVSUBP(LOGL_ERROR, vsub, "IMSI in ID RESP differs:"
480 " %s\n", mi_string);
481 } else {
482 strncpy(vsub->imsi, mi_string, sizeof(vsub->imsi));
483 vsub->imsi[sizeof(vsub->imsi)-1] = '\0';
484 }
485 /* retry with identity=IMSI */
486 afp->by_imsi = true;
487 osmo_fsm_inst_state_chg(fi, VLR_SUB_AS_NEEDS_AUTH, 0, 0);
488 osmo_fsm_inst_dispatch(fi, VLR_AUTH_E_START, NULL);
489 break;
490 }
491}
492
493static const struct osmo_fsm_state auth_fsm_states[] = {
494 [VLR_SUB_AS_NEEDS_AUTH] = {
495 .name = OSMO_STRINGIFY(VLR_SUB_AS_NEEDS_AUTH),
496 .in_event_mask = S(VLR_AUTH_E_START),
497 .out_state_mask = S(VLR_SUB_AS_NEEDS_AUTH_WAIT_AI) |
498 S(VLR_SUB_AS_WAIT_RESP),
499 .action = auth_fsm_needs_auth,
500 },
501 [VLR_SUB_AS_NEEDS_AUTH_WAIT_AI] = {
502 .name = OSMO_STRINGIFY(VLR_SUB_AS_NEEDS_AUTH_WAIT_AI),
503 .in_event_mask = S(VLR_AUTH_E_HLR_SAI_ACK) |
504 S(VLR_AUTH_E_HLR_SAI_NACK),
505 .out_state_mask = S(VLR_SUB_AS_AUTH_FAILED) |
506 S(VLR_SUB_AS_WAIT_RESP),
507 .action = auth_fsm_wait_ai,
508 },
509 [VLR_SUB_AS_WAIT_RESP] = {
510 .name = OSMO_STRINGIFY(VLR_SUB_AS_WAIT_RESP),
511 .in_event_mask = S(VLR_AUTH_E_MS_AUTH_RESP) |
512 S(VLR_AUTH_E_MS_AUTH_FAIL),
513 .out_state_mask = S(VLR_SUB_AS_WAIT_ID_IMSI) |
514 S(VLR_SUB_AS_AUTH_FAILED) |
515 S(VLR_SUB_AS_AUTHENTICATED) |
516 S(VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC),
517 .action = auth_fsm_wait_auth_resp,
518 },
519 [VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC] = {
520 .name = OSMO_STRINGIFY(VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC),
521 .in_event_mask = S(VLR_AUTH_E_HLR_SAI_ACK) |
522 S(VLR_AUTH_E_HLR_SAI_NACK),
523 .out_state_mask = S(VLR_SUB_AS_AUTH_FAILED) |
524 S(VLR_SUB_AS_WAIT_RESP_RESYNC),
525 .action = auth_fsm_wait_ai_resync,
526 },
527 [VLR_SUB_AS_WAIT_RESP_RESYNC] = {
528 .name = OSMO_STRINGIFY(VLR_SUB_AS_WAIT_RESP_RESYNC),
529 .in_event_mask = S(VLR_AUTH_E_MS_AUTH_RESP) |
530 S(VLR_AUTH_E_MS_AUTH_FAIL),
531 .out_state_mask = S(VLR_SUB_AS_AUTH_FAILED) |
532 S(VLR_SUB_AS_AUTHENTICATED),
533 .action = auth_fsm_wait_auth_resp_resync,
534 },
535 [VLR_SUB_AS_WAIT_ID_IMSI] = {
536 .name = OSMO_STRINGIFY(VLR_SUB_AS_WAIT_ID_IMSI),
537 .in_event_mask = S(VLR_AUTH_E_MS_ID_IMSI),
538 .out_state_mask = S(VLR_SUB_AS_NEEDS_AUTH),
539 .action = auth_fsm_wait_imsi,
540 },
541 [VLR_SUB_AS_AUTHENTICATED] = {
542 .name = OSMO_STRINGIFY(VLR_SUB_AS_AUTHENTICATED),
543 .in_event_mask = 0,
544 .out_state_mask = 0,
545 },
546 [VLR_SUB_AS_AUTH_FAILED] = {
547 .name = OSMO_STRINGIFY(VLR_SUB_AS_AUTH_FAILED),
548 .in_event_mask = 0,
549 .out_state_mask = 0,
550 .onenter = auth_fsm_onenter_failed,
551 },
552};
553
554struct osmo_fsm vlr_auth_fsm = {
555 .name = "VLR_Authenticate",
556 .states = auth_fsm_states,
557 .num_states = ARRAY_SIZE(auth_fsm_states),
558 .allstate_event_mask = 0,
559 .allstate_action = NULL,
560 .log_subsys = DVLR,
561 .event_names = fsm_auth_event_names,
562};
563
564/***********************************************************************
565 * User API (for SGSN/MSC code)
566 ***********************************************************************/
567
568/* MSC->VLR: Start Procedure Authenticate_VLR (TS 23.012 Ch. 4.1.2.2) */
569struct osmo_fsm_inst *auth_fsm_start(struct vlr_subscr *vsub,
570 uint32_t log_level,
571 struct osmo_fsm_inst *parent,
572 uint32_t parent_term_event,
573 bool is_r99,
574 bool is_utran)
575{
576 struct osmo_fsm_inst *fi;
577 struct auth_fsm_priv *afp;
578
579 fi = osmo_fsm_inst_alloc_child(&vlr_auth_fsm, parent,
580 parent_term_event);
Neels Hofmeyrc698ab92017-11-07 13:23:13 +0100581 if (!fi) {
582 osmo_fsm_inst_dispatch(parent, parent_term_event, 0);
583 return NULL;
584 }
Harald Welteb8b85a12016-06-17 00:06:42 +0200585
586 afp = talloc_zero(fi, struct auth_fsm_priv);
587 if (!afp) {
588 osmo_fsm_inst_dispatch(parent, parent_term_event, 0);
589 return NULL;
590 }
591
592 afp->vsub = vsub;
593 if (vsub->imsi[0])
594 afp->by_imsi = true;
595 afp->is_r99 = is_r99;
596 afp->is_utran = is_utran;
597 fi->priv = afp;
598 vsub->auth_fsm = fi;
599
600 osmo_fsm_inst_dispatch(fi, VLR_AUTH_E_START, NULL);
601
602 return fi;
603}