blob: d95d1b7ec251795bb135a3b938e0a3e7deeee543 [file] [log] [blame]
Harald Welteb8b85a12016-06-17 00:06:42 +02001/* Osmocom Visitor Location Register (VLR) code base */
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/linuxlist.h>
23#include <osmocom/core/fsm.h>
24#include <osmocom/core/utils.h>
25#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
26#include <osmocom/gsm/gsup.h>
27#include <osmocom/gsm/apn.h>
28#include <openbsc/gsm_subscriber.h>
29#include <openbsc/gsup_client.h>
30#include <openbsc/vlr.h>
31#include <openbsc/gprs_sgsn.h>
32#include <openbsc/gprs_utils.h>
33#include <openbsc/debug.h>
34
35#include <openssl/rand.h>
36
37#include <netinet/in.h>
38#include <arpa/inet.h>
39#include <limits.h>
40
41#include "vlr_core.h"
42#include "vlr_auth_fsm.h"
43#include "vlr_lu_fsm.h"
44#include "vlr_access_req_fsm.h"
45
46#define SGSN_SUBSCR_MAX_RETRIES 3
47#define SGSN_SUBSCR_RETRY_INTERVAL 10
48
49/***********************************************************************
50 * Convenience functions
51 ***********************************************************************/
52
53const struct value_string vlr_ciph_names[] = {
54 OSMO_VALUE_STRING(VLR_CIPH_NONE),
55 OSMO_VALUE_STRING(VLR_CIPH_A5_1),
56 OSMO_VALUE_STRING(VLR_CIPH_A5_2),
57 OSMO_VALUE_STRING(VLR_CIPH_A5_3),
58 { 0, NULL }
59};
60
61uint32_t vlr_timer(struct vlr_instance *vlr, uint32_t timer)
62{
63 uint32_t tidx = 0xffffffff;
64
65 switch (timer) {
66 case 3270:
67 tidx = VLR_T_3270;
68 break;
69 case 3260:
70 tidx = VLR_T_3260;
71 break;
72 case 3250:
73 tidx = VLR_T_3250;
74 break;
75 }
76
77 OSMO_ASSERT(tidx < sizeof(vlr->cfg.timer));
78 return vlr->cfg.timer[tidx];
79}
80
81struct vlr_subscr *_vlr_subscr_find_by_imsi(struct vlr_instance *vlr,
82 const char *imsi,
83 const char *file, int line)
84{
85 struct vlr_subscr *vsub;
86
87 if (!imsi || !*imsi)
88 return NULL;
89
90 llist_for_each_entry(vsub, &vlr->subscribers, list) {
91 if (vlr_subscr_matches_imsi(vsub, imsi))
92 return _vlr_subscr_get(vsub, file, line);
93 }
94 return NULL;
95}
96
97struct vlr_subscr *_vlr_subscr_find_by_tmsi(struct vlr_instance *vlr,
98 uint32_t tmsi,
99 const char *file, int line)
100{
101 struct vlr_subscr *vsub;
102
103 if (tmsi == GSM_RESERVED_TMSI)
104 return NULL;
105
106 llist_for_each_entry(vsub, &vlr->subscribers, list) {
107 if (vlr_subscr_matches_tmsi(vsub, tmsi))
108 return _vlr_subscr_get(vsub, file, line);
109 }
110 return NULL;
111}
112
113struct vlr_subscr *_vlr_subscr_find_by_msisdn(struct vlr_instance *vlr,
114 const char *msisdn,
115 const char *file, int line)
116{
117 struct vlr_subscr *vsub;
118
119 if (!msisdn || !*msisdn)
120 return NULL;
121
122 llist_for_each_entry(vsub, &vlr->subscribers, list) {
123 if (vlr_subscr_matches_msisdn(vsub, msisdn))
124 return _vlr_subscr_get(vsub, file, line);
125 }
126 return NULL;
127}
128
129/* Transmit GSUP message to HLR */
130static int vlr_tx_gsup_message(struct vlr_instance *vlr,
131 struct osmo_gsup_message *gsup_msg)
132{
133 struct msgb *msg = gsup_client_msgb_alloc();
134
135 osmo_gsup_encode(msg, gsup_msg);
136
137 if (!vlr->gsup_client) {
138 LOGP(DVLR, LOGL_NOTICE, "GSUP link is down, cannot "
139 "send GSUP: %s\n", msgb_hexdump(msg));
140 msgb_free(msg);
141 return -ENOTSUP;
142 }
143
144 LOGP(DVLR, LOGL_DEBUG, "GSUP tx: %s\n",
145 osmo_hexdump_nospc(msg->data, msg->len));
146
147 return gsup_client_send(vlr->gsup_client, msg);
148}
149
150/* Transmit GSUP message for subscriber to HLR, using IMSI from subscriber */
151static int vlr_subscr_tx_gsup_message(struct vlr_subscr *vsub,
152 struct osmo_gsup_message *gsup_msg)
153{
154 struct vlr_instance *vlr = vsub->vlr;
155
156 if (strlen(gsup_msg->imsi) == 0)
157 osmo_strlcpy(gsup_msg->imsi, vsub->imsi, sizeof(gsup_msg->imsi));
158
159 return vlr_tx_gsup_message(vlr, gsup_msg);
160}
161
162/* Transmit GSUP error in response to original message */
163static int vlr_tx_gsup_error_reply(struct vlr_instance *vlr,
164 struct osmo_gsup_message *gsup_orig,
165 enum gsm48_gmm_cause cause)
166{
167 struct osmo_gsup_message gsup_reply = {0};
168
169 osmo_strlcpy(gsup_reply.imsi, gsup_orig->imsi, sizeof(gsup_reply.imsi));
170 gsup_reply.cause = cause;
171 gsup_reply.message_type =
172 OSMO_GSUP_TO_MSGT_ERROR(gsup_orig->message_type);
173
174 return vlr_tx_gsup_message(vlr, &gsup_reply);
175}
176
177struct vlr_subscr *_vlr_subscr_get(struct vlr_subscr *sub, const char *file, int line)
178{
179 if (!sub)
180 return NULL;
181 OSMO_ASSERT(sub->use_count < INT_MAX);
182 sub->use_count++;
183 LOGPSRC(DREF, LOGL_DEBUG, file, line,
184 "VLR subscr %s usage increases to: %d\n",
185 vlr_subscr_name(sub), sub->use_count);
186 return sub;
187}
188
189struct vlr_subscr *_vlr_subscr_put(struct vlr_subscr *sub, const char *file, int line)
190{
191 if (!sub)
192 return NULL;
193 sub->use_count--;
194 LOGPSRC(DREF, sub->use_count >= 0? LOGL_DEBUG : LOGL_ERROR,
195 file, line,
196 "VLR subscr %s usage decreases to: %d\n",
197 vlr_subscr_name(sub), sub->use_count);
198 if (sub->use_count <= 0)
199 vlr_subscr_free(sub);
200 return NULL;
201}
202
203/* Allocate a new subscriber and insert it into list */
204static struct vlr_subscr *_vlr_subscr_alloc(struct vlr_instance *vlr)
205{
206 struct vlr_subscr *vsub;
207 int i;
208
209 vsub = talloc_zero(vlr, struct vlr_subscr);
210 vsub->vlr = vlr;
211 vsub->tmsi = GSM_RESERVED_TMSI;
212 vsub->tmsi_new = GSM_RESERVED_TMSI;
213
214 for (i = 0; i < ARRAY_SIZE(vsub->auth_tuples); i++)
215 vsub->auth_tuples[i].key_seq = GSM_KEY_SEQ_INVAL;
216
217 INIT_LLIST_HEAD(&vsub->cs.requests);
218 INIT_LLIST_HEAD(&vsub->ps.pdp_list);
219
220 llist_add_tail(&vsub->list, &vlr->subscribers);
221 return vsub;
222}
223
224struct vlr_subscr *vlr_subscr_alloc(struct vlr_instance *vlr)
225{
226 return vlr_subscr_get(_vlr_subscr_alloc(vlr));
227}
228
229/* Send a GSUP Purge MS request.
230 * TODO: this should be sent to the *previous* VLR when this VLR is "taking"
231 * this subscriber, not to the HLR? */
232int vlr_subscr_purge(struct vlr_subscr *vsub)
233{
234 struct osmo_gsup_message gsup_msg = {0};
235
236 gsup_msg.message_type = OSMO_GSUP_MSGT_PURGE_MS_REQUEST;
237
238 /* provide HLR number in case we know it */
239 gsup_msg.hlr_enc_len = vsub->hlr.len;
240 gsup_msg.hlr_enc = vsub->hlr.buf;
241
242 return vlr_subscr_tx_gsup_message(vsub, &gsup_msg);
243}
244
245void vlr_subscr_cancel(struct vlr_subscr *vsub, enum gsm48_gmm_cause cause)
246{
247 if (!vsub)
248 return;
249
250 if (vsub->lu_fsm) {
251 if (vsub->lu_fsm->state == VLR_ULA_S_WAIT_HLR_UPD)
252 osmo_fsm_inst_dispatch(vsub->lu_fsm,
253 VLR_ULA_E_HLR_LU_RES,
254 (void*)&cause);
255 else
256 osmo_fsm_inst_term(vsub->lu_fsm, OSMO_FSM_TERM_ERROR,
257 0);
258 }
259
260 if (vsub->proc_arq_fsm)
261 osmo_fsm_inst_term(vsub->proc_arq_fsm, OSMO_FSM_TERM_ERROR, 0);
262}
263
264/* Call vlr_subscr_cancel(), then completely drop the entry from the VLR */
265void vlr_subscr_free(struct vlr_subscr *vsub)
266{
267 llist_del(&vsub->list);
268 DEBUGP(DREF, "freeing VLR subscr %s\n", vlr_subscr_name(vsub));
269 talloc_free(vsub);
270}
271
272/* Generate a new TMSI and store in vsub->tmsi_new.
273 * Search all known subscribers to ensure that the TMSI is unique. */
274int vlr_subscr_alloc_tmsi(struct vlr_subscr *vsub)
275{
276 struct vlr_instance *vlr = vsub->vlr;
277 uint32_t tmsi;
278 int tried;
279
280 for (tried = 0; tried < 100; tried++) {
281 if (RAND_bytes((uint8_t *) &tmsi, sizeof(tmsi)) != 1) {
282 LOGP(DVLR, LOGL_ERROR, "RAND_bytes failed\n");
283 return -1;
284 }
285 /* throw the dice again, if the TSMI doesn't fit */
286 if (tmsi == GSM_RESERVED_TMSI)
287 continue;
288
289 /* Section 2.4 of 23.003: MSC has two MSB 00/01/10, SGSN 11 */
290 if (vlr->cfg.is_ps) {
291 /* SGSN */
292 tmsi |= 0xC000000;
293 } else {
294 /* MSC */
295 if ((tmsi & 0xC0000000) == 0xC0000000)
296 tmsi &= ~0xC0000000;
297 }
298
299 /* If this TMSI is already in use, try another one. */
300 if (vlr_subscr_find_by_tmsi(vlr, tmsi))
301 continue;
302
303 vsub->tmsi_new = tmsi;
304 return 0;
305 }
306
307 LOGP(DVLR, LOGL_ERROR, "subscr %s: unable to generate valid TMSI"
308 " after %d tries\n", vlr_subscr_name(vsub), tried);
309 return -1;
310}
311
312/* Find subscriber by IMSI, or create new subscriber if not found.
313 * \param[in] vlr VLR instace.
314 * \param[in] imsi IMSI string.
315 * \param[out] created if non-NULL, returns whether a new entry was created. */
316struct vlr_subscr *_vlr_subscr_find_or_create_by_imsi(struct vlr_instance *vlr,
317 const char *imsi,
318 bool *created,
319 const char *file,
320 int line)
321{
322 struct vlr_subscr *vsub;
323 vsub = _vlr_subscr_find_by_imsi(vlr, imsi, file, line);
324 if (vsub) {
325 if (created)
326 *created = false;
327 return vsub;
328 }
329
330 vsub = _vlr_subscr_get(_vlr_subscr_alloc(vlr), file, line);
331 if (!vsub)
332 return NULL;
333 vlr_subscr_set_imsi(vsub, imsi);
334 LOGP(DVLR, LOGL_INFO, "New subscr, IMSI: %s\n", vsub->imsi);
335 if (created)
336 *created = true;
337 return vsub;
338}
339
340/* Find subscriber by TMSI, or create new subscriber if not found.
341 * \param[in] vlr VLR instace.
342 * \param[in] tmsi TMSI.
343 * \param[out] created if non-NULL, returns whether a new entry was created. */
344struct vlr_subscr *_vlr_subscr_find_or_create_by_tmsi(struct vlr_instance *vlr,
345 uint32_t tmsi,
346 bool *created,
347 const char *file,
348 int line)
349{
350 struct vlr_subscr *vsub;
351 vsub = _vlr_subscr_find_by_tmsi(vlr, tmsi, file, line);
352 if (vsub) {
353 if (created)
354 *created = false;
355 return vsub;
356 }
357
358 vsub = _vlr_subscr_get(_vlr_subscr_alloc(vlr), file, line);
359 if (!vsub)
360 return NULL;
361 vsub->tmsi = tmsi;
362 LOGP(DVLR, LOGL_INFO, "New subscr, TMSI: 0x%08x\n", vsub->tmsi);
363 if (created)
364 *created = true;
365 return vsub;
366}
367
368void vlr_subscr_set_imsi(struct vlr_subscr *vsub, const char *imsi)
369{
370 if (!vsub)
371 return;
372 osmo_strlcpy(vsub->imsi, imsi, sizeof(vsub->imsi));
373 vsub->id = atoll(vsub->imsi);
374 DEBUGP(DVLR, "set IMSI on subscriber; IMSI=%s id=%llu\n",
375 vsub->imsi, vsub->id);
376}
377
378void vlr_subscr_set_imei(struct vlr_subscr *vsub, const char *imei)
379{
380 if (!vsub)
381 return;
382 osmo_strlcpy(vsub->imei, imei, sizeof(vsub->imei));
383 DEBUGP(DVLR, "set IMEI on subscriber; IMSI=%s IMEI=%s\n",
384 vsub->imsi, vsub->imei);
385}
386
387void vlr_subscr_set_imeisv(struct vlr_subscr *vsub, const char *imeisv)
388{
389 if (!vsub)
390 return;
391 osmo_strlcpy(vsub->imeisv, imeisv, sizeof(vsub->imeisv));
392 DEBUGP(DVLR, "set IMEISV on subscriber; IMSI=%s IMEISV=%s\n",
393 vsub->imsi, vsub->imeisv);
394}
395
396/* Safely copy the given MSISDN string to vsub->msisdn */
397void vlr_subscr_set_msisdn(struct vlr_subscr *vsub, const char *msisdn)
398{
399 if (!vsub)
400 return;
401 osmo_strlcpy(vsub->msisdn, msisdn, sizeof(vsub->msisdn));
402 DEBUGP(DVLR, "set MSISDN on subscriber; IMSI=%s MSISDN=%s\n",
403 vsub->imsi, vsub->msisdn);
404}
405
406bool vlr_subscr_matches_imsi(struct vlr_subscr *vsub, const char *imsi)
407{
408 return vsub && imsi && vsub->imsi[0] && !strcmp(vsub->imsi, imsi);
409}
410
411bool vlr_subscr_matches_tmsi(struct vlr_subscr *vsub, uint32_t tmsi)
412{
413 return vsub && tmsi != GSM_RESERVED_TMSI
414 && (vsub->tmsi == tmsi || vsub->tmsi_new == tmsi);
415}
416
417bool vlr_subscr_matches_msisdn(struct vlr_subscr *vsub, const char *msisdn)
418{
419 return vsub && msisdn && vsub->msisdn[0]
420 && !strcmp(vsub->msisdn, msisdn);
421}
422
423bool vlr_subscr_matches_imei(struct vlr_subscr *vsub, const char *imei)
424{
425 return vsub && imei && vsub->imei[0]
426 && !strcmp(vsub->imei, imei);
427}
428
429/* Send updated subscriber information to HLR */
430int vlr_subscr_changed(struct vlr_subscr *vsub)
431{
432 /* FIXME */
433 LOGP(DVLR, LOGL_ERROR, "Not implemented: %s\n", __func__);
434 return 0;
435}
436
437/***********************************************************************
438 * PDP context data
439 ***********************************************************************/
440
441struct sgsn_subscriber_pdp_data *
442vlr_subscr_pdp_data_alloc(struct vlr_subscr *vsub)
443{
444 struct sgsn_subscriber_pdp_data* pdata;
445
446 pdata = talloc_zero(vsub, struct sgsn_subscriber_pdp_data);
447
448 llist_add_tail(&pdata->list, &vsub->ps.pdp_list);
449
450 return pdata;
451}
452
453static int vlr_subscr_pdp_data_clear(struct vlr_subscr *vsub)
454{
455 struct sgsn_subscriber_pdp_data *pdp, *pdp2;
456 int count = 0;
457
458 llist_for_each_entry_safe(pdp, pdp2, &vsub->ps.pdp_list, list) {
459 llist_del(&pdp->list);
460 talloc_free(pdp);
461 count += 1;
462 }
463
464 return count;
465}
466
467static struct sgsn_subscriber_pdp_data *
468vlr_subscr_pdp_data_get_by_id(struct vlr_subscr *vsub, unsigned context_id)
469{
470 struct sgsn_subscriber_pdp_data *pdp;
471
472 llist_for_each_entry(pdp, &vsub->ps.pdp_list, list) {
473 if (pdp->context_id == context_id)
474 return pdp;
475 }
476
477 return NULL;
478}
479
480/***********************************************************************
481 * Actual Implementation
482 ***********************************************************************/
483
484static int vlr_rx_gsup_unknown_imsi(struct vlr_instance *vlr,
485 struct osmo_gsup_message *gsup_msg)
486{
487 if (OSMO_GSUP_IS_MSGT_REQUEST(gsup_msg->message_type)) {
488 vlr_tx_gsup_error_reply(vlr, gsup_msg,
489 GMM_CAUSE_IMSI_UNKNOWN);
490 LOGP(DVLR, LOGL_NOTICE,
491 "Unknown IMSI %s, discarding GSUP request "
492 "of type 0x%02x\n",
493 gsup_msg->imsi, gsup_msg->message_type);
494 } else if (OSMO_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
495 LOGP(DVLR, LOGL_NOTICE,
496 "Unknown IMSI %s, discarding GSUP error "
497 "of type 0x%02x, cause '%s' (%d)\n",
498 gsup_msg->imsi, gsup_msg->message_type,
499 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
500 gsup_msg->cause);
501 } else {
502 LOGP(DVLR, LOGL_NOTICE,
503 "Unknown IMSI %s, discarding GSUP response "
504 "of type 0x%02x\n",
505 gsup_msg->imsi, gsup_msg->message_type);
506 }
507
508 return -GMM_CAUSE_IMSI_UNKNOWN;
509}
510
511static int vlr_rx_gsup_purge_no_subscr(struct vlr_instance *vlr,
512 struct osmo_gsup_message *gsup_msg)
513{
514 if (OSMO_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
515 LOGGSUPP(LOGL_NOTICE, gsup_msg,
516 "Purge MS has failed with cause '%s' (%d)\n",
517 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
518 gsup_msg->cause);
519 return -gsup_msg->cause;
520 }
521 LOGGSUPP(LOGL_INFO, gsup_msg, "Completing purge MS\n");
522 return 0;
523}
524
525/* VLR internal call to request UpdateLocation from HLR */
526int vlr_subscr_req_lu(struct vlr_subscr *vsub, bool is_ps)
527{
528 struct osmo_gsup_message gsup_msg = {0};
529 int rc;
530
531 gsup_msg.message_type = OSMO_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
532 rc = vlr_subscr_tx_gsup_message(vsub, &gsup_msg);
533
534 return rc;
535}
536
537/* VLR internal call to request tuples from HLR */
538int vlr_subscr_req_sai(struct vlr_subscr *vsub,
539 const uint8_t *auts, const uint8_t *auts_rand)
540{
541 struct osmo_gsup_message gsup_msg = {0};
542
543 gsup_msg.message_type = OSMO_GSUP_MSGT_SEND_AUTH_INFO_REQUEST;
544 gsup_msg.auts = auts;
545 gsup_msg.rand = auts_rand;
546
547 return vlr_subscr_tx_gsup_message(vsub, &gsup_msg);
548}
549
550/* Tell HLR that authentication failure occurred */
551int vlr_subscr_tx_auth_fail_rep(struct vlr_subscr *vsub)
552{
553 struct osmo_gsup_message gsup_msg = {0};
554
555 gsup_msg.message_type = OSMO_GSUP_MSGT_AUTH_FAIL_REPORT;
556 osmo_strlcpy(gsup_msg.imsi, vsub->imsi, sizeof(gsup_msg.imsi));
557 return vlr_tx_gsup_message(vsub->vlr, &gsup_msg);
558}
559
560/* Update the subscriber with GSUP-received auth tuples */
561void vlr_subscr_update_tuples(struct vlr_subscr *vsub,
562 const struct osmo_gsup_message *gsup)
563{
564 unsigned int i;
565 unsigned int got_tuples;
566
567 if (gsup->num_auth_vectors) {
568 memset(&vsub->auth_tuples, 0, sizeof(vsub->auth_tuples));
569 for (i = 0; i < ARRAY_SIZE(vsub->auth_tuples); i++)
570 vsub->auth_tuples[i].key_seq = GSM_KEY_SEQ_INVAL;
571 }
572
573 got_tuples = 0;
574 for (i = 0; i < gsup->num_auth_vectors; i++) {
575 size_t key_seq = i;
576
577 if (key_seq >= ARRAY_SIZE(vsub->auth_tuples)) {
578 LOGVSUBP(LOGL_NOTICE, vsub,
579 "Skipping auth tuple wih invalid cksn %zu\n",
580 key_seq);
581 continue;
582 }
583 vsub->auth_tuples[i].vec = gsup->auth_vectors[i];
584 vsub->auth_tuples[i].key_seq = key_seq;
585 got_tuples ++;
586 }
587
588 LOGVSUBP(LOGL_DEBUG, vsub, "Received %u auth tuples\n", got_tuples);
589
590 if (!got_tuples) {
591 /* FIXME what now? */
592 // vlr_subscr_cancel(vsub, GMM_CAUSE_GSM_AUTH_UNACCEPT); ?
593 }
594
595 /* New tuples means last_tuple becomes invalid */
596 vsub->last_tuple = NULL;
597}
598
599/* Handle SendAuthInfo Result/Error from HLR */
600static int vlr_subscr_handle_sai_res(struct vlr_subscr *vsub,
601 const struct osmo_gsup_message *gsup)
602{
603 struct osmo_fsm_inst *auth_fi = vsub->auth_fsm;
604 void *data = (void *) gsup;
605
606 switch (gsup->message_type) {
607 case OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
608 osmo_fsm_inst_dispatch(auth_fi, VLR_AUTH_E_HLR_SAI_ACK, data);
609 break;
610 case OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
611 osmo_fsm_inst_dispatch(auth_fi, VLR_AUTH_E_HLR_SAI_NACK, data);
612 break;
613 default:
614 return -1;
615 }
616
617 return 0;
618}
619
620static int decode_bcd_number_safe(char *output, int output_len,
621 const uint8_t *bcd_lv, int input_len,
622 int h_len)
623{
624 uint8_t len;
625 OSMO_ASSERT(output_len >= 1);
626 *output = '\0';
627 if (input_len < 1)
628 return -EIO;
629 len = bcd_lv[0];
630 if (input_len < len)
631 return -EIO;
632 return gsm48_decode_bcd_number(output, output_len, bcd_lv, h_len);
633}
634
635static void vlr_subscr_gsup_insert_data(struct vlr_subscr *vsub,
636 const struct osmo_gsup_message *gsup_msg)
637{
638 unsigned idx;
639 int rc;
640
641 if (gsup_msg->msisdn_enc) {
642 decode_bcd_number_safe(vsub->msisdn, sizeof(vsub->msisdn),
643 gsup_msg->msisdn_enc,
644 gsup_msg->msisdn_enc_len, 0);
645 LOGP(DVLR, LOGL_DEBUG, "IMSI:%s has MSISDN:%s\n",
646 vsub->imsi, vsub->msisdn);
647 }
648
649 if (gsup_msg->hlr_enc) {
650 if (gsup_msg->hlr_enc_len > sizeof(vsub->hlr.buf)) {
651 LOGP(DVLR, LOGL_ERROR, "HLR-Number too long (%zu)\n",
652 gsup_msg->hlr_enc_len);
653 vsub->hlr.len = 0;
654 } else {
655 memcpy(vsub->hlr.buf, gsup_msg->hlr_enc,
656 gsup_msg->hlr_enc_len);
657 vsub->hlr.len = gsup_msg->hlr_enc_len;
658 }
659 }
660
661 if (gsup_msg->pdp_info_compl) {
662 rc = vlr_subscr_pdp_data_clear(vsub);
663 if (rc > 0)
664 LOGP(DVLR, LOGL_INFO, "Cleared existing PDP info\n");
665 }
666
667 for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) {
668 const struct osmo_gsup_pdp_info *pdp_info = &gsup_msg->pdp_infos[idx];
669 size_t ctx_id = pdp_info->context_id;
670 struct sgsn_subscriber_pdp_data *pdp_data;
671
672 if (pdp_info->apn_enc_len >= sizeof(pdp_data->apn_str)-1) {
673 LOGVSUBP(LOGL_ERROR, vsub,
674 "APN too long, context id = %zu, APN = %s\n",
675 ctx_id, osmo_hexdump(pdp_info->apn_enc,
676 pdp_info->apn_enc_len));
677 continue;
678 }
679
680 if (pdp_info->qos_enc_len > sizeof(pdp_data->qos_subscribed)) {
681 LOGVSUBP(LOGL_ERROR, vsub,
682 "QoS info too long (%zu)\n",
683 pdp_info->qos_enc_len);
684 continue;
685 }
686
687 LOGVSUBP(LOGL_INFO, vsub,
688 "Will set PDP info, context id = %zu, APN = %s\n",
689 ctx_id, osmo_hexdump(pdp_info->apn_enc, pdp_info->apn_enc_len));
690
691 /* Set PDP info [ctx_id] */
692 pdp_data = vlr_subscr_pdp_data_get_by_id(vsub, ctx_id);
693 if (!pdp_data) {
694 pdp_data = vlr_subscr_pdp_data_alloc(vsub);
695 pdp_data->context_id = ctx_id;
696 }
697
698 OSMO_ASSERT(pdp_data != NULL);
699 pdp_data->pdp_type = pdp_info->pdp_type;
700 osmo_apn_to_str(pdp_data->apn_str,
701 pdp_info->apn_enc, pdp_info->apn_enc_len);
702 memcpy(pdp_data->qos_subscribed, pdp_info->qos_enc, pdp_info->qos_enc_len);
703 pdp_data->qos_subscribed_len = pdp_info->qos_enc_len;
704 }
705}
706
707
708/* Handle InsertSubscrData Result from HLR */
709static int vlr_subscr_handle_isd_req(struct vlr_subscr *vsub,
710 const struct osmo_gsup_message *gsup)
711{
712 struct osmo_gsup_message gsup_reply = {0};
713
714 vlr_subscr_gsup_insert_data(vsub, gsup);
715 vsub->vlr->ops.subscr_update(vsub);
716
717 gsup_reply.message_type = OSMO_GSUP_MSGT_INSERT_DATA_RESULT;
718 return vlr_subscr_tx_gsup_message(vsub, &gsup_reply);
719}
720
721/* Handle UpdateLocation Result from HLR */
722static int vlr_subscr_handle_lu_res(struct vlr_subscr *vsub,
723 const struct osmo_gsup_message *gsup)
724{
725 if (!vsub->lu_fsm) {
726 LOGVSUBP(LOGL_ERROR, vsub, "Rx GSUP LU Result "
727 "without LU in progress\n");
728 return -ENODEV;
729 }
730
731 /* contrary to MAP, we allow piggy-backing subscriber data onto the
732 * UPDATE LOCATION RESULT, and don't mandate the use of a separate
733 * nested INSERT SUBSCRIBER DATA transaction */
734 vlr_subscr_gsup_insert_data(vsub, gsup);
735
736 osmo_fsm_inst_dispatch(vsub->lu_fsm, VLR_ULA_E_HLR_LU_RES, NULL);
737
738 return 0;
739}
740
741/* Handle UpdateLocation Result from HLR */
742static int vlr_subscr_handle_lu_err(struct vlr_subscr *vsub,
743 const struct osmo_gsup_message *gsup)
744{
745 if (!vsub->lu_fsm) {
746 LOGVSUBP(LOGL_ERROR, vsub, "Rx GSUP LU Error "
747 "without LU in progress\n");
748 return -ENODEV;
749 }
750
751 LOGVSUBP(LOGL_DEBUG, vsub, "UpdateLocation failed; gmm_cause: %s\n",
752 get_value_string(gsm48_gmm_cause_names, gsup->cause));
753
754 osmo_fsm_inst_dispatch(vsub->lu_fsm, VLR_ULA_E_HLR_LU_RES,
755 (void *)&gsup->cause);
756
757 return 0;
758}
759
760/* Handle LOCATION CANCEL request from HLR */
761static int vlr_subscr_handle_cancel_req(struct vlr_subscr *vsub,
762 struct osmo_gsup_message *gsup_msg)
763{
764 struct osmo_gsup_message gsup_reply = {0};
765 int is_update_procedure = !gsup_msg->cancel_type ||
766 gsup_msg->cancel_type == OSMO_GSUP_CANCEL_TYPE_UPDATE;
767
768 LOGVSUBP(LOGL_INFO, vsub, "Cancelling MS subscriber (%s)\n",
769 is_update_procedure ?
770 "update procedure" : "subscription withdraw");
771
772 gsup_reply.message_type = OSMO_GSUP_MSGT_LOCATION_CANCEL_RESULT;
773 vlr_subscr_tx_gsup_message(vsub, &gsup_reply);
774
775 vlr_subscr_cancel(vsub, gsup_msg->cause);
776
777 return 0;
778}
779
780/* Incoming handler for GSUP from HLR.
781 * Keep this function non-static for direct invocation by unit tests. */
782int vlr_gsupc_read_cb(struct gsup_client *gsupc, struct msgb *msg)
783{
784 struct vlr_instance *vlr = (struct vlr_instance *) gsupc->data;
785 struct vlr_subscr *vsub;
786 struct osmo_gsup_message gsup;
787 int rc;
788
789 DEBUGP(DVLR, "GSUP rx %u: %s\n", msgb_l2len(msg),
790 osmo_hexdump_nospc(msgb_l2(msg), msgb_l2len(msg)));
791
792 rc = osmo_gsup_decode(msgb_l2(msg), msgb_l2len(msg), &gsup);
793 if (rc < 0) {
794 LOGP(DVLR, LOGL_ERROR,
795 "decoding GSUP message fails with error '%s' (%d)\n",
796 get_value_string(gsm48_gmm_cause_names, -rc), -rc);
797 return rc;
798 }
799
800 if (!gsup.imsi[0]) {
801 LOGP(DVLR, LOGL_ERROR, "Missing IMSI in GSUP message\n");
802 if (OSMO_GSUP_IS_MSGT_REQUEST(gsup.message_type))
803 vlr_tx_gsup_error_reply(vlr, &gsup,
804 GMM_CAUSE_INV_MAND_INFO);
805 return -GMM_CAUSE_INV_MAND_INFO;
806 }
807
808 vsub = vlr_subscr_find_by_imsi(vlr, gsup.imsi);
809 if (!vsub) {
810 switch (gsup.message_type) {
811 case OSMO_GSUP_MSGT_PURGE_MS_RESULT:
812 case OSMO_GSUP_MSGT_PURGE_MS_ERROR:
813 return vlr_rx_gsup_purge_no_subscr(vlr, &gsup);
814 default:
815 return vlr_rx_gsup_unknown_imsi(vlr, &gsup);
816 }
817 }
818
819 switch (gsup.message_type) {
820 case OSMO_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
821 case OSMO_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
822 rc = vlr_subscr_handle_sai_res(vsub, &gsup);
823 break;
824 case OSMO_GSUP_MSGT_INSERT_DATA_REQUEST:
825 rc = vlr_subscr_handle_isd_req(vsub, &gsup);
826 break;
827 case OSMO_GSUP_MSGT_LOCATION_CANCEL_REQUEST:
828 rc = vlr_subscr_handle_cancel_req(vsub, &gsup);
829 break;
830 case OSMO_GSUP_MSGT_UPDATE_LOCATION_RESULT:
831 rc = vlr_subscr_handle_lu_res(vsub, &gsup);
832 break;
833 case OSMO_GSUP_MSGT_UPDATE_LOCATION_ERROR:
834 rc = vlr_subscr_handle_lu_err(vsub, &gsup);
835 break;
836 case OSMO_GSUP_MSGT_PURGE_MS_ERROR:
837 case OSMO_GSUP_MSGT_PURGE_MS_RESULT:
838 case OSMO_GSUP_MSGT_DELETE_DATA_REQUEST:
839 LOGVSUBP(LOGL_ERROR, vsub,
840 "Rx GSUP msg_type=%d not yet implemented\n",
841 gsup.message_type);
842 rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
843 break;
844 default:
845 LOGVSUBP(LOGL_ERROR, vsub,
846 "Rx GSUP msg_type=%d not valid at VLR/SGSN side\n",
847 gsup.message_type);
848 rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
849 break;
850 }
851
852 vlr_subscr_put(vsub);
853 return rc;
854}
855
856/* MSC->VLR: Subscriber has provided IDENTITY RESPONSE */
857int vlr_subscr_rx_id_resp(struct vlr_subscr *vsub,
858 const uint8_t *mi, size_t mi_len)
859{
860 char mi_string[GSM48_MI_SIZE];
861 uint8_t mi_type = mi[0] & GSM_MI_TYPE_MASK;
862
863 gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
864
865 /* update the vlr_subscr with the given identity */
866 switch (mi_type) {
867 case GSM_MI_TYPE_IMSI:
868 if (vsub->imsi[0]
869 && !vlr_subscr_matches_imsi(vsub, mi_string)) {
870 LOGVSUBP(LOGL_ERROR, vsub, "IMSI in ID RESP differs:"
871 " %s\n", mi_string);
872 } else
873 vlr_subscr_set_imsi(vsub, mi_string);
874 break;
875 case GSM_MI_TYPE_IMEI:
876 vlr_subscr_set_imei(vsub, mi_string);
877 break;
878 case GSM_MI_TYPE_IMEISV:
879 vlr_subscr_set_imeisv(vsub, mi_string);
880 break;
881 }
882
883 if (vsub->auth_fsm) {
884 switch (mi_type) {
885 case GSM_MI_TYPE_IMSI:
886 osmo_fsm_inst_dispatch(vsub->auth_fsm,
887 VLR_AUTH_E_MS_ID_IMSI, mi_string);
888 break;
889 }
890 }
891
892 if (vsub->lu_fsm) {
893 uint32_t event = 0;
894 switch (mi_type) {
895 case GSM_MI_TYPE_IMSI:
896 event = VLR_ULA_E_ID_IMSI;
897 break;
898 case GSM_MI_TYPE_IMEI:
899 event = VLR_ULA_E_ID_IMEI;
900 break;
901 case GSM_MI_TYPE_IMEISV:
902 event = VLR_ULA_E_ID_IMEISV;
903 break;
904 default:
905 OSMO_ASSERT(0);
906 break;
907 }
908 osmo_fsm_inst_dispatch(vsub->lu_fsm, event, mi_string);
909 } else {
910 LOGVSUBP(LOGL_NOTICE, vsub, "gratuitous ID RESPONSE?!?\n");
911 }
912
913 return 0;
914}
915
916/* MSC->VLR: Subscriber has provided IDENTITY RESPONSE */
917int vlr_subscr_rx_tmsi_reall_compl(struct vlr_subscr *vsub)
918{
919 if (vsub->lu_fsm) {
920 return osmo_fsm_inst_dispatch(vsub->lu_fsm,
921 VLR_ULA_E_NEW_TMSI_ACK, NULL);
922 } else if (vsub->proc_arq_fsm) {
923 return osmo_fsm_inst_dispatch(vsub->proc_arq_fsm,
924 PR_ARQ_E_TMSI_ACK, NULL);
925 } else {
926 LOGVSUBP(LOGL_NOTICE, vsub,
927 "gratuitous TMSI REALLOC COMPL");
928 return -EINVAL;
929 }
930}
931
932int vlr_subscr_rx_imsi_detach(struct vlr_subscr *vsub)
933{
934 /* paranoia: should any LU or PARQ FSMs still be running, stop them. */
935 vlr_subscr_cancel(vsub, GMM_CAUSE_IMPL_DETACHED);
936
937 vsub->imsi_detached_flag = true;
938 if (vsub->lu_complete) {
939 vsub->lu_complete = false;
940 /* balancing the get from vlr_lu_compl_fsm_success() */
941 vlr_subscr_put(vsub);
942 }
943 return 0;
944}
945
946/* Tear down any running FSMs due to MSC connection timeout.
947 * Visit all vsub->*_fsm pointers and give them a queue to send a final reject
948 * message before the entire connection is torn down.
949 * \param[in] vsub subscriber to tear down
950 */
951void vlr_subscr_conn_timeout(struct vlr_subscr *vsub)
952{
953 if (!vsub)
954 return;
955
956 vlr_loc_update_conn_timeout(vsub->lu_fsm);
957 vlr_parq_conn_timeout(vsub->proc_arq_fsm);
958}
959
960struct vlr_instance *vlr_alloc(void *ctx, const struct vlr_ops *ops)
961{
962 struct vlr_instance *vlr = talloc_zero(ctx, struct vlr_instance);
963 OSMO_ASSERT(vlr);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200964
965 /* Some of these are needed only on UTRAN, but in case the caller wants
966 * only GERAN, she should just provide dummy callbacks. */
Harald Welteb8b85a12016-06-17 00:06:42 +0200967 OSMO_ASSERT(ops->tx_auth_req);
968 OSMO_ASSERT(ops->tx_auth_rej);
969 OSMO_ASSERT(ops->tx_id_req);
970 OSMO_ASSERT(ops->tx_lu_acc);
971 OSMO_ASSERT(ops->tx_lu_rej);
972 OSMO_ASSERT(ops->tx_cm_serv_acc);
973 OSMO_ASSERT(ops->tx_cm_serv_rej);
974 OSMO_ASSERT(ops->set_ciph_mode);
Neels Hofmeyr84da6b12016-05-20 21:59:55 +0200975 OSMO_ASSERT(ops->tx_common_id);
Harald Welteb8b85a12016-06-17 00:06:42 +0200976 OSMO_ASSERT(ops->subscr_update);
977 OSMO_ASSERT(ops->subscr_assoc);
978
979 INIT_LLIST_HEAD(&vlr->subscribers);
980 INIT_LLIST_HEAD(&vlr->operations);
981 memcpy(&vlr->ops, ops, sizeof(vlr->ops));
982
983 /* osmo_auth_fsm.c */
984 osmo_fsm_register(&vlr_auth_fsm);
985 /* osmo_lu_fsm.c */
986 vlr_lu_fsm_init();
987 /* vlr_access_request_fsm.c */
988 vlr_parq_fsm_init();
989
990 return vlr;
991}
992
993int vlr_start(const char *gsup_unit_name, struct vlr_instance *vlr,
994 const char *gsup_server_addr_str, uint16_t gsup_server_port)
995{
996 OSMO_ASSERT(vlr);
997
998 vlr->gsup_client = gsup_client_create(gsup_unit_name,
999 gsup_server_addr_str,
1000 gsup_server_port,
1001 &vlr_gsupc_read_cb, NULL);
1002 if (!vlr->gsup_client)
1003 return -ENOMEM;
1004 vlr->gsup_client->data = vlr;
1005
1006 return 0;
1007}
1008
1009/* MSC->VLR: Subscribre has disconnected */
1010int vlr_subscr_disconnected(struct vlr_subscr *vsub)
1011{
1012 /* This corresponds to a MAP-ABORT from MSC->VLR on a classic B
1013 * interface */
1014 osmo_fsm_inst_term(vsub->lu_fsm, OSMO_FSM_TERM_REQUEST, NULL);
1015 osmo_fsm_inst_term(vsub->auth_fsm, OSMO_FSM_TERM_REQUEST, NULL);
1016 vsub->msc_conn_ref = NULL;
1017
1018 return 0;
1019}
1020
1021/* MSC->VLR: Receive Authentication Failure from Subscriber */
1022int vlr_subscr_rx_auth_fail(struct vlr_subscr *vsub, const uint8_t *auts)
1023{
1024 struct vlr_auth_resp_par par = {0};
1025 par.auts = auts;
1026
1027 osmo_fsm_inst_dispatch(vsub->auth_fsm, VLR_AUTH_E_MS_AUTH_FAIL, &par);
1028 return 0;
1029}
1030
1031/* MSC->VLR: Receive Authentication Response from MS
1032 * \returns 1 in case of success, 0 in case of delay, -1 on auth error */
1033int vlr_subscr_rx_auth_resp(struct vlr_subscr *vsub, bool is_r99,
1034 bool is_utran, const uint8_t *res, uint8_t res_len)
1035{
1036 struct osmo_fsm_inst *auth_fi = vsub->auth_fsm;
1037 struct vlr_auth_resp_par par;
1038
1039 par.is_r99 = is_r99;
1040 par.is_utran = is_utran;
1041 par.res = res;
1042 par.res_len = res_len;
1043 osmo_fsm_inst_dispatch(auth_fi, VLR_AUTH_E_MS_AUTH_RESP, (void *) &par);
1044
1045 return 0;
1046}
1047
1048/* MSC->VLR: Receive result of Ciphering Mode Command from MS */
1049void vlr_subscr_rx_ciph_res(struct vlr_subscr *vsub, struct vlr_ciph_result *res)
1050{
1051 if (vsub->lu_fsm && vsub->lu_fsm->state == VLR_ULA_S_WAIT_CIPH)
1052 osmo_fsm_inst_dispatch(vsub->lu_fsm, VLR_ULA_E_CIPH_RES, res);
1053 if (vsub->proc_arq_fsm
1054 && vsub->proc_arq_fsm->state == PR_ARQ_S_WAIT_CIPH)
1055 osmo_fsm_inst_dispatch(vsub->proc_arq_fsm, PR_ARQ_E_CIPH_RES,
1056 res);
1057}
1058
1059/* Internal evaluation of requested ciphering mode.
1060 * Send set_ciph_mode() to MSC depending on the ciph_mode argument.
1061 * \param[in] vlr VLR instance.
1062 * \param[in] fi Calling FSM instance, for logging.
1063 * \param[in] msc_conn_ref MSC conn to send to.
1064 * \param[in] ciph_mode Ciphering config, to decide whether to do ciphering.
1065 * \returns 0 if no ciphering is needed or message was sent successfully,
1066 * or a negative value if ciph_mode is invalid or sending failed.
1067 */
1068int vlr_set_ciph_mode(struct vlr_instance *vlr,
1069 struct osmo_fsm_inst *fi,
1070 void *msc_conn_ref,
1071 enum vlr_ciph ciph_mode,
1072 bool retrieve_imeisv)
1073{
1074 switch (ciph_mode) {
1075 case VLR_CIPH_NONE:
1076 return 0;
1077
1078 case VLR_CIPH_A5_1:
1079 case VLR_CIPH_A5_3:
1080 return vlr->ops.set_ciph_mode(msc_conn_ref,
1081 ciph_mode,
1082 retrieve_imeisv);
1083
1084 case VLR_CIPH_A5_2:
1085 /* TODO policy by user config? */
1086 LOGPFSML(fi, LOGL_ERROR, "A5/2 ciphering is not allowed\n");
1087 return -EINVAL;
1088
1089 default:
1090 LOGPFSML(fi, LOGL_ERROR, "unknown ciphering value: %d\n",
1091 ciph_mode);
1092 return -EINVAL;
1093 }
1094}
1095
1096void log_set_filter_vlr_subscr(struct log_target *target,
1097 struct vlr_subscr *vlr_subscr)
1098{
1099 struct vlr_subscr **fsub = (void*)&target->filter_data[LOG_FLT_VLR_SUBSCR];
1100
1101 /* free the old data */
1102 if (*fsub) {
1103 vlr_subscr_put(*fsub);
1104 *fsub = NULL;
1105 }
1106
1107 if (vlr_subscr) {
1108 target->filter_map |= (1 << LOG_FLT_VLR_SUBSCR);
1109 *fsub = vlr_subscr_get(vlr_subscr);
1110 } else
1111 target->filter_map &= ~(1 << LOG_FLT_VLR_SUBSCR);
1112}