blob: e4dda9c46aaae47b8b141810dc7bf563873f1ebd [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 Erlbeck33b6dad2014-11-12 10:12:11 +010029
30#include <openbsc/debug.h>
31
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010032#include <netinet/in.h>
33#include <arpa/inet.h>
34
Jacob Erlbeck743dec42015-01-08 15:18:39 +010035#define SGSN_SUBSCR_MAX_RETRIES 3
36#define SGSN_SUBSCR_RETRY_INTERVAL 10
37
Jacob Erlbeck929acdf2015-01-27 13:47:24 +010038#define LOGGSUPP(level, gsup, fmt, args...) \
39 LOGP(DGPRS, level, "GSUP(%s) " fmt, \
40 (gsup)->imsi, \
41 ## args)
42
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010043extern void *tall_bsc_ctx;
44
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010045static int gsup_read_cb(struct gprs_gsup_client *gsupc, struct msgb *msg);
46
47/* TODO: Some functions are specific to the SGSN, but this file is more general
48 * (it has gprs_* name). Either move these functions elsewhere, split them and
49 * move a part, or replace the gprs_ prefix by sgsn_. The applies to
50 * gprs_subscr_init, gsup_read_cb, and gprs_subscr_tx_gsup_message.
51 */
52
53int gprs_subscr_init(struct sgsn_instance *sgi)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010054{
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010055 const char *addr_str;
56
57 if (!sgi->cfg.gsup_server_addr.sin_addr.s_addr)
58 return 0;
59
60 addr_str = inet_ntoa(sgi->cfg.gsup_server_addr.sin_addr);
61
62 sgi->gsup_client = gprs_gsup_client_create(
63 addr_str, sgi->cfg.gsup_server_port,
64 &gsup_read_cb);
65
66 if (!sgi->gsup_client)
67 return -1;
68
69 return 1;
70}
71
72static int gsup_read_cb(struct gprs_gsup_client *gsupc, struct msgb *msg)
73{
74 int rc;
75
76 rc = gprs_subscr_rx_gsup_message(msg);
Jacob Erlbecke154d8b2014-12-19 19:15:55 +010077 msgb_free(msg);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010078 if (rc < 0)
79 return -1;
80
81 return rc;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010082}
83
Jacob Erlbeckf81cacc2015-01-08 16:23:25 +010084static int check_blocking(
85 struct gsm_subscriber *subscr,
86 enum sgsn_subscriber_proc what)
87{
88 if (subscr->sgsn_data->blocked_by == SGSN_SUBSCR_PROC_NONE ||
89 subscr->sgsn_data->blocked_by == what)
90 return 1;
91
92 return 0;
93}
94
95static void abort_blocking_procedure(struct gsm_subscriber *subscr)
96{
Holger Hans Peter Freyther1d778fd2015-01-20 21:14:03 +010097 /* reset something */
Jacob Erlbeckf81cacc2015-01-08 16:23:25 +010098}
99
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +0100100int gprs_subscr_purge(struct gsm_subscriber *subscr);
101
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100102static struct sgsn_subscriber_data *sgsn_subscriber_data_alloc(void *ctx)
103{
104 struct sgsn_subscriber_data *sdata;
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100105 int idx;
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100106
107 sdata = talloc_zero(ctx, struct sgsn_subscriber_data);
108
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100109 sdata->error_cause = SGSN_ERROR_CAUSE_NONE;
110
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100111 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
112 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
113
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100114 return sdata;
115}
116
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100117struct gsm_subscriber *gprs_subscr_get_or_create(const char *imsi)
118{
119 struct gsm_subscriber *subscr;
120
121 subscr = subscr_get_or_create(NULL, imsi);
122 if (!subscr)
123 return NULL;
124
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100125 if (!subscr->sgsn_data)
126 subscr->sgsn_data = sgsn_subscriber_data_alloc(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100127 return subscr;
128}
129
130struct gsm_subscriber *gprs_subscr_get_by_imsi(const char *imsi)
131{
132 return subscr_active_by_imsi(NULL, imsi);
133}
134
Jacob Erlbeck3e4e58f2015-01-26 11:07:24 +0100135void gprs_subscr_cleanup(struct gsm_subscriber *subscr)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100136{
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100137 if (subscr->sgsn_data->mm) {
138 subscr_put(subscr->sgsn_data->mm->subscr);
139 subscr->sgsn_data->mm->subscr = NULL;
140 subscr->sgsn_data->mm = NULL;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100141 }
142
Holger Hans Peter Freyther1d778fd2015-01-20 21:14:03 +0100143 if (subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE) {
144 gprs_subscr_purge(subscr);
145 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +0100146 }
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100147}
148
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100149void gprs_subscr_cancel(struct gsm_subscriber *subscr)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100150{
151 subscr->authorized = 0;
152 subscr->flags |= GPRS_SUBSCRIBER_CANCELLED;
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100153 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100154
155 gprs_subscr_update(subscr);
Jacob Erlbeck3e4e58f2015-01-26 11:07:24 +0100156 gprs_subscr_cleanup(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100157}
158
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100159static int gprs_subscr_tx_gsup_message(struct gsm_subscriber *subscr,
160 struct gprs_gsup_message *gsup_msg)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100161{
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100162 struct msgb *msg = gprs_gsup_msgb_alloc();
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100163
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100164 if (strlen(gsup_msg->imsi) == 0 && subscr)
165 strncpy(gsup_msg->imsi, subscr->imsi, sizeof(gsup_msg->imsi) - 1);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100166
167 gprs_gsup_encode(msg, gsup_msg);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100168
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100169 LOGGSUBSCRP(LOGL_INFO, subscr,
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100170 "Sending GSUP, will send: %s\n", msgb_hexdump(msg));
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100171
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100172 if (!sgsn->gsup_client) {
173 msgb_free(msg);
174 return -ENOTSUP;
175 }
176
177 return gprs_gsup_client_send(sgsn->gsup_client, msg);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100178}
179
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100180static int gprs_subscr_tx_gsup_error_reply(struct gsm_subscriber *subscr,
181 struct gprs_gsup_message *gsup_orig,
182 enum gsm48_gmm_cause cause)
183{
184 struct gprs_gsup_message gsup_reply = {0};
185
186 strncpy(gsup_reply.imsi, gsup_orig->imsi, sizeof(gsup_reply.imsi) - 1);
187 gsup_reply.cause = cause;
188 gsup_reply.message_type =
189 GPRS_GSUP_TO_MSGT_ERROR(gsup_orig->message_type);
190
191 return gprs_subscr_tx_gsup_message(subscr, &gsup_reply);
192}
193
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100194static int gprs_subscr_handle_gsup_auth_res(struct gsm_subscriber *subscr,
195 struct gprs_gsup_message *gsup_msg)
196{
197 unsigned idx;
198 struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
199
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100200 LOGGSUBSCRP(LOGL_INFO, subscr,
201 "Got SendAuthenticationInfoResult, num_auth_tuples = %d\n",
202 gsup_msg->num_auth_tuples);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100203
204 if (gsup_msg->num_auth_tuples > 0) {
205 memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
206
207 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
208 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
209 }
210
211 for (idx = 0; idx < gsup_msg->num_auth_tuples; idx++) {
212 size_t key_seq = gsup_msg->auth_tuples[idx].key_seq;
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100213 LOGGSUBSCRP(LOGL_DEBUG, subscr,
214 "Adding auth tuple, cksn = %d\n", key_seq);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100215 if (key_seq >= ARRAY_SIZE(sdata->auth_triplets)) {
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100216 LOGGSUBSCRP(LOGL_NOTICE, subscr,
217 "Skipping auth triplet with invalid cksn %d\n",
218 key_seq);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100219 continue;
220 }
221 sdata->auth_triplets[key_seq] = gsup_msg->auth_tuples[idx];
222 }
223
224 sdata->auth_triplets_updated = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100225 sdata->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100226
227 gprs_subscr_update_auth_info(subscr);
228
229 return 0;
230}
231
232static int gprs_subscr_handle_gsup_upd_loc_res(struct gsm_subscriber *subscr,
233 struct gprs_gsup_message *gsup_msg)
234{
235 unsigned idx;
236
237 if (gsup_msg->pdp_info_compl) {
238 LOGP(DGPRS, LOGL_INFO, "Would clear existing PDP info\n");
239
240 /* TODO: clear existing PDP info entries */
241 }
242
243 for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) {
244 struct gprs_gsup_pdp_info *pdp_info = &gsup_msg->pdp_infos[idx];
245 size_t ctx_id = pdp_info->context_id;
246
247 LOGP(DGPRS, LOGL_INFO,
248 "Would set PDP info, context id = %d, APN = %s\n",
249 ctx_id, osmo_hexdump(pdp_info->apn_enc, pdp_info->apn_enc_len));
250
251 /* TODO: set PDP info [ctx_id] */
252 }
253
254 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100255 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100256
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100257 subscr->flags |= GPRS_SUBSCRIBER_ENABLE_PURGE;
258
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100259 gprs_subscr_update(subscr);
260 return 0;
261}
262
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100263static int check_cause(int cause)
264{
265 switch (cause) {
266 case GMM_CAUSE_IMSI_UNKNOWN ... GMM_CAUSE_ILLEGAL_ME:
267 case GMM_CAUSE_GPRS_NOTALLOWED ... GMM_CAUSE_NO_GPRS_PLMN:
268 return EACCES;
269
270 case GMM_CAUSE_MSC_TEMP_NOTREACH ... GMM_CAUSE_CONGESTION:
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100271 return EHOSTUNREACH;
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100272
273 case GMM_CAUSE_SEM_INCORR_MSG ... GMM_CAUSE_PROTO_ERR_UNSPEC:
274 default:
275 return EINVAL;
276 }
277}
278
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100279static int gprs_subscr_handle_gsup_auth_err(struct gsm_subscriber *subscr,
280 struct gprs_gsup_message *gsup_msg)
281{
282 unsigned idx;
283 struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100284 int cause_err;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100285
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100286 cause_err = check_cause(gsup_msg->cause);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100287
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100288 LOGGSUBSCRP(LOGL_DEBUG, subscr,
289 "Send authentication info has failed with cause %d, "
290 "handled as: %s\n",
291 gsup_msg->cause, strerror(cause_err));
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100292
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100293 switch (cause_err) {
294 case EACCES:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100295 LOGGSUBSCRP(LOGL_NOTICE, subscr,
296 "GPRS send auth info req failed, access denied, "
297 "GMM cause = '%s' (%d)\n",
298 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
299 gsup_msg->cause);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100300 /* Clear auth tuples */
301 memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
302 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
303 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100304
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100305 subscr->authorized = 0;
306 sdata->error_cause = gsup_msg->cause;
307 gprs_subscr_update_auth_info(subscr);
308 break;
309
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100310 case EHOSTUNREACH:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100311 LOGGSUBSCRP(LOGL_NOTICE, subscr,
312 "GPRS send auth info req failed, GMM cause = '%s' (%d)\n",
313 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
314 gsup_msg->cause);
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100315
316 sdata->error_cause = gsup_msg->cause;
317 gprs_subscr_update_auth_info(subscr);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100318 break;
319
320 default:
321 case EINVAL:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100322 LOGGSUBSCRP(LOGL_ERROR, subscr,
323 "GSUP protocol remote error, GMM cause = '%s' (%d)\n",
324 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
325 gsup_msg->cause);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100326 break;
327 }
328
329 return -gsup_msg->cause;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100330}
331
332static int gprs_subscr_handle_gsup_upd_loc_err(struct gsm_subscriber *subscr,
333 struct gprs_gsup_message *gsup_msg)
334{
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100335 int cause_err;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100336
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100337 cause_err = check_cause(gsup_msg->cause);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100338
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100339 LOGGSUBSCRP(LOGL_DEBUG, subscr,
340 "Update location has failed with cause %d, handled as: %s\n",
341 gsup_msg->cause, strerror(cause_err));
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100342
343 switch (cause_err) {
344 case EACCES:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100345 LOGGSUBSCRP(LOGL_NOTICE, subscr,
346 "GPRS update location failed, access denied, "
347 "GMM cause = '%s' (%d)\n",
348 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
349 gsup_msg->cause);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100350
351 subscr->authorized = 0;
352 subscr->sgsn_data->error_cause = gsup_msg->cause;
353 gprs_subscr_update_auth_info(subscr);
354 break;
355
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100356 case EHOSTUNREACH:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100357 LOGGSUBSCRP(LOGL_NOTICE, subscr,
358 "GPRS update location failed, GMM cause = '%s' (%d)\n",
359 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
360 gsup_msg->cause);
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100361
362 subscr->sgsn_data->error_cause = gsup_msg->cause;
363 gprs_subscr_update_auth_info(subscr);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100364 break;
365
366 default:
367 case EINVAL:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100368 LOGGSUBSCRP(LOGL_ERROR, subscr,
369 "GSUP protocol remote error, GMM cause = '%s' (%d)\n",
370 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
371 gsup_msg->cause);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100372 break;
373 }
374
375 return -gsup_msg->cause;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100376}
377
Jacob Erlbeck929acdf2015-01-27 13:47:24 +0100378static int gprs_subscr_handle_gsup_purge_no_subscr(
379 struct gprs_gsup_message *gsup_msg)
380{
381 if (GPRS_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
382 LOGGSUPP(LOGL_NOTICE, gsup_msg,
383 "Purge MS has failed with cause '%s' (%d)\n",
384 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
385 gsup_msg->cause);
386 return -gsup_msg->cause;
387 }
388
389 LOGGSUPP(LOGL_INFO, gsup_msg, "Completing purge MS\n");
390 return 0;
391}
392
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100393static int gprs_subscr_handle_gsup_purge_res(struct gsm_subscriber *subscr,
394 struct gprs_gsup_message *gsup_msg)
395{
396 LOGGSUBSCRP(LOGL_INFO, subscr, "Completing purge MS\n");
397
398 /* Force silent cancellation */
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100399 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100400 gprs_subscr_cancel(subscr);
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100401
402 return 0;
403}
404
405static int gprs_subscr_handle_gsup_purge_err(struct gsm_subscriber *subscr,
406 struct gprs_gsup_message *gsup_msg)
407{
408 LOGGSUBSCRP(LOGL_NOTICE, subscr,
409 "Purge MS has failed with cause '%s' (%d)\n",
410 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
411 gsup_msg->cause);
412
413 /* In GSM 09.02, 19.1.4.4, the text and the SDL diagram imply that
414 * the subscriber data is not removed if the request has failed. On the
415 * other hand, keeping the subscriber data in either error case
416 * (subscriber unknown, syntactical message error, connection error)
417 * doesn't seem to give any advantage, since the data will be restored
418 * on the next Attach Request anyway.
419 * This approach ensures, that the subscriber record will not stick if
420 * an error happens.
421 */
422
423 /* TODO: Check whether this behaviour is acceptable and either just
424 * remove this TODO-notice or change the implementation to not delete
425 * the subscriber data (eventually resetting the ENABLE_PURGE flag and
426 * restarting the expiry timer based on the cause).
427 *
428 * Subscriber Unknown: cancel subscr
429 * Temporary network problems: do nothing (handled by timer based retry)
430 * Message problems (syntax, nyi, ...): cancel subscr (retry won't help)
431 */
432
433 gprs_subscr_handle_gsup_purge_res(subscr, gsup_msg);
434
435 return -gsup_msg->cause;
436}
437
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100438static int gprs_subscr_handle_loc_cancel_req(struct gsm_subscriber *subscr,
439 struct gprs_gsup_message *gsup_msg)
440{
441 struct gprs_gsup_message gsup_reply = {0};
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100442 int is_update_procedure = !gsup_msg->cancel_type || gsup_msg->cancel_type;
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100443
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100444 LOGGSUBSCRP(LOGL_INFO, subscr, "Cancelling MS subscriber (%s)\n",
445 is_update_procedure ?
446 "update procedure" : "subscription withdraw");
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100447
448 gsup_reply.message_type = GPRS_GSUP_MSGT_LOCATION_CANCEL_RESULT;
449 gprs_subscr_tx_gsup_message(subscr, &gsup_reply);
450
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100451 if (is_update_procedure)
452 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
453 else
454 /* Since a withdraw cause is not specified, just abort the
455 * current attachment. The following re-attachment should then
456 * be rejected with a proper cause value.
457 */
458 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
459
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100460 gprs_subscr_cancel(subscr);
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100461
462 return 0;
463}
464
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100465static int gprs_subscr_handle_unknown_imsi(struct gprs_gsup_message *gsup_msg)
466{
467 if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg->message_type)) {
468 gprs_subscr_tx_gsup_error_reply(NULL, gsup_msg,
469 GMM_CAUSE_IMSI_UNKNOWN);
470 LOGP(DGPRS, LOGL_NOTICE,
471 "Unknown IMSI %s, discarding GSUP request "
472 "of type 0x%02x\n",
473 gsup_msg->imsi, gsup_msg->message_type);
474 } else if (GPRS_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
475 LOGP(DGPRS, LOGL_NOTICE,
476 "Unknown IMSI %s, discarding GSUP error "
477 "of type 0x%02x, cause '%s' (%d)\n",
478 gsup_msg->imsi, gsup_msg->message_type,
479 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
480 gsup_msg->cause);
481 } else {
482 LOGP(DGPRS, LOGL_NOTICE,
483 "Unknown IMSI %s, discarding GSUP response "
484 "of type 0x%02x\n",
485 gsup_msg->imsi, gsup_msg->message_type);
486 }
487
488 return -GMM_CAUSE_IMSI_UNKNOWN;
489}
490
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100491int gprs_subscr_rx_gsup_message(struct msgb *msg)
492{
493 uint8_t *data = msgb_l2(msg);
494 size_t data_len = msgb_l2len(msg);
495 int rc = 0;
496
497 struct gprs_gsup_message gsup_msg = {0};
498 struct gsm_subscriber *subscr;
499
500 rc = gprs_gsup_decode(data, data_len, &gsup_msg);
501 if (rc < 0) {
502 LOGP(DGPRS, LOGL_ERROR,
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100503 "decoding GSUP message fails with error '%s' (%d)\n",
504 get_value_string(gsm48_gmm_cause_names, -rc), -rc);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100505 return rc;
506 }
507
508 if (!gsup_msg.imsi[0])
509 return -GMM_CAUSE_INV_MAND_INFO;
510
Jacob Erlbeck4dedb272015-01-15 17:50:16 +0100511 subscr = gprs_subscr_get_by_imsi(gsup_msg.imsi);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100512
Jacob Erlbeck929acdf2015-01-27 13:47:24 +0100513 if (!subscr) {
514 switch (gsup_msg.message_type) {
515 case GPRS_GSUP_MSGT_PURGE_MS_RESULT:
516 case GPRS_GSUP_MSGT_PURGE_MS_ERROR:
517 return gprs_subscr_handle_gsup_purge_no_subscr(&gsup_msg);
518 default:
519 return gprs_subscr_handle_unknown_imsi(&gsup_msg);
520 }
521 }
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100522
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100523 LOGGSUBSCRP(LOGL_INFO, subscr,
524 "Received GSUP message of type 0x%02x\n", gsup_msg.message_type);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100525
526 switch (gsup_msg.message_type) {
527 case GPRS_GSUP_MSGT_LOCATION_CANCEL_REQUEST:
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100528 rc = gprs_subscr_handle_loc_cancel_req(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100529 break;
530
531 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100532 rc = gprs_subscr_handle_gsup_auth_res(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100533 break;
534
535 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100536 rc = gprs_subscr_handle_gsup_auth_err(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100537 break;
538
539 case GPRS_GSUP_MSGT_UPDATE_LOCATION_RESULT:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100540 rc = gprs_subscr_handle_gsup_upd_loc_res(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100541 break;
542
543 case GPRS_GSUP_MSGT_UPDATE_LOCATION_ERROR:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100544 rc = gprs_subscr_handle_gsup_upd_loc_err(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100545 break;
546
547 case GPRS_GSUP_MSGT_PURGE_MS_ERROR:
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100548 rc = gprs_subscr_handle_gsup_purge_err(subscr, &gsup_msg);
549 break;
550
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100551 case GPRS_GSUP_MSGT_PURGE_MS_RESULT:
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100552 rc = gprs_subscr_handle_gsup_purge_res(subscr, &gsup_msg);
553 break;
554
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100555 case GPRS_GSUP_MSGT_INSERT_DATA_REQUEST:
556 case GPRS_GSUP_MSGT_DELETE_DATA_REQUEST:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100557 LOGGSUBSCRP(LOGL_ERROR, subscr,
558 "Rx GSUP message type %d not yet implemented\n",
559 gsup_msg.message_type);
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100560 gprs_subscr_tx_gsup_error_reply(subscr, &gsup_msg,
561 GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100562 rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
563 break;
564
565 default:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100566 LOGGSUBSCRP(LOGL_ERROR, subscr,
567 "Rx GSUP message type %d not valid at SGSN\n",
568 gsup_msg.message_type);
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100569 if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
570 gprs_subscr_tx_gsup_error_reply(
571 subscr, &gsup_msg, GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
572 rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100573 break;
574 };
575
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100576 subscr_put(subscr);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100577
578 return rc;
579}
580
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100581int gprs_subscr_purge(struct gsm_subscriber *subscr)
582{
583 struct gprs_gsup_message gsup_msg = {0};
Jacob Erlbeckf81cacc2015-01-08 16:23:25 +0100584 int rc;
585
586 if (!check_blocking(subscr, SGSN_SUBSCR_PROC_PURGE)) {
587 LOGGSUBSCRP(
588 LOGL_NOTICE, subscr,
589 "Cannot purge MS subscriber, blocked\n");
590 return -EAGAIN;
591 }
592
593 /* GSM 09.02, 19.4.1.4 requires other MAP requests to be blocked until
594 * this procedure is completed
595 */
596 subscr->sgsn_data->blocked_by = SGSN_SUBSCR_PROC_PURGE;
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100597
598 LOGGSUBSCRP(LOGL_INFO, subscr, "purging MS subscriber\n");
599
600 gsup_msg.message_type = GPRS_GSUP_MSGT_PURGE_MS_REQUEST;
Jacob Erlbeckf81cacc2015-01-08 16:23:25 +0100601 rc = gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
602 if (rc < 0)
603 subscr->sgsn_data->blocked_by = SGSN_SUBSCR_PROC_NONE;
604
605 return rc;
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100606}
607
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100608int gprs_subscr_query_auth_info(struct gsm_subscriber *subscr)
609{
610 struct gprs_gsup_message gsup_msg = {0};
611
Jacob Erlbeckf81cacc2015-01-08 16:23:25 +0100612 if (!check_blocking(subscr, SGSN_SUBSCR_PROC_UPD_AUTH)) {
613 LOGGSUBSCRP(
614 LOGL_NOTICE, subscr,
615 "Cannot start update auth info request procedure, blocked\n");
616 abort_blocking_procedure(subscr);
617 return -EAGAIN;
618 }
619
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100620 LOGGSUBSCRP(LOGL_INFO, subscr,
621 "subscriber auth info is not available\n");
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100622
623 gsup_msg.message_type = GPRS_GSUP_MSGT_SEND_AUTH_INFO_REQUEST;
624 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
625}
626
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100627int gprs_subscr_location_update(struct gsm_subscriber *subscr)
628{
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100629 struct gprs_gsup_message gsup_msg = {0};
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100630
Jacob Erlbeckf81cacc2015-01-08 16:23:25 +0100631 if (!check_blocking(subscr, SGSN_SUBSCR_PROC_UPD_LOC)) {
632 LOGGSUBSCRP(
633 LOGL_NOTICE, subscr,
634 "Cannot start update location procedure, blocked\n");
635 abort_blocking_procedure(subscr);
636 return -EAGAIN;
637 }
638
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100639 LOGGSUBSCRP(LOGL_INFO, subscr,
640 "subscriber data is not available\n");
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100641
642 gsup_msg.message_type = GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
643 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100644}
645
646void gprs_subscr_update(struct gsm_subscriber *subscr)
647{
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100648 LOGGSUBSCRP(LOGL_DEBUG, subscr, "Updating subscriber data\n");
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100649
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100650 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100651 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
652
Jacob Erlbeck555b2e52015-01-26 13:52:42 +0100653 if (subscr->sgsn_data->mm)
654 sgsn_update_subscriber_data(subscr->sgsn_data->mm);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100655}
656
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100657void gprs_subscr_update_auth_info(struct gsm_subscriber *subscr)
658{
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100659 LOGGSUBSCRP(LOGL_DEBUG, subscr,
660 "Updating subscriber authentication info\n");
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100661
662 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
663 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
664
Jacob Erlbeck555b2e52015-01-26 13:52:42 +0100665 if (subscr->sgsn_data->mm)
666 sgsn_update_subscriber_data(subscr->sgsn_data->mm);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100667}
668
669struct gsm_subscriber *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100670{
671 struct gsm_subscriber *subscr = NULL;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100672
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100673 if (mmctx->subscr)
674 return subscr_get(mmctx->subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100675
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100676 if (mmctx->imsi[0])
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100677 subscr = gprs_subscr_get_by_imsi(mmctx->imsi);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100678
679 if (!subscr) {
680 subscr = gprs_subscr_get_or_create(mmctx->imsi);
681 subscr->flags |= GSM_SUBSCRIBER_FIRST_CONTACT;
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100682 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100683 }
684
685 if (strcpy(subscr->equipment.imei, mmctx->imei) != 0) {
686 strncpy(subscr->equipment.imei, mmctx->imei, GSM_IMEI_LENGTH-1);
687 subscr->equipment.imei[GSM_IMEI_LENGTH-1] = 0;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100688 }
689
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100690 if (subscr->lac != mmctx->ra.lac)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100691 subscr->lac = mmctx->ra.lac;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100692
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100693 subscr->sgsn_data->mm = mmctx;
694 mmctx->subscr = subscr_get(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100695
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100696 return subscr;
697}
698
699int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx)
700{
701 struct gsm_subscriber *subscr = NULL;
702 int rc;
703
704 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber data update\n");
705
706 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
707
708 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
709
710 rc = gprs_subscr_location_update(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100711 subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100712 return rc;
713}
714
715int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx)
716{
717 struct gsm_subscriber *subscr = NULL;
718 int rc;
719
720 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber authentication info\n");
721
722 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
723
724 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
725
726 rc = gprs_subscr_query_auth_info(subscr);
727 subscr_put(subscr);
728 return rc;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100729}