blob: 24603403dd1ab070fd194deca988f08d537ad7c5 [file] [log] [blame]
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +01001/* MS subscriber data handling */
2
3/* (C) 2014 by sysmocom s.f.m.c. GmbH
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 <openbsc/gsm_subscriber.h>
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010023#include <openbsc/gprs_gsup_client.h>
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010024
25#include <openbsc/sgsn.h>
26#include <openbsc/gprs_sgsn.h>
27#include <openbsc/gprs_gmm.h>
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +010028#include <openbsc/gprs_gsup_messages.h>
Jacob Erlbeck0e8add62014-12-17 14:03:35 +010029#include <openbsc/gprs_utils.h>
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010030
31#include <openbsc/debug.h>
32
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010033#include <netinet/in.h>
34#include <arpa/inet.h>
35
Jacob Erlbeck743dec42015-01-08 15:18:39 +010036#define SGSN_SUBSCR_MAX_RETRIES 3
37#define SGSN_SUBSCR_RETRY_INTERVAL 10
38
Jacob Erlbeck929acdf2015-01-27 13:47:24 +010039#define LOGGSUPP(level, gsup, fmt, args...) \
40 LOGP(DGPRS, level, "GSUP(%s) " fmt, \
41 (gsup)->imsi, \
42 ## args)
43
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010044extern void *tall_bsc_ctx;
45
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010046static int gsup_read_cb(struct gprs_gsup_client *gsupc, struct msgb *msg);
47
48/* TODO: Some functions are specific to the SGSN, but this file is more general
49 * (it has gprs_* name). Either move these functions elsewhere, split them and
50 * move a part, or replace the gprs_ prefix by sgsn_. The applies to
51 * gprs_subscr_init, gsup_read_cb, and gprs_subscr_tx_gsup_message.
52 */
53
54int gprs_subscr_init(struct sgsn_instance *sgi)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010055{
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010056 const char *addr_str;
57
58 if (!sgi->cfg.gsup_server_addr.sin_addr.s_addr)
59 return 0;
60
61 addr_str = inet_ntoa(sgi->cfg.gsup_server_addr.sin_addr);
62
63 sgi->gsup_client = gprs_gsup_client_create(
64 addr_str, sgi->cfg.gsup_server_port,
65 &gsup_read_cb);
66
67 if (!sgi->gsup_client)
68 return -1;
69
70 return 1;
71}
72
73static int gsup_read_cb(struct gprs_gsup_client *gsupc, struct msgb *msg)
74{
75 int rc;
76
77 rc = gprs_subscr_rx_gsup_message(msg);
Jacob Erlbecke154d8b2014-12-19 19:15:55 +010078 msgb_free(msg);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010079 if (rc < 0)
80 return -1;
81
82 return rc;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010083}
84
Jacob Erlbeckf81cacc2015-01-08 16:23:25 +010085static int check_blocking(
86 struct gsm_subscriber *subscr,
87 enum sgsn_subscriber_proc what)
88{
89 if (subscr->sgsn_data->blocked_by == SGSN_SUBSCR_PROC_NONE ||
90 subscr->sgsn_data->blocked_by == what)
91 return 1;
92
93 return 0;
94}
95
96static void abort_blocking_procedure(struct gsm_subscriber *subscr)
97{
Holger Hans Peter Freyther1d778fd2015-01-20 21:14:03 +010098 /* reset something */
Jacob Erlbeckf81cacc2015-01-08 16:23:25 +010099}
100
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +0100101int gprs_subscr_purge(struct gsm_subscriber *subscr);
102
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100103static struct sgsn_subscriber_data *sgsn_subscriber_data_alloc(void *ctx)
104{
105 struct sgsn_subscriber_data *sdata;
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100106 int idx;
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100107
108 sdata = talloc_zero(ctx, struct sgsn_subscriber_data);
109
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100110 sdata->error_cause = SGSN_ERROR_CAUSE_NONE;
111
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100112 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
113 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
114
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100115 INIT_LLIST_HEAD(&sdata->pdp_list);
116
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100117 return sdata;
118}
119
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100120struct sgsn_subscriber_pdp_data* sgsn_subscriber_pdp_data_alloc(
121 struct sgsn_subscriber_data *sdata)
122{
123 struct sgsn_subscriber_pdp_data* pdata;
124
125 pdata = talloc_zero(sdata, struct sgsn_subscriber_pdp_data);
126
127 llist_add_tail(&pdata->list, &sdata->pdp_list);
128
129 return pdata;
130}
131
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100132struct gsm_subscriber *gprs_subscr_get_or_create(const char *imsi)
133{
134 struct gsm_subscriber *subscr;
135
136 subscr = subscr_get_or_create(NULL, imsi);
137 if (!subscr)
138 return NULL;
139
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100140 if (!subscr->sgsn_data)
141 subscr->sgsn_data = sgsn_subscriber_data_alloc(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100142 return subscr;
143}
144
145struct gsm_subscriber *gprs_subscr_get_by_imsi(const char *imsi)
146{
147 return subscr_active_by_imsi(NULL, imsi);
148}
149
Jacob Erlbeck3e4e58f2015-01-26 11:07:24 +0100150void gprs_subscr_cleanup(struct gsm_subscriber *subscr)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100151{
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100152 if (subscr->sgsn_data->mm) {
153 subscr_put(subscr->sgsn_data->mm->subscr);
154 subscr->sgsn_data->mm->subscr = NULL;
155 subscr->sgsn_data->mm = NULL;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100156 }
157
Holger Hans Peter Freyther1d778fd2015-01-20 21:14:03 +0100158 if (subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE) {
159 gprs_subscr_purge(subscr);
160 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +0100161 }
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100162}
163
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100164void gprs_subscr_cancel(struct gsm_subscriber *subscr)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100165{
166 subscr->authorized = 0;
167 subscr->flags |= GPRS_SUBSCRIBER_CANCELLED;
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100168 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100169
170 gprs_subscr_update(subscr);
Jacob Erlbeck3e4e58f2015-01-26 11:07:24 +0100171 gprs_subscr_cleanup(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100172}
173
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100174static int gprs_subscr_tx_gsup_message(struct gsm_subscriber *subscr,
175 struct gprs_gsup_message *gsup_msg)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100176{
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100177 struct msgb *msg = gprs_gsup_msgb_alloc();
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100178
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100179 if (strlen(gsup_msg->imsi) == 0 && subscr)
180 strncpy(gsup_msg->imsi, subscr->imsi, sizeof(gsup_msg->imsi) - 1);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100181
182 gprs_gsup_encode(msg, gsup_msg);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100183
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100184 LOGGSUBSCRP(LOGL_INFO, subscr,
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100185 "Sending GSUP, will send: %s\n", msgb_hexdump(msg));
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100186
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100187 if (!sgsn->gsup_client) {
188 msgb_free(msg);
189 return -ENOTSUP;
190 }
191
192 return gprs_gsup_client_send(sgsn->gsup_client, msg);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100193}
194
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100195static int gprs_subscr_tx_gsup_error_reply(struct gsm_subscriber *subscr,
196 struct gprs_gsup_message *gsup_orig,
197 enum gsm48_gmm_cause cause)
198{
199 struct gprs_gsup_message gsup_reply = {0};
200
201 strncpy(gsup_reply.imsi, gsup_orig->imsi, sizeof(gsup_reply.imsi) - 1);
202 gsup_reply.cause = cause;
203 gsup_reply.message_type =
204 GPRS_GSUP_TO_MSGT_ERROR(gsup_orig->message_type);
205
206 return gprs_subscr_tx_gsup_message(subscr, &gsup_reply);
207}
208
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100209static int gprs_subscr_handle_gsup_auth_res(struct gsm_subscriber *subscr,
210 struct gprs_gsup_message *gsup_msg)
211{
212 unsigned idx;
213 struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
214
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100215 LOGGSUBSCRP(LOGL_INFO, subscr,
216 "Got SendAuthenticationInfoResult, num_auth_tuples = %d\n",
217 gsup_msg->num_auth_tuples);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100218
219 if (gsup_msg->num_auth_tuples > 0) {
220 memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
221
222 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
223 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
224 }
225
226 for (idx = 0; idx < gsup_msg->num_auth_tuples; idx++) {
227 size_t key_seq = gsup_msg->auth_tuples[idx].key_seq;
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100228 LOGGSUBSCRP(LOGL_DEBUG, subscr,
229 "Adding auth tuple, cksn = %d\n", key_seq);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100230 if (key_seq >= ARRAY_SIZE(sdata->auth_triplets)) {
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100231 LOGGSUBSCRP(LOGL_NOTICE, subscr,
232 "Skipping auth triplet with invalid cksn %d\n",
233 key_seq);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100234 continue;
235 }
236 sdata->auth_triplets[key_seq] = gsup_msg->auth_tuples[idx];
237 }
238
239 sdata->auth_triplets_updated = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100240 sdata->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100241
242 gprs_subscr_update_auth_info(subscr);
243
244 return 0;
245}
246
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100247static int gprs_subscr_pdp_data_clear(struct gsm_subscriber *subscr)
248{
249 struct sgsn_subscriber_pdp_data *pdp, *pdp2;
250 int count = 0;
251
252 llist_for_each_entry_safe(pdp, pdp2, &subscr->sgsn_data->pdp_list, list) {
253 llist_del(&pdp->list);
254 talloc_free(pdp);
255 count += 1;
256 }
257
258 return count;
259}
260
261static struct sgsn_subscriber_pdp_data *gprs_subscr_pdp_data_get_by_id(
262 struct gsm_subscriber *subscr, unsigned context_id)
263{
264 struct sgsn_subscriber_pdp_data *pdp;
265
266 llist_for_each_entry(pdp, &subscr->sgsn_data->pdp_list, list) {
267 if (pdp->context_id == context_id)
268 return pdp;
269 }
270
271 return NULL;
272}
273
274
275static void gprs_subscr_gsup_insert_data(struct gsm_subscriber *subscr,
276 struct gprs_gsup_message *gsup_msg)
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100277{
278 unsigned idx;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100279 int rc;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100280
281 if (gsup_msg->pdp_info_compl) {
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100282 rc = gprs_subscr_pdp_data_clear(subscr);
283 if (rc > 0)
284 LOGP(DGPRS, LOGL_INFO, "Cleared existing PDP info\n");
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100285 }
286
287 for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) {
288 struct gprs_gsup_pdp_info *pdp_info = &gsup_msg->pdp_infos[idx];
289 size_t ctx_id = pdp_info->context_id;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100290 struct sgsn_subscriber_pdp_data *pdp_data;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100291
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100292 if (pdp_info->apn_enc_len >= sizeof(pdp_data->apn_str)-1) {
293 LOGGSUBSCRP(LOGL_ERROR, subscr,
294 "APN too long, context id = %d, APN = %s\n",
295 ctx_id, osmo_hexdump(pdp_info->apn_enc,
296 pdp_info->apn_enc_len));
297 continue;
298 }
299
300 LOGGSUBSCRP(LOGL_INFO, subscr,
301 "Will set PDP info, context id = %d, APN = %s\n",
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100302 ctx_id, osmo_hexdump(pdp_info->apn_enc, pdp_info->apn_enc_len));
303
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100304 /* Set PDP info [ctx_id] */
305 pdp_data = gprs_subscr_pdp_data_get_by_id(subscr, ctx_id);
306 if (!pdp_data) {
307 pdp_data = sgsn_subscriber_pdp_data_alloc(subscr->sgsn_data);
308 pdp_data->context_id = ctx_id;
309 }
310
311 OSMO_ASSERT(pdp_data != NULL);
312 pdp_data->pdp_type = pdp_info->pdp_type;
313 gprs_apn_to_str(pdp_data->apn_str,
314 pdp_info->apn_enc, pdp_info->apn_enc_len);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100315 }
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100316}
317
318static int gprs_subscr_handle_gsup_upd_loc_res(struct gsm_subscriber *subscr,
319 struct gprs_gsup_message *gsup_msg)
320{
321 gprs_subscr_gsup_insert_data(subscr, gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100322
323 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100324 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100325
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100326 subscr->flags |= GPRS_SUBSCRIBER_ENABLE_PURGE;
327
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100328 gprs_subscr_update(subscr);
329 return 0;
330}
331
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100332static int check_cause(int cause)
333{
334 switch (cause) {
335 case GMM_CAUSE_IMSI_UNKNOWN ... GMM_CAUSE_ILLEGAL_ME:
336 case GMM_CAUSE_GPRS_NOTALLOWED ... GMM_CAUSE_NO_GPRS_PLMN:
337 return EACCES;
338
339 case GMM_CAUSE_MSC_TEMP_NOTREACH ... GMM_CAUSE_CONGESTION:
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100340 return EHOSTUNREACH;
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100341
342 case GMM_CAUSE_SEM_INCORR_MSG ... GMM_CAUSE_PROTO_ERR_UNSPEC:
343 default:
344 return EINVAL;
345 }
346}
347
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100348static int gprs_subscr_handle_gsup_auth_err(struct gsm_subscriber *subscr,
349 struct gprs_gsup_message *gsup_msg)
350{
351 unsigned idx;
352 struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100353 int cause_err;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100354
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100355 cause_err = check_cause(gsup_msg->cause);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100356
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100357 LOGGSUBSCRP(LOGL_DEBUG, subscr,
358 "Send authentication info has failed with cause %d, "
359 "handled as: %s\n",
360 gsup_msg->cause, strerror(cause_err));
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100361
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100362 switch (cause_err) {
363 case EACCES:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100364 LOGGSUBSCRP(LOGL_NOTICE, subscr,
365 "GPRS send auth info req failed, access denied, "
366 "GMM cause = '%s' (%d)\n",
367 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
368 gsup_msg->cause);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100369 /* Clear auth tuples */
370 memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
371 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
372 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100373
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100374 subscr->authorized = 0;
375 sdata->error_cause = gsup_msg->cause;
376 gprs_subscr_update_auth_info(subscr);
377 break;
378
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100379 case EHOSTUNREACH:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100380 LOGGSUBSCRP(LOGL_NOTICE, subscr,
381 "GPRS send auth info req failed, GMM cause = '%s' (%d)\n",
382 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
383 gsup_msg->cause);
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100384
385 sdata->error_cause = gsup_msg->cause;
386 gprs_subscr_update_auth_info(subscr);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100387 break;
388
389 default:
390 case EINVAL:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100391 LOGGSUBSCRP(LOGL_ERROR, subscr,
392 "GSUP protocol remote error, GMM cause = '%s' (%d)\n",
393 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
394 gsup_msg->cause);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100395 break;
396 }
397
398 return -gsup_msg->cause;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100399}
400
401static int gprs_subscr_handle_gsup_upd_loc_err(struct gsm_subscriber *subscr,
402 struct gprs_gsup_message *gsup_msg)
403{
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100404 int cause_err;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100405
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100406 cause_err = check_cause(gsup_msg->cause);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100407
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100408 LOGGSUBSCRP(LOGL_DEBUG, subscr,
409 "Update location has failed with cause %d, handled as: %s\n",
410 gsup_msg->cause, strerror(cause_err));
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100411
412 switch (cause_err) {
413 case EACCES:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100414 LOGGSUBSCRP(LOGL_NOTICE, subscr,
415 "GPRS update location failed, access denied, "
416 "GMM cause = '%s' (%d)\n",
417 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
418 gsup_msg->cause);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100419
420 subscr->authorized = 0;
421 subscr->sgsn_data->error_cause = gsup_msg->cause;
422 gprs_subscr_update_auth_info(subscr);
423 break;
424
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100425 case EHOSTUNREACH:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100426 LOGGSUBSCRP(LOGL_NOTICE, subscr,
427 "GPRS update location failed, GMM cause = '%s' (%d)\n",
428 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
429 gsup_msg->cause);
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100430
431 subscr->sgsn_data->error_cause = gsup_msg->cause;
432 gprs_subscr_update_auth_info(subscr);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100433 break;
434
435 default:
436 case EINVAL:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100437 LOGGSUBSCRP(LOGL_ERROR, subscr,
438 "GSUP protocol remote error, GMM cause = '%s' (%d)\n",
439 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
440 gsup_msg->cause);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100441 break;
442 }
443
444 return -gsup_msg->cause;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100445}
446
Jacob Erlbeck929acdf2015-01-27 13:47:24 +0100447static int gprs_subscr_handle_gsup_purge_no_subscr(
448 struct gprs_gsup_message *gsup_msg)
449{
450 if (GPRS_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
451 LOGGSUPP(LOGL_NOTICE, gsup_msg,
452 "Purge MS has failed with cause '%s' (%d)\n",
453 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
454 gsup_msg->cause);
455 return -gsup_msg->cause;
456 }
457
458 LOGGSUPP(LOGL_INFO, gsup_msg, "Completing purge MS\n");
459 return 0;
460}
461
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100462static int gprs_subscr_handle_gsup_purge_res(struct gsm_subscriber *subscr,
463 struct gprs_gsup_message *gsup_msg)
464{
465 LOGGSUBSCRP(LOGL_INFO, subscr, "Completing purge MS\n");
466
467 /* Force silent cancellation */
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100468 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100469 gprs_subscr_cancel(subscr);
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100470
471 return 0;
472}
473
474static int gprs_subscr_handle_gsup_purge_err(struct gsm_subscriber *subscr,
475 struct gprs_gsup_message *gsup_msg)
476{
477 LOGGSUBSCRP(LOGL_NOTICE, subscr,
478 "Purge MS has failed with cause '%s' (%d)\n",
479 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
480 gsup_msg->cause);
481
482 /* In GSM 09.02, 19.1.4.4, the text and the SDL diagram imply that
483 * the subscriber data is not removed if the request has failed. On the
484 * other hand, keeping the subscriber data in either error case
485 * (subscriber unknown, syntactical message error, connection error)
486 * doesn't seem to give any advantage, since the data will be restored
487 * on the next Attach Request anyway.
488 * This approach ensures, that the subscriber record will not stick if
489 * an error happens.
490 */
491
492 /* TODO: Check whether this behaviour is acceptable and either just
493 * remove this TODO-notice or change the implementation to not delete
494 * the subscriber data (eventually resetting the ENABLE_PURGE flag and
495 * restarting the expiry timer based on the cause).
496 *
497 * Subscriber Unknown: cancel subscr
498 * Temporary network problems: do nothing (handled by timer based retry)
499 * Message problems (syntax, nyi, ...): cancel subscr (retry won't help)
500 */
501
502 gprs_subscr_handle_gsup_purge_res(subscr, gsup_msg);
503
504 return -gsup_msg->cause;
505}
506
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100507static int gprs_subscr_handle_loc_cancel_req(struct gsm_subscriber *subscr,
508 struct gprs_gsup_message *gsup_msg)
509{
510 struct gprs_gsup_message gsup_reply = {0};
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100511 int is_update_procedure = !gsup_msg->cancel_type || gsup_msg->cancel_type;
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100512
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100513 LOGGSUBSCRP(LOGL_INFO, subscr, "Cancelling MS subscriber (%s)\n",
514 is_update_procedure ?
515 "update procedure" : "subscription withdraw");
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100516
517 gsup_reply.message_type = GPRS_GSUP_MSGT_LOCATION_CANCEL_RESULT;
518 gprs_subscr_tx_gsup_message(subscr, &gsup_reply);
519
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100520 if (is_update_procedure)
521 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
522 else
523 /* Since a withdraw cause is not specified, just abort the
524 * current attachment. The following re-attachment should then
525 * be rejected with a proper cause value.
526 */
527 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
528
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100529 gprs_subscr_cancel(subscr);
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100530
531 return 0;
532}
533
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100534static int gprs_subscr_handle_unknown_imsi(struct gprs_gsup_message *gsup_msg)
535{
536 if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg->message_type)) {
537 gprs_subscr_tx_gsup_error_reply(NULL, gsup_msg,
538 GMM_CAUSE_IMSI_UNKNOWN);
539 LOGP(DGPRS, LOGL_NOTICE,
540 "Unknown IMSI %s, discarding GSUP request "
541 "of type 0x%02x\n",
542 gsup_msg->imsi, gsup_msg->message_type);
543 } else if (GPRS_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
544 LOGP(DGPRS, LOGL_NOTICE,
545 "Unknown IMSI %s, discarding GSUP error "
546 "of type 0x%02x, cause '%s' (%d)\n",
547 gsup_msg->imsi, gsup_msg->message_type,
548 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
549 gsup_msg->cause);
550 } else {
551 LOGP(DGPRS, LOGL_NOTICE,
552 "Unknown IMSI %s, discarding GSUP response "
553 "of type 0x%02x\n",
554 gsup_msg->imsi, gsup_msg->message_type);
555 }
556
557 return -GMM_CAUSE_IMSI_UNKNOWN;
558}
559
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100560int gprs_subscr_rx_gsup_message(struct msgb *msg)
561{
562 uint8_t *data = msgb_l2(msg);
563 size_t data_len = msgb_l2len(msg);
564 int rc = 0;
565
566 struct gprs_gsup_message gsup_msg = {0};
567 struct gsm_subscriber *subscr;
568
569 rc = gprs_gsup_decode(data, data_len, &gsup_msg);
570 if (rc < 0) {
571 LOGP(DGPRS, LOGL_ERROR,
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100572 "decoding GSUP message fails with error '%s' (%d)\n",
573 get_value_string(gsm48_gmm_cause_names, -rc), -rc);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100574 return rc;
575 }
576
Jacob Erlbeck07f6e362015-01-29 14:00:28 +0100577 if (!gsup_msg.imsi[0]) {
578 LOGP(DGPRS, LOGL_ERROR, "Missing IMSI in GSUP message\n");
579
580 if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
581 gprs_subscr_tx_gsup_error_reply(NULL, &gsup_msg,
582 GMM_CAUSE_INV_MAND_INFO);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100583 return -GMM_CAUSE_INV_MAND_INFO;
Jacob Erlbeck07f6e362015-01-29 14:00:28 +0100584 }
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100585
Jacob Erlbeck9ff82892015-01-29 14:17:51 +0100586 if (!gsup_msg.cause && GPRS_GSUP_IS_MSGT_ERROR(gsup_msg.message_type))
587 gsup_msg.cause = GMM_CAUSE_NET_FAIL;
588
Jacob Erlbeck4dedb272015-01-15 17:50:16 +0100589 subscr = gprs_subscr_get_by_imsi(gsup_msg.imsi);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100590
Jacob Erlbeck929acdf2015-01-27 13:47:24 +0100591 if (!subscr) {
592 switch (gsup_msg.message_type) {
593 case GPRS_GSUP_MSGT_PURGE_MS_RESULT:
594 case GPRS_GSUP_MSGT_PURGE_MS_ERROR:
595 return gprs_subscr_handle_gsup_purge_no_subscr(&gsup_msg);
596 default:
597 return gprs_subscr_handle_unknown_imsi(&gsup_msg);
598 }
599 }
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100600
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100601 LOGGSUBSCRP(LOGL_INFO, subscr,
602 "Received GSUP message of type 0x%02x\n", gsup_msg.message_type);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100603
604 switch (gsup_msg.message_type) {
605 case GPRS_GSUP_MSGT_LOCATION_CANCEL_REQUEST:
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100606 rc = gprs_subscr_handle_loc_cancel_req(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100607 break;
608
609 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100610 rc = gprs_subscr_handle_gsup_auth_res(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100611 break;
612
613 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100614 rc = gprs_subscr_handle_gsup_auth_err(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100615 break;
616
617 case GPRS_GSUP_MSGT_UPDATE_LOCATION_RESULT:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100618 rc = gprs_subscr_handle_gsup_upd_loc_res(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100619 break;
620
621 case GPRS_GSUP_MSGT_UPDATE_LOCATION_ERROR:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100622 rc = gprs_subscr_handle_gsup_upd_loc_err(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100623 break;
624
625 case GPRS_GSUP_MSGT_PURGE_MS_ERROR:
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100626 rc = gprs_subscr_handle_gsup_purge_err(subscr, &gsup_msg);
627 break;
628
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100629 case GPRS_GSUP_MSGT_PURGE_MS_RESULT:
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100630 rc = gprs_subscr_handle_gsup_purge_res(subscr, &gsup_msg);
631 break;
632
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100633 case GPRS_GSUP_MSGT_INSERT_DATA_REQUEST:
634 case GPRS_GSUP_MSGT_DELETE_DATA_REQUEST:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100635 LOGGSUBSCRP(LOGL_ERROR, subscr,
636 "Rx GSUP message type %d not yet implemented\n",
637 gsup_msg.message_type);
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100638 gprs_subscr_tx_gsup_error_reply(subscr, &gsup_msg,
639 GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100640 rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
641 break;
642
643 default:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100644 LOGGSUBSCRP(LOGL_ERROR, subscr,
645 "Rx GSUP message type %d not valid at SGSN\n",
646 gsup_msg.message_type);
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100647 if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
648 gprs_subscr_tx_gsup_error_reply(
649 subscr, &gsup_msg, GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
650 rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100651 break;
652 };
653
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100654 subscr_put(subscr);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100655
656 return rc;
657}
658
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100659int gprs_subscr_purge(struct gsm_subscriber *subscr)
660{
661 struct gprs_gsup_message gsup_msg = {0};
Jacob Erlbeckf81cacc2015-01-08 16:23:25 +0100662 int rc;
663
664 if (!check_blocking(subscr, SGSN_SUBSCR_PROC_PURGE)) {
665 LOGGSUBSCRP(
666 LOGL_NOTICE, subscr,
667 "Cannot purge MS subscriber, blocked\n");
668 return -EAGAIN;
669 }
670
671 /* GSM 09.02, 19.4.1.4 requires other MAP requests to be blocked until
672 * this procedure is completed
673 */
674 subscr->sgsn_data->blocked_by = SGSN_SUBSCR_PROC_PURGE;
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100675
676 LOGGSUBSCRP(LOGL_INFO, subscr, "purging MS subscriber\n");
677
678 gsup_msg.message_type = GPRS_GSUP_MSGT_PURGE_MS_REQUEST;
Jacob Erlbeckf81cacc2015-01-08 16:23:25 +0100679 rc = gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
680 if (rc < 0)
681 subscr->sgsn_data->blocked_by = SGSN_SUBSCR_PROC_NONE;
682
683 return rc;
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100684}
685
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100686int gprs_subscr_query_auth_info(struct gsm_subscriber *subscr)
687{
688 struct gprs_gsup_message gsup_msg = {0};
689
Jacob Erlbeckf81cacc2015-01-08 16:23:25 +0100690 if (!check_blocking(subscr, SGSN_SUBSCR_PROC_UPD_AUTH)) {
691 LOGGSUBSCRP(
692 LOGL_NOTICE, subscr,
693 "Cannot start update auth info request procedure, blocked\n");
694 abort_blocking_procedure(subscr);
695 return -EAGAIN;
696 }
697
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100698 LOGGSUBSCRP(LOGL_INFO, subscr,
699 "subscriber auth info is not available\n");
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100700
701 gsup_msg.message_type = GPRS_GSUP_MSGT_SEND_AUTH_INFO_REQUEST;
702 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
703}
704
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100705int gprs_subscr_location_update(struct gsm_subscriber *subscr)
706{
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100707 struct gprs_gsup_message gsup_msg = {0};
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100708
Jacob Erlbeckf81cacc2015-01-08 16:23:25 +0100709 if (!check_blocking(subscr, SGSN_SUBSCR_PROC_UPD_LOC)) {
710 LOGGSUBSCRP(
711 LOGL_NOTICE, subscr,
712 "Cannot start update location procedure, blocked\n");
713 abort_blocking_procedure(subscr);
714 return -EAGAIN;
715 }
716
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100717 LOGGSUBSCRP(LOGL_INFO, subscr,
718 "subscriber data is not available\n");
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100719
720 gsup_msg.message_type = GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
721 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100722}
723
724void gprs_subscr_update(struct gsm_subscriber *subscr)
725{
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100726 LOGGSUBSCRP(LOGL_DEBUG, subscr, "Updating subscriber data\n");
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100727
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100728 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100729 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
730
Jacob Erlbeck555b2e52015-01-26 13:52:42 +0100731 if (subscr->sgsn_data->mm)
732 sgsn_update_subscriber_data(subscr->sgsn_data->mm);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100733}
734
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100735void gprs_subscr_update_auth_info(struct gsm_subscriber *subscr)
736{
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100737 LOGGSUBSCRP(LOGL_DEBUG, subscr,
738 "Updating subscriber authentication info\n");
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100739
740 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
741 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
742
Jacob Erlbeck555b2e52015-01-26 13:52:42 +0100743 if (subscr->sgsn_data->mm)
744 sgsn_update_subscriber_data(subscr->sgsn_data->mm);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100745}
746
747struct gsm_subscriber *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100748{
749 struct gsm_subscriber *subscr = NULL;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100750
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100751 if (mmctx->subscr)
752 return subscr_get(mmctx->subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100753
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100754 if (mmctx->imsi[0])
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100755 subscr = gprs_subscr_get_by_imsi(mmctx->imsi);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100756
757 if (!subscr) {
758 subscr = gprs_subscr_get_or_create(mmctx->imsi);
759 subscr->flags |= GSM_SUBSCRIBER_FIRST_CONTACT;
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100760 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100761 }
762
763 if (strcpy(subscr->equipment.imei, mmctx->imei) != 0) {
764 strncpy(subscr->equipment.imei, mmctx->imei, GSM_IMEI_LENGTH-1);
765 subscr->equipment.imei[GSM_IMEI_LENGTH-1] = 0;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100766 }
767
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100768 if (subscr->lac != mmctx->ra.lac)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100769 subscr->lac = mmctx->ra.lac;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100770
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100771 subscr->sgsn_data->mm = mmctx;
772 mmctx->subscr = subscr_get(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100773
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100774 return subscr;
775}
776
777int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx)
778{
779 struct gsm_subscriber *subscr = NULL;
780 int rc;
781
782 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber data update\n");
783
784 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
785
786 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
787
788 rc = gprs_subscr_location_update(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100789 subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100790 return rc;
791}
792
793int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx)
794{
795 struct gsm_subscriber *subscr = NULL;
796 int rc;
797
798 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber authentication info\n");
799
800 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
801
802 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
803
804 rc = gprs_subscr_query_auth_info(subscr);
805 subscr_put(subscr);
806 return rc;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100807}