blob: d6d874b0bedbb8de82384f014ee5d0f7cc3ffcd8 [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 Erlbeck33b6dad2014-11-12 10:12:11 +010038extern void *tall_bsc_ctx;
39
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010040static int gsup_read_cb(struct gprs_gsup_client *gsupc, struct msgb *msg);
41
42/* TODO: Some functions are specific to the SGSN, but this file is more general
43 * (it has gprs_* name). Either move these functions elsewhere, split them and
44 * move a part, or replace the gprs_ prefix by sgsn_. The applies to
45 * gprs_subscr_init, gsup_read_cb, and gprs_subscr_tx_gsup_message.
46 */
47
48int gprs_subscr_init(struct sgsn_instance *sgi)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010049{
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010050 const char *addr_str;
51
52 if (!sgi->cfg.gsup_server_addr.sin_addr.s_addr)
53 return 0;
54
55 addr_str = inet_ntoa(sgi->cfg.gsup_server_addr.sin_addr);
56
57 sgi->gsup_client = gprs_gsup_client_create(
58 addr_str, sgi->cfg.gsup_server_port,
59 &gsup_read_cb);
60
61 if (!sgi->gsup_client)
62 return -1;
63
64 return 1;
65}
66
67static int gsup_read_cb(struct gprs_gsup_client *gsupc, struct msgb *msg)
68{
69 int rc;
70
71 rc = gprs_subscr_rx_gsup_message(msg);
Jacob Erlbecke154d8b2014-12-19 19:15:55 +010072 msgb_free(msg);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010073 if (rc < 0)
74 return -1;
75
76 return rc;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010077}
78
Jacob Erlbeckf81cacc2015-01-08 16:23:25 +010079static int check_blocking(
80 struct gsm_subscriber *subscr,
81 enum sgsn_subscriber_proc what)
82{
83 if (subscr->sgsn_data->blocked_by == SGSN_SUBSCR_PROC_NONE ||
84 subscr->sgsn_data->blocked_by == what)
85 return 1;
86
87 return 0;
88}
89
90static void abort_blocking_procedure(struct gsm_subscriber *subscr)
91{
Holger Hans Peter Freyther1d778fd2015-01-20 21:14:03 +010092 /* reset something */
Jacob Erlbeckf81cacc2015-01-08 16:23:25 +010093}
94
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +010095int gprs_subscr_purge(struct gsm_subscriber *subscr);
96
Jacob Erlbecka1e03732014-12-02 11:28:38 +010097static struct sgsn_subscriber_data *sgsn_subscriber_data_alloc(void *ctx)
98{
99 struct sgsn_subscriber_data *sdata;
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100100 int idx;
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100101
102 sdata = talloc_zero(ctx, struct sgsn_subscriber_data);
103
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100104 sdata->error_cause = SGSN_ERROR_CAUSE_NONE;
105
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100106 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
107 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
108
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100109 return sdata;
110}
111
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100112struct gsm_subscriber *gprs_subscr_get_or_create(const char *imsi)
113{
114 struct gsm_subscriber *subscr;
115
116 subscr = subscr_get_or_create(NULL, imsi);
117 if (!subscr)
118 return NULL;
119
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100120 if (!subscr->sgsn_data)
121 subscr->sgsn_data = sgsn_subscriber_data_alloc(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100122 return subscr;
123}
124
125struct gsm_subscriber *gprs_subscr_get_by_imsi(const char *imsi)
126{
127 return subscr_active_by_imsi(NULL, imsi);
128}
129
130void gprs_subscr_delete(struct gsm_subscriber *subscr)
131{
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100132 if (subscr->sgsn_data->mm) {
133 subscr_put(subscr->sgsn_data->mm->subscr);
134 subscr->sgsn_data->mm->subscr = NULL;
135 subscr->sgsn_data->mm = NULL;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100136 }
137
Holger Hans Peter Freyther1d778fd2015-01-20 21:14:03 +0100138 if (subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE) {
139 gprs_subscr_purge(subscr);
140 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +0100141 }
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100142
Holger Hans Peter Freyther1d778fd2015-01-20 21:14:03 +0100143 subscr->keep_in_ram = 0;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100144 subscr_put(subscr);
145}
146
147void gprs_subscr_put_and_cancel(struct gsm_subscriber *subscr)
148{
149 subscr->authorized = 0;
150 subscr->flags |= GPRS_SUBSCRIBER_CANCELLED;
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100151 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100152
153 gprs_subscr_update(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100154 gprs_subscr_delete(subscr);
155}
156
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100157static int gprs_subscr_tx_gsup_message(struct gsm_subscriber *subscr,
158 struct gprs_gsup_message *gsup_msg)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100159{
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100160 struct msgb *msg = gprs_gsup_msgb_alloc();
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100161
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100162 if (strlen(gsup_msg->imsi) == 0 && subscr)
163 strncpy(gsup_msg->imsi, subscr->imsi, sizeof(gsup_msg->imsi) - 1);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100164
165 gprs_gsup_encode(msg, gsup_msg);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100166
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100167 LOGGSUBSCRP(LOGL_INFO, subscr,
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100168 "Sending GSUP, will send: %s\n", msgb_hexdump(msg));
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100169
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100170 if (!sgsn->gsup_client) {
171 msgb_free(msg);
172 return -ENOTSUP;
173 }
174
175 return gprs_gsup_client_send(sgsn->gsup_client, msg);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100176}
177
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100178static int gprs_subscr_tx_gsup_error_reply(struct gsm_subscriber *subscr,
179 struct gprs_gsup_message *gsup_orig,
180 enum gsm48_gmm_cause cause)
181{
182 struct gprs_gsup_message gsup_reply = {0};
183
184 strncpy(gsup_reply.imsi, gsup_orig->imsi, sizeof(gsup_reply.imsi) - 1);
185 gsup_reply.cause = cause;
186 gsup_reply.message_type =
187 GPRS_GSUP_TO_MSGT_ERROR(gsup_orig->message_type);
188
189 return gprs_subscr_tx_gsup_message(subscr, &gsup_reply);
190}
191
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100192static int gprs_subscr_handle_gsup_auth_res(struct gsm_subscriber *subscr,
193 struct gprs_gsup_message *gsup_msg)
194{
195 unsigned idx;
196 struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
197
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100198 LOGGSUBSCRP(LOGL_INFO, subscr,
199 "Got SendAuthenticationInfoResult, num_auth_tuples = %d\n",
200 gsup_msg->num_auth_tuples);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100201
202 if (gsup_msg->num_auth_tuples > 0) {
203 memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
204
205 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
206 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
207 }
208
209 for (idx = 0; idx < gsup_msg->num_auth_tuples; idx++) {
210 size_t key_seq = gsup_msg->auth_tuples[idx].key_seq;
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100211 LOGGSUBSCRP(LOGL_DEBUG, subscr,
212 "Adding auth tuple, cksn = %d\n", key_seq);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100213 if (key_seq >= ARRAY_SIZE(sdata->auth_triplets)) {
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100214 LOGGSUBSCRP(LOGL_NOTICE, subscr,
215 "Skipping auth triplet with invalid cksn %d\n",
216 key_seq);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100217 continue;
218 }
219 sdata->auth_triplets[key_seq] = gsup_msg->auth_tuples[idx];
220 }
221
222 sdata->auth_triplets_updated = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100223 sdata->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100224
225 gprs_subscr_update_auth_info(subscr);
226
227 return 0;
228}
229
230static int gprs_subscr_handle_gsup_upd_loc_res(struct gsm_subscriber *subscr,
231 struct gprs_gsup_message *gsup_msg)
232{
233 unsigned idx;
234
235 if (gsup_msg->pdp_info_compl) {
236 LOGP(DGPRS, LOGL_INFO, "Would clear existing PDP info\n");
237
238 /* TODO: clear existing PDP info entries */
239 }
240
241 for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) {
242 struct gprs_gsup_pdp_info *pdp_info = &gsup_msg->pdp_infos[idx];
243 size_t ctx_id = pdp_info->context_id;
244
245 LOGP(DGPRS, LOGL_INFO,
246 "Would set PDP info, context id = %d, APN = %s\n",
247 ctx_id, osmo_hexdump(pdp_info->apn_enc, pdp_info->apn_enc_len));
248
249 /* TODO: set PDP info [ctx_id] */
250 }
251
252 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100253 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100254
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100255 subscr->flags |= GPRS_SUBSCRIBER_ENABLE_PURGE;
256
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100257 gprs_subscr_update(subscr);
258 return 0;
259}
260
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100261static int check_cause(int cause)
262{
263 switch (cause) {
264 case GMM_CAUSE_IMSI_UNKNOWN ... GMM_CAUSE_ILLEGAL_ME:
265 case GMM_CAUSE_GPRS_NOTALLOWED ... GMM_CAUSE_NO_GPRS_PLMN:
266 return EACCES;
267
268 case GMM_CAUSE_MSC_TEMP_NOTREACH ... GMM_CAUSE_CONGESTION:
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100269 return EHOSTUNREACH;
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100270
271 case GMM_CAUSE_SEM_INCORR_MSG ... GMM_CAUSE_PROTO_ERR_UNSPEC:
272 default:
273 return EINVAL;
274 }
275}
276
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100277static int gprs_subscr_handle_gsup_auth_err(struct gsm_subscriber *subscr,
278 struct gprs_gsup_message *gsup_msg)
279{
280 unsigned idx;
281 struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100282 int cause_err;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100283
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100284 cause_err = check_cause(gsup_msg->cause);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100285
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100286 LOGGSUBSCRP(LOGL_DEBUG, subscr,
287 "Send authentication info has failed with cause %d, "
288 "handled as: %s\n",
289 gsup_msg->cause, strerror(cause_err));
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100290
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100291 switch (cause_err) {
292 case EACCES:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100293 LOGGSUBSCRP(LOGL_NOTICE, subscr,
294 "GPRS send auth info req failed, access denied, "
295 "GMM cause = '%s' (%d)\n",
296 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
297 gsup_msg->cause);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100298 /* Clear auth tuples */
299 memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
300 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
301 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100302
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100303 subscr->authorized = 0;
304 sdata->error_cause = gsup_msg->cause;
305 gprs_subscr_update_auth_info(subscr);
306 break;
307
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100308 case EHOSTUNREACH:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100309 LOGGSUBSCRP(LOGL_NOTICE, subscr,
310 "GPRS send auth info req failed, GMM cause = '%s' (%d)\n",
311 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
312 gsup_msg->cause);
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100313
314 sdata->error_cause = gsup_msg->cause;
315 gprs_subscr_update_auth_info(subscr);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100316 break;
317
318 default:
319 case EINVAL:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100320 LOGGSUBSCRP(LOGL_ERROR, subscr,
321 "GSUP protocol remote error, GMM cause = '%s' (%d)\n",
322 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
323 gsup_msg->cause);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100324 break;
325 }
326
327 return -gsup_msg->cause;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100328}
329
330static int gprs_subscr_handle_gsup_upd_loc_err(struct gsm_subscriber *subscr,
331 struct gprs_gsup_message *gsup_msg)
332{
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100333 int cause_err;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100334
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100335 cause_err = check_cause(gsup_msg->cause);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100336
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100337 LOGGSUBSCRP(LOGL_DEBUG, subscr,
338 "Update location has failed with cause %d, handled as: %s\n",
339 gsup_msg->cause, strerror(cause_err));
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100340
341 switch (cause_err) {
342 case EACCES:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100343 LOGGSUBSCRP(LOGL_NOTICE, subscr,
344 "GPRS update location failed, access denied, "
345 "GMM cause = '%s' (%d)\n",
346 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
347 gsup_msg->cause);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100348
349 subscr->authorized = 0;
350 subscr->sgsn_data->error_cause = gsup_msg->cause;
351 gprs_subscr_update_auth_info(subscr);
352 break;
353
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100354 case EHOSTUNREACH:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100355 LOGGSUBSCRP(LOGL_NOTICE, subscr,
356 "GPRS update location failed, GMM cause = '%s' (%d)\n",
357 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
358 gsup_msg->cause);
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100359
360 subscr->sgsn_data->error_cause = gsup_msg->cause;
361 gprs_subscr_update_auth_info(subscr);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100362 break;
363
364 default:
365 case EINVAL:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100366 LOGGSUBSCRP(LOGL_ERROR, subscr,
367 "GSUP protocol remote error, GMM cause = '%s' (%d)\n",
368 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
369 gsup_msg->cause);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100370 break;
371 }
372
373 return -gsup_msg->cause;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100374}
375
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100376static int gprs_subscr_handle_gsup_purge_res(struct gsm_subscriber *subscr,
377 struct gprs_gsup_message *gsup_msg)
378{
379 LOGGSUBSCRP(LOGL_INFO, subscr, "Completing purge MS\n");
380
381 /* Force silent cancellation */
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100382 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100383 gprs_subscr_put_and_cancel(subscr_get(subscr));
384
385 return 0;
386}
387
388static int gprs_subscr_handle_gsup_purge_err(struct gsm_subscriber *subscr,
389 struct gprs_gsup_message *gsup_msg)
390{
391 LOGGSUBSCRP(LOGL_NOTICE, subscr,
392 "Purge MS has failed with cause '%s' (%d)\n",
393 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
394 gsup_msg->cause);
395
396 /* In GSM 09.02, 19.1.4.4, the text and the SDL diagram imply that
397 * the subscriber data is not removed if the request has failed. On the
398 * other hand, keeping the subscriber data in either error case
399 * (subscriber unknown, syntactical message error, connection error)
400 * doesn't seem to give any advantage, since the data will be restored
401 * on the next Attach Request anyway.
402 * This approach ensures, that the subscriber record will not stick if
403 * an error happens.
404 */
405
406 /* TODO: Check whether this behaviour is acceptable and either just
407 * remove this TODO-notice or change the implementation to not delete
408 * the subscriber data (eventually resetting the ENABLE_PURGE flag and
409 * restarting the expiry timer based on the cause).
410 *
411 * Subscriber Unknown: cancel subscr
412 * Temporary network problems: do nothing (handled by timer based retry)
413 * Message problems (syntax, nyi, ...): cancel subscr (retry won't help)
414 */
415
416 gprs_subscr_handle_gsup_purge_res(subscr, gsup_msg);
417
418 return -gsup_msg->cause;
419}
420
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100421static int gprs_subscr_handle_loc_cancel_req(struct gsm_subscriber *subscr,
422 struct gprs_gsup_message *gsup_msg)
423{
424 struct gprs_gsup_message gsup_reply = {0};
425
426 LOGGSUBSCRP(LOGL_INFO, subscr, "purging MS subscriber\n");
427
428 gsup_reply.message_type = GPRS_GSUP_MSGT_LOCATION_CANCEL_RESULT;
429 gprs_subscr_tx_gsup_message(subscr, &gsup_reply);
430
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100431 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100432 gprs_subscr_put_and_cancel(subscr_get(subscr));
433
434 return 0;
435}
436
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100437static int gprs_subscr_handle_unknown_imsi(struct gprs_gsup_message *gsup_msg)
438{
439 if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg->message_type)) {
440 gprs_subscr_tx_gsup_error_reply(NULL, gsup_msg,
441 GMM_CAUSE_IMSI_UNKNOWN);
442 LOGP(DGPRS, LOGL_NOTICE,
443 "Unknown IMSI %s, discarding GSUP request "
444 "of type 0x%02x\n",
445 gsup_msg->imsi, gsup_msg->message_type);
446 } else if (GPRS_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
447 LOGP(DGPRS, LOGL_NOTICE,
448 "Unknown IMSI %s, discarding GSUP error "
449 "of type 0x%02x, cause '%s' (%d)\n",
450 gsup_msg->imsi, gsup_msg->message_type,
451 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
452 gsup_msg->cause);
453 } else {
454 LOGP(DGPRS, LOGL_NOTICE,
455 "Unknown IMSI %s, discarding GSUP response "
456 "of type 0x%02x\n",
457 gsup_msg->imsi, gsup_msg->message_type);
458 }
459
460 return -GMM_CAUSE_IMSI_UNKNOWN;
461}
462
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100463int gprs_subscr_rx_gsup_message(struct msgb *msg)
464{
465 uint8_t *data = msgb_l2(msg);
466 size_t data_len = msgb_l2len(msg);
467 int rc = 0;
468
469 struct gprs_gsup_message gsup_msg = {0};
470 struct gsm_subscriber *subscr;
471
472 rc = gprs_gsup_decode(data, data_len, &gsup_msg);
473 if (rc < 0) {
474 LOGP(DGPRS, LOGL_ERROR,
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100475 "decoding GSUP message fails with error '%s' (%d)\n",
476 get_value_string(gsm48_gmm_cause_names, -rc), -rc);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100477 return rc;
478 }
479
480 if (!gsup_msg.imsi[0])
481 return -GMM_CAUSE_INV_MAND_INFO;
482
Jacob Erlbeck4dedb272015-01-15 17:50:16 +0100483 subscr = gprs_subscr_get_by_imsi(gsup_msg.imsi);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100484
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100485 if (!subscr)
486 return gprs_subscr_handle_unknown_imsi(&gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100487
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100488 LOGGSUBSCRP(LOGL_INFO, subscr,
489 "Received GSUP message of type 0x%02x\n", gsup_msg.message_type);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100490
491 switch (gsup_msg.message_type) {
492 case GPRS_GSUP_MSGT_LOCATION_CANCEL_REQUEST:
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100493 rc = gprs_subscr_handle_loc_cancel_req(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100494 break;
495
496 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100497 rc = gprs_subscr_handle_gsup_auth_res(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100498 break;
499
500 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100501 rc = gprs_subscr_handle_gsup_auth_err(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100502 break;
503
504 case GPRS_GSUP_MSGT_UPDATE_LOCATION_RESULT:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100505 rc = gprs_subscr_handle_gsup_upd_loc_res(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100506 break;
507
508 case GPRS_GSUP_MSGT_UPDATE_LOCATION_ERROR:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100509 rc = gprs_subscr_handle_gsup_upd_loc_err(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100510 break;
511
512 case GPRS_GSUP_MSGT_PURGE_MS_ERROR:
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100513 rc = gprs_subscr_handle_gsup_purge_err(subscr, &gsup_msg);
514 break;
515
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100516 case GPRS_GSUP_MSGT_PURGE_MS_RESULT:
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100517 rc = gprs_subscr_handle_gsup_purge_res(subscr, &gsup_msg);
518 break;
519
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100520 case GPRS_GSUP_MSGT_INSERT_DATA_REQUEST:
521 case GPRS_GSUP_MSGT_DELETE_DATA_REQUEST:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100522 LOGGSUBSCRP(LOGL_ERROR, subscr,
523 "Rx GSUP message type %d not yet implemented\n",
524 gsup_msg.message_type);
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100525 gprs_subscr_tx_gsup_error_reply(subscr, &gsup_msg,
526 GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100527 rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
528 break;
529
530 default:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100531 LOGGSUBSCRP(LOGL_ERROR, subscr,
532 "Rx GSUP message type %d not valid at SGSN\n",
533 gsup_msg.message_type);
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100534 if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
535 gprs_subscr_tx_gsup_error_reply(
536 subscr, &gsup_msg, GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
537 rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100538 break;
539 };
540
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100541 subscr_put(subscr);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100542
543 return rc;
544}
545
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100546int gprs_subscr_purge(struct gsm_subscriber *subscr)
547{
548 struct gprs_gsup_message gsup_msg = {0};
Jacob Erlbeckf81cacc2015-01-08 16:23:25 +0100549 int rc;
550
551 if (!check_blocking(subscr, SGSN_SUBSCR_PROC_PURGE)) {
552 LOGGSUBSCRP(
553 LOGL_NOTICE, subscr,
554 "Cannot purge MS subscriber, blocked\n");
555 return -EAGAIN;
556 }
557
558 /* GSM 09.02, 19.4.1.4 requires other MAP requests to be blocked until
559 * this procedure is completed
560 */
561 subscr->sgsn_data->blocked_by = SGSN_SUBSCR_PROC_PURGE;
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100562
563 LOGGSUBSCRP(LOGL_INFO, subscr, "purging MS subscriber\n");
564
565 gsup_msg.message_type = GPRS_GSUP_MSGT_PURGE_MS_REQUEST;
Jacob Erlbeckf81cacc2015-01-08 16:23:25 +0100566 rc = gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
567 if (rc < 0)
568 subscr->sgsn_data->blocked_by = SGSN_SUBSCR_PROC_NONE;
569
570 return rc;
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100571}
572
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100573int gprs_subscr_query_auth_info(struct gsm_subscriber *subscr)
574{
575 struct gprs_gsup_message gsup_msg = {0};
576
Jacob Erlbeckf81cacc2015-01-08 16:23:25 +0100577 if (!check_blocking(subscr, SGSN_SUBSCR_PROC_UPD_AUTH)) {
578 LOGGSUBSCRP(
579 LOGL_NOTICE, subscr,
580 "Cannot start update auth info request procedure, blocked\n");
581 abort_blocking_procedure(subscr);
582 return -EAGAIN;
583 }
584
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100585 LOGGSUBSCRP(LOGL_INFO, subscr,
586 "subscriber auth info is not available\n");
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100587
588 gsup_msg.message_type = GPRS_GSUP_MSGT_SEND_AUTH_INFO_REQUEST;
589 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
590}
591
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100592int gprs_subscr_location_update(struct gsm_subscriber *subscr)
593{
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100594 struct gprs_gsup_message gsup_msg = {0};
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100595
Jacob Erlbeckf81cacc2015-01-08 16:23:25 +0100596 if (!check_blocking(subscr, SGSN_SUBSCR_PROC_UPD_LOC)) {
597 LOGGSUBSCRP(
598 LOGL_NOTICE, subscr,
599 "Cannot start update location procedure, blocked\n");
600 abort_blocking_procedure(subscr);
601 return -EAGAIN;
602 }
603
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100604 LOGGSUBSCRP(LOGL_INFO, subscr,
605 "subscriber data is not available\n");
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100606
607 gsup_msg.message_type = GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
608 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100609}
610
611void gprs_subscr_update(struct gsm_subscriber *subscr)
612{
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100613 LOGGSUBSCRP(LOGL_DEBUG, subscr, "Updating subscriber data\n");
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100614
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100615 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100616 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
617
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100618 sgsn_update_subscriber_data(subscr->sgsn_data->mm, subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100619}
620
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100621void gprs_subscr_update_auth_info(struct gsm_subscriber *subscr)
622{
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100623 LOGGSUBSCRP(LOGL_DEBUG, subscr,
624 "Updating subscriber authentication info\n");
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100625
626 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
627 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
628
629 sgsn_update_subscriber_data(subscr->sgsn_data->mm, subscr);
630}
631
632struct gsm_subscriber *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100633{
634 struct gsm_subscriber *subscr = NULL;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100635
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100636 if (mmctx->subscr)
637 return subscr_get(mmctx->subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100638
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100639 if (mmctx->imsi[0])
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100640 subscr = gprs_subscr_get_by_imsi(mmctx->imsi);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100641
642 if (!subscr) {
643 subscr = gprs_subscr_get_or_create(mmctx->imsi);
644 subscr->flags |= GSM_SUBSCRIBER_FIRST_CONTACT;
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100645 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100646 }
647
648 if (strcpy(subscr->equipment.imei, mmctx->imei) != 0) {
649 strncpy(subscr->equipment.imei, mmctx->imei, GSM_IMEI_LENGTH-1);
650 subscr->equipment.imei[GSM_IMEI_LENGTH-1] = 0;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100651 }
652
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100653 if (subscr->lac != mmctx->ra.lac)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100654 subscr->lac = mmctx->ra.lac;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100655
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100656 subscr->sgsn_data->mm = mmctx;
657 mmctx->subscr = subscr_get(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100658
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100659 return subscr;
660}
661
662int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx)
663{
664 struct gsm_subscriber *subscr = NULL;
665 int rc;
666
667 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber data update\n");
668
669 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
670
671 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
672
673 rc = gprs_subscr_location_update(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100674 subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100675 return rc;
676}
677
678int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx)
679{
680 struct gsm_subscriber *subscr = NULL;
681 int rc;
682
683 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber authentication info\n");
684
685 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
686
687 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
688
689 rc = gprs_subscr_query_auth_info(subscr);
690 subscr_put(subscr);
691 return rc;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100692}