blob: 5bde6a090a4d7f90ae335be98318e9ae0332c3f5 [file] [log] [blame]
Jacob Erlbecke8b69682014-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 Erlbeck233715c2014-12-18 12:46:47 +010023#include <openbsc/gprs_gsup_client.h>
Jacob Erlbecke8b69682014-11-12 10:12:11 +010024
25#include <openbsc/sgsn.h>
26#include <openbsc/gprs_sgsn.h>
27#include <openbsc/gprs_gmm.h>
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +010028#include <openbsc/gprs_gsup_messages.h>
Jacob Erlbecke8b69682014-11-12 10:12:11 +010029
30#include <openbsc/debug.h>
31
Jacob Erlbeck233715c2014-12-18 12:46:47 +010032#include <netinet/in.h>
33#include <arpa/inet.h>
34
Jacob Erlbeck87972662015-01-08 15:18:39 +010035#define SGSN_SUBSCR_MAX_RETRIES 3
36#define SGSN_SUBSCR_RETRY_INTERVAL 10
37
Jacob Erlbecke8b69682014-11-12 10:12:11 +010038extern void *tall_bsc_ctx;
39
Jacob Erlbeck233715c2014-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 Erlbecke8b69682014-11-12 10:12:11 +010049{
Jacob Erlbeck233715c2014-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 Erlbeckedb67a12014-12-19 19:15:55 +010072 msgb_free(msg);
Jacob Erlbeck233715c2014-12-18 12:46:47 +010073 if (rc < 0)
74 return -1;
75
76 return rc;
Jacob Erlbecke8b69682014-11-12 10:12:11 +010077}
78
Jacob Erlbeckfdf8ce52015-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{
92 /* Best effort, stop retries at least */
93 subscr->sgsn_data->retries = SGSN_SUBSCR_MAX_RETRIES;
94}
95
Jacob Erlbeck9bf4be92015-01-06 16:32:41 +010096static void sgsn_subscriber_timeout_cb(void *subscr_);
97int gprs_subscr_purge(struct gsm_subscriber *subscr);
98
99void gprs_subscr_stop_timer(struct gsm_subscriber *subscr)
100{
101 if (subscr->sgsn_data->timer.data) {
102 osmo_timer_del(&subscr->sgsn_data->timer);
103 subscr->sgsn_data->timer.cb = NULL;
104 OSMO_ASSERT(subscr->sgsn_data->timer.data == subscr);
105 subscr->sgsn_data->timer.data = NULL;
106 subscr_put(subscr);
107 }
108}
109
110void gprs_subscr_start_timer(struct gsm_subscriber *subscr, unsigned seconds)
111{
112 if (!subscr->sgsn_data->timer.data) {
113 subscr->sgsn_data->timer.cb = sgsn_subscriber_timeout_cb;
114 subscr->sgsn_data->timer.data = subscr_get(subscr);
Jacob Erlbeck87972662015-01-08 15:18:39 +0100115 subscr->sgsn_data->retries = 0;
Jacob Erlbeck9bf4be92015-01-06 16:32:41 +0100116 }
117
118 osmo_timer_schedule(&subscr->sgsn_data->timer, seconds, 0);
119}
120
121static void sgsn_subscriber_timeout_cb(void *subscr_)
122{
123 struct gsm_subscriber *subscr = subscr_;
124
125 LOGGSUBSCRP(LOGL_INFO, subscr,
126 "Expired, deleting subscriber entry\n");
127
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100128 subscr_get(subscr);
129
130 /* Check, whether to cleanup immediately */
Jacob Erlbeck87972662015-01-08 15:18:39 +0100131 if (!(subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE) ||
132 subscr->sgsn_data->retries >= SGSN_SUBSCR_MAX_RETRIES)
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100133 goto force_cleanup;
134
135 /* Send a 'purge MS' message to the HLR */
136 if (gprs_subscr_purge(subscr) < 0)
137 goto force_cleanup;
138
139 /* Purge request has been sent */
140
Jacob Erlbeck87972662015-01-08 15:18:39 +0100141 /* Check, whether purge is still enabled */
142 if (!(subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE))
143 goto force_cleanup;
144
145 /* Make sure this will be tried again if there is no response in time */
146 subscr->sgsn_data->retries += 1;
147 gprs_subscr_start_timer(subscr, SGSN_SUBSCR_RETRY_INTERVAL);
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100148 subscr_put(subscr);
149 return;
150
151force_cleanup:
Jacob Erlbeckfdf8ce52015-01-08 16:23:25 +0100152 /* Make sure to clear blocking */
153 if (check_blocking(subscr, SGSN_SUBSCR_PROC_PURGE))
154 subscr->sgsn_data->blocked_by = SGSN_SUBSCR_PROC_NONE;
155
Jacob Erlbeck9bf4be92015-01-06 16:32:41 +0100156 /* Make sure, the timer is cleaned up */
157 subscr->keep_in_ram = 0;
158 gprs_subscr_stop_timer(subscr);
159 /* The subscr is freed now, if the timer was the last user */
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100160 subscr_put(subscr);
Jacob Erlbeck9bf4be92015-01-06 16:32:41 +0100161}
162
Jacob Erlbeck359cafa2014-12-02 11:28:38 +0100163static struct sgsn_subscriber_data *sgsn_subscriber_data_alloc(void *ctx)
164{
165 struct sgsn_subscriber_data *sdata;
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100166 int idx;
Jacob Erlbeck359cafa2014-12-02 11:28:38 +0100167
168 sdata = talloc_zero(ctx, struct sgsn_subscriber_data);
169
Jacob Erlbeckf96779f2015-01-19 11:10:04 +0100170 sdata->error_cause = SGSN_ERROR_CAUSE_NONE;
171
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100172 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
173 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
174
Jacob Erlbeck359cafa2014-12-02 11:28:38 +0100175 return sdata;
176}
177
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100178struct gsm_subscriber *gprs_subscr_get_or_create(const char *imsi)
179{
180 struct gsm_subscriber *subscr;
181
182 subscr = subscr_get_or_create(NULL, imsi);
183 if (!subscr)
184 return NULL;
185
Jacob Erlbeck359cafa2014-12-02 11:28:38 +0100186 if (!subscr->sgsn_data)
187 subscr->sgsn_data = sgsn_subscriber_data_alloc(subscr);
188
Jacob Erlbeck9bf4be92015-01-06 16:32:41 +0100189 gprs_subscr_stop_timer(subscr);
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100190
191 return subscr;
192}
193
194struct gsm_subscriber *gprs_subscr_get_by_imsi(const char *imsi)
195{
196 return subscr_active_by_imsi(NULL, imsi);
197}
198
199void gprs_subscr_delete(struct gsm_subscriber *subscr)
200{
Jacob Erlbeck359cafa2014-12-02 11:28:38 +0100201 if (subscr->sgsn_data->mm) {
202 subscr_put(subscr->sgsn_data->mm->subscr);
203 subscr->sgsn_data->mm->subscr = NULL;
204 subscr->sgsn_data->mm = NULL;
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100205 }
206
207 if ((subscr->flags & GPRS_SUBSCRIBER_CANCELLED) ||
Jacob Erlbeck9bf4be92015-01-06 16:32:41 +0100208 (subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT)) {
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100209 subscr->keep_in_ram = 0;
Jacob Erlbeck9bf4be92015-01-06 16:32:41 +0100210 gprs_subscr_stop_timer(subscr);
211 } else if (sgsn->cfg.subscriber_expiry_timeout != SGSN_TIMEOUT_NEVER) {
212 gprs_subscr_start_timer(subscr, sgsn->cfg.subscriber_expiry_timeout);
213 } else {
214 subscr->keep_in_ram = 1;
215 }
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100216
217 subscr_put(subscr);
218}
219
220void gprs_subscr_put_and_cancel(struct gsm_subscriber *subscr)
221{
222 subscr->authorized = 0;
223 subscr->flags |= GPRS_SUBSCRIBER_CANCELLED;
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100224 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100225
226 gprs_subscr_update(subscr);
227
228 gprs_subscr_delete(subscr);
229}
230
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100231static int gprs_subscr_tx_gsup_message(struct gsm_subscriber *subscr,
232 struct gprs_gsup_message *gsup_msg)
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100233{
Jacob Erlbeck233715c2014-12-18 12:46:47 +0100234 struct msgb *msg = gprs_gsup_msgb_alloc();
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100235
Jacob Erlbeck4f414862015-01-15 17:08:30 +0100236 if (strlen(gsup_msg->imsi) == 0 && subscr)
237 strncpy(gsup_msg->imsi, subscr->imsi, sizeof(gsup_msg->imsi) - 1);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100238
239 gprs_gsup_encode(msg, gsup_msg);
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100240
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100241 LOGGSUBSCRP(LOGL_INFO, subscr,
Jacob Erlbeck4f414862015-01-15 17:08:30 +0100242 "Sending GSUP, will send: %s\n", msgb_hexdump(msg));
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100243
Jacob Erlbeck233715c2014-12-18 12:46:47 +0100244 if (!sgsn->gsup_client) {
245 msgb_free(msg);
246 return -ENOTSUP;
247 }
248
249 return gprs_gsup_client_send(sgsn->gsup_client, msg);
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100250}
251
Jacob Erlbeck4f414862015-01-15 17:08:30 +0100252static int gprs_subscr_tx_gsup_error_reply(struct gsm_subscriber *subscr,
253 struct gprs_gsup_message *gsup_orig,
254 enum gsm48_gmm_cause cause)
255{
256 struct gprs_gsup_message gsup_reply = {0};
257
258 strncpy(gsup_reply.imsi, gsup_orig->imsi, sizeof(gsup_reply.imsi) - 1);
259 gsup_reply.cause = cause;
260 gsup_reply.message_type =
261 GPRS_GSUP_TO_MSGT_ERROR(gsup_orig->message_type);
262
263 return gprs_subscr_tx_gsup_message(subscr, &gsup_reply);
264}
265
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100266static int gprs_subscr_handle_gsup_auth_res(struct gsm_subscriber *subscr,
267 struct gprs_gsup_message *gsup_msg)
268{
269 unsigned idx;
270 struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
271
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100272 LOGGSUBSCRP(LOGL_INFO, subscr,
273 "Got SendAuthenticationInfoResult, num_auth_tuples = %d\n",
274 gsup_msg->num_auth_tuples);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100275
276 if (gsup_msg->num_auth_tuples > 0) {
277 memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
278
279 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
280 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
281 }
282
283 for (idx = 0; idx < gsup_msg->num_auth_tuples; idx++) {
284 size_t key_seq = gsup_msg->auth_tuples[idx].key_seq;
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100285 LOGGSUBSCRP(LOGL_DEBUG, subscr,
286 "Adding auth tuple, cksn = %d\n", key_seq);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100287 if (key_seq >= ARRAY_SIZE(sdata->auth_triplets)) {
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100288 LOGGSUBSCRP(LOGL_NOTICE, subscr,
289 "Skipping auth triplet with invalid cksn %d\n",
290 key_seq);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100291 continue;
292 }
293 sdata->auth_triplets[key_seq] = gsup_msg->auth_tuples[idx];
294 }
295
296 sdata->auth_triplets_updated = 1;
Jacob Erlbeckf96779f2015-01-19 11:10:04 +0100297 sdata->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100298
299 gprs_subscr_update_auth_info(subscr);
300
301 return 0;
302}
303
304static int gprs_subscr_handle_gsup_upd_loc_res(struct gsm_subscriber *subscr,
305 struct gprs_gsup_message *gsup_msg)
306{
307 unsigned idx;
308
309 if (gsup_msg->pdp_info_compl) {
310 LOGP(DGPRS, LOGL_INFO, "Would clear existing PDP info\n");
311
312 /* TODO: clear existing PDP info entries */
313 }
314
315 for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) {
316 struct gprs_gsup_pdp_info *pdp_info = &gsup_msg->pdp_infos[idx];
317 size_t ctx_id = pdp_info->context_id;
318
319 LOGP(DGPRS, LOGL_INFO,
320 "Would set PDP info, context id = %d, APN = %s\n",
321 ctx_id, osmo_hexdump(pdp_info->apn_enc, pdp_info->apn_enc_len));
322
323 /* TODO: set PDP info [ctx_id] */
324 }
325
326 subscr->authorized = 1;
Jacob Erlbeckf96779f2015-01-19 11:10:04 +0100327 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100328
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100329 subscr->flags |= GPRS_SUBSCRIBER_ENABLE_PURGE;
330
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100331 gprs_subscr_update(subscr);
332 return 0;
333}
334
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100335static int check_cause(int cause)
336{
337 switch (cause) {
338 case GMM_CAUSE_IMSI_UNKNOWN ... GMM_CAUSE_ILLEGAL_ME:
339 case GMM_CAUSE_GPRS_NOTALLOWED ... GMM_CAUSE_NO_GPRS_PLMN:
340 return EACCES;
341
342 case GMM_CAUSE_MSC_TEMP_NOTREACH ... GMM_CAUSE_CONGESTION:
Jacob Erlbecke4dc7fc2015-01-05 16:20:47 +0100343 return EHOSTUNREACH;
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100344
345 case GMM_CAUSE_SEM_INCORR_MSG ... GMM_CAUSE_PROTO_ERR_UNSPEC:
346 default:
347 return EINVAL;
348 }
349}
350
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100351static int gprs_subscr_handle_gsup_auth_err(struct gsm_subscriber *subscr,
352 struct gprs_gsup_message *gsup_msg)
353{
354 unsigned idx;
355 struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100356 int cause_err;
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100357
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100358 cause_err = check_cause(gsup_msg->cause);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100359
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100360 LOGGSUBSCRP(LOGL_DEBUG, subscr,
361 "Send authentication info has failed with cause %d, "
362 "handled as: %s\n",
363 gsup_msg->cause, strerror(cause_err));
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100364
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100365 switch (cause_err) {
366 case EACCES:
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100367 LOGGSUBSCRP(LOGL_NOTICE, subscr,
368 "GPRS send auth info req failed, access denied, "
369 "GMM cause = '%s' (%d)\n",
370 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
371 gsup_msg->cause);
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100372 /* Clear auth tuples */
373 memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
374 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
375 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100376
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100377 subscr->authorized = 0;
378 sdata->error_cause = gsup_msg->cause;
379 gprs_subscr_update_auth_info(subscr);
380 break;
381
Jacob Erlbecke4dc7fc2015-01-05 16:20:47 +0100382 case EHOSTUNREACH:
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100383 LOGGSUBSCRP(LOGL_NOTICE, subscr,
384 "GPRS send auth info req failed, GMM cause = '%s' (%d)\n",
385 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
386 gsup_msg->cause);
Jacob Erlbecke4dc7fc2015-01-05 16:20:47 +0100387
388 sdata->error_cause = gsup_msg->cause;
389 gprs_subscr_update_auth_info(subscr);
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100390 break;
391
392 default:
393 case EINVAL:
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100394 LOGGSUBSCRP(LOGL_ERROR, subscr,
395 "GSUP protocol remote error, GMM cause = '%s' (%d)\n",
396 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
397 gsup_msg->cause);
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100398 break;
399 }
400
401 return -gsup_msg->cause;
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100402}
403
404static int gprs_subscr_handle_gsup_upd_loc_err(struct gsm_subscriber *subscr,
405 struct gprs_gsup_message *gsup_msg)
406{
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100407 int cause_err;
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100408
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100409 cause_err = check_cause(gsup_msg->cause);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100410
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100411 LOGGSUBSCRP(LOGL_DEBUG, subscr,
412 "Update location has failed with cause %d, handled as: %s\n",
413 gsup_msg->cause, strerror(cause_err));
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100414
415 switch (cause_err) {
416 case EACCES:
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100417 LOGGSUBSCRP(LOGL_NOTICE, subscr,
418 "GPRS update location failed, access denied, "
419 "GMM cause = '%s' (%d)\n",
420 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
421 gsup_msg->cause);
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100422
423 subscr->authorized = 0;
424 subscr->sgsn_data->error_cause = gsup_msg->cause;
425 gprs_subscr_update_auth_info(subscr);
426 break;
427
Jacob Erlbecke4dc7fc2015-01-05 16:20:47 +0100428 case EHOSTUNREACH:
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100429 LOGGSUBSCRP(LOGL_NOTICE, subscr,
430 "GPRS update location failed, GMM cause = '%s' (%d)\n",
431 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
432 gsup_msg->cause);
Jacob Erlbecke4dc7fc2015-01-05 16:20:47 +0100433
434 subscr->sgsn_data->error_cause = gsup_msg->cause;
435 gprs_subscr_update_auth_info(subscr);
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100436 break;
437
438 default:
439 case EINVAL:
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100440 LOGGSUBSCRP(LOGL_ERROR, subscr,
441 "GSUP protocol remote error, GMM cause = '%s' (%d)\n",
442 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
443 gsup_msg->cause);
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100444 break;
445 }
446
447 return -gsup_msg->cause;
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100448}
449
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100450static int gprs_subscr_handle_gsup_purge_res(struct gsm_subscriber *subscr,
451 struct gprs_gsup_message *gsup_msg)
452{
453 LOGGSUBSCRP(LOGL_INFO, subscr, "Completing purge MS\n");
454
455 /* Force silent cancellation */
Jacob Erlbeckf96779f2015-01-19 11:10:04 +0100456 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100457 gprs_subscr_put_and_cancel(subscr_get(subscr));
458
459 return 0;
460}
461
462static int gprs_subscr_handle_gsup_purge_err(struct gsm_subscriber *subscr,
463 struct gprs_gsup_message *gsup_msg)
464{
465 LOGGSUBSCRP(LOGL_NOTICE, subscr,
466 "Purge MS has failed with cause '%s' (%d)\n",
467 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
468 gsup_msg->cause);
469
470 /* In GSM 09.02, 19.1.4.4, the text and the SDL diagram imply that
471 * the subscriber data is not removed if the request has failed. On the
472 * other hand, keeping the subscriber data in either error case
473 * (subscriber unknown, syntactical message error, connection error)
474 * doesn't seem to give any advantage, since the data will be restored
475 * on the next Attach Request anyway.
476 * This approach ensures, that the subscriber record will not stick if
477 * an error happens.
478 */
479
480 /* TODO: Check whether this behaviour is acceptable and either just
481 * remove this TODO-notice or change the implementation to not delete
482 * the subscriber data (eventually resetting the ENABLE_PURGE flag and
483 * restarting the expiry timer based on the cause).
484 *
485 * Subscriber Unknown: cancel subscr
486 * Temporary network problems: do nothing (handled by timer based retry)
487 * Message problems (syntax, nyi, ...): cancel subscr (retry won't help)
488 */
489
490 gprs_subscr_handle_gsup_purge_res(subscr, gsup_msg);
491
492 return -gsup_msg->cause;
493}
494
Jacob Erlbeck00b8b912015-01-08 15:29:01 +0100495static int gprs_subscr_handle_loc_cancel_req(struct gsm_subscriber *subscr,
496 struct gprs_gsup_message *gsup_msg)
497{
498 struct gprs_gsup_message gsup_reply = {0};
499
500 LOGGSUBSCRP(LOGL_INFO, subscr, "purging MS subscriber\n");
501
502 gsup_reply.message_type = GPRS_GSUP_MSGT_LOCATION_CANCEL_RESULT;
503 gprs_subscr_tx_gsup_message(subscr, &gsup_reply);
504
Jacob Erlbeckf96779f2015-01-19 11:10:04 +0100505 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck00b8b912015-01-08 15:29:01 +0100506 gprs_subscr_put_and_cancel(subscr_get(subscr));
507
508 return 0;
509}
510
Jacob Erlbeck4f414862015-01-15 17:08:30 +0100511static int gprs_subscr_handle_unknown_imsi(struct gprs_gsup_message *gsup_msg)
512{
513 if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg->message_type)) {
514 gprs_subscr_tx_gsup_error_reply(NULL, gsup_msg,
515 GMM_CAUSE_IMSI_UNKNOWN);
516 LOGP(DGPRS, LOGL_NOTICE,
517 "Unknown IMSI %s, discarding GSUP request "
518 "of type 0x%02x\n",
519 gsup_msg->imsi, gsup_msg->message_type);
520 } else if (GPRS_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
521 LOGP(DGPRS, LOGL_NOTICE,
522 "Unknown IMSI %s, discarding GSUP error "
523 "of type 0x%02x, cause '%s' (%d)\n",
524 gsup_msg->imsi, gsup_msg->message_type,
525 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
526 gsup_msg->cause);
527 } else {
528 LOGP(DGPRS, LOGL_NOTICE,
529 "Unknown IMSI %s, discarding GSUP response "
530 "of type 0x%02x\n",
531 gsup_msg->imsi, gsup_msg->message_type);
532 }
533
534 return -GMM_CAUSE_IMSI_UNKNOWN;
535}
536
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100537int gprs_subscr_rx_gsup_message(struct msgb *msg)
538{
539 uint8_t *data = msgb_l2(msg);
540 size_t data_len = msgb_l2len(msg);
541 int rc = 0;
542
543 struct gprs_gsup_message gsup_msg = {0};
544 struct gsm_subscriber *subscr;
545
546 rc = gprs_gsup_decode(data, data_len, &gsup_msg);
547 if (rc < 0) {
548 LOGP(DGPRS, LOGL_ERROR,
Jacob Erlbeck092bbc82015-01-05 18:57:32 +0100549 "decoding GSUP message fails with error '%s' (%d)\n",
550 get_value_string(gsm48_gmm_cause_names, -rc), -rc);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100551 return rc;
552 }
553
554 if (!gsup_msg.imsi[0])
555 return -GMM_CAUSE_INV_MAND_INFO;
556
Jacob Erlbeck629dacc2015-01-15 17:50:16 +0100557 subscr = gprs_subscr_get_by_imsi(gsup_msg.imsi);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100558
Jacob Erlbeck4f414862015-01-15 17:08:30 +0100559 if (!subscr)
560 return gprs_subscr_handle_unknown_imsi(&gsup_msg);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100561
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100562 LOGGSUBSCRP(LOGL_INFO, subscr,
563 "Received GSUP message of type 0x%02x\n", gsup_msg.message_type);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100564
565 switch (gsup_msg.message_type) {
566 case GPRS_GSUP_MSGT_LOCATION_CANCEL_REQUEST:
Jacob Erlbeck00b8b912015-01-08 15:29:01 +0100567 rc = gprs_subscr_handle_loc_cancel_req(subscr, &gsup_msg);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100568 break;
569
570 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
Jacob Erlbeck092bbc82015-01-05 18:57:32 +0100571 rc = gprs_subscr_handle_gsup_auth_res(subscr, &gsup_msg);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100572 break;
573
574 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
Jacob Erlbeck092bbc82015-01-05 18:57:32 +0100575 rc = gprs_subscr_handle_gsup_auth_err(subscr, &gsup_msg);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100576 break;
577
578 case GPRS_GSUP_MSGT_UPDATE_LOCATION_RESULT:
Jacob Erlbeck092bbc82015-01-05 18:57:32 +0100579 rc = gprs_subscr_handle_gsup_upd_loc_res(subscr, &gsup_msg);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100580 break;
581
582 case GPRS_GSUP_MSGT_UPDATE_LOCATION_ERROR:
Jacob Erlbeck092bbc82015-01-05 18:57:32 +0100583 rc = gprs_subscr_handle_gsup_upd_loc_err(subscr, &gsup_msg);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100584 break;
585
586 case GPRS_GSUP_MSGT_PURGE_MS_ERROR:
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100587 rc = gprs_subscr_handle_gsup_purge_err(subscr, &gsup_msg);
588 break;
589
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100590 case GPRS_GSUP_MSGT_PURGE_MS_RESULT:
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100591 rc = gprs_subscr_handle_gsup_purge_res(subscr, &gsup_msg);
592 break;
593
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100594 case GPRS_GSUP_MSGT_INSERT_DATA_REQUEST:
595 case GPRS_GSUP_MSGT_DELETE_DATA_REQUEST:
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100596 LOGGSUBSCRP(LOGL_ERROR, subscr,
597 "Rx GSUP message type %d not yet implemented\n",
598 gsup_msg.message_type);
Jacob Erlbeck4f414862015-01-15 17:08:30 +0100599 gprs_subscr_tx_gsup_error_reply(subscr, &gsup_msg,
600 GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100601 rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
602 break;
603
604 default:
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100605 LOGGSUBSCRP(LOGL_ERROR, subscr,
606 "Rx GSUP message type %d not valid at SGSN\n",
607 gsup_msg.message_type);
Jacob Erlbeck4f414862015-01-15 17:08:30 +0100608 if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
609 gprs_subscr_tx_gsup_error_reply(
610 subscr, &gsup_msg, GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
611 rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100612 break;
613 };
614
Jacob Erlbeck00b8b912015-01-08 15:29:01 +0100615 subscr_put(subscr);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100616
617 return rc;
618}
619
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100620int gprs_subscr_purge(struct gsm_subscriber *subscr)
621{
622 struct gprs_gsup_message gsup_msg = {0};
Jacob Erlbeckfdf8ce52015-01-08 16:23:25 +0100623 int rc;
624
625 if (!check_blocking(subscr, SGSN_SUBSCR_PROC_PURGE)) {
626 LOGGSUBSCRP(
627 LOGL_NOTICE, subscr,
628 "Cannot purge MS subscriber, blocked\n");
629 return -EAGAIN;
630 }
631
632 /* GSM 09.02, 19.4.1.4 requires other MAP requests to be blocked until
633 * this procedure is completed
634 */
635 subscr->sgsn_data->blocked_by = SGSN_SUBSCR_PROC_PURGE;
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100636
637 LOGGSUBSCRP(LOGL_INFO, subscr, "purging MS subscriber\n");
638
639 gsup_msg.message_type = GPRS_GSUP_MSGT_PURGE_MS_REQUEST;
Jacob Erlbeckfdf8ce52015-01-08 16:23:25 +0100640 rc = gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
641 if (rc < 0)
642 subscr->sgsn_data->blocked_by = SGSN_SUBSCR_PROC_NONE;
643
644 return rc;
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100645}
646
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100647int gprs_subscr_query_auth_info(struct gsm_subscriber *subscr)
648{
649 struct gprs_gsup_message gsup_msg = {0};
650
Jacob Erlbeckfdf8ce52015-01-08 16:23:25 +0100651 if (!check_blocking(subscr, SGSN_SUBSCR_PROC_UPD_AUTH)) {
652 LOGGSUBSCRP(
653 LOGL_NOTICE, subscr,
654 "Cannot start update auth info request procedure, blocked\n");
655 abort_blocking_procedure(subscr);
656 return -EAGAIN;
657 }
658
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100659 LOGGSUBSCRP(LOGL_INFO, subscr,
660 "subscriber auth info is not available\n");
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100661
662 gsup_msg.message_type = GPRS_GSUP_MSGT_SEND_AUTH_INFO_REQUEST;
663 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
664}
665
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100666int gprs_subscr_location_update(struct gsm_subscriber *subscr)
667{
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100668 struct gprs_gsup_message gsup_msg = {0};
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100669
Jacob Erlbeckfdf8ce52015-01-08 16:23:25 +0100670 if (!check_blocking(subscr, SGSN_SUBSCR_PROC_UPD_LOC)) {
671 LOGGSUBSCRP(
672 LOGL_NOTICE, subscr,
673 "Cannot start update location procedure, blocked\n");
674 abort_blocking_procedure(subscr);
675 return -EAGAIN;
676 }
677
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100678 LOGGSUBSCRP(LOGL_INFO, subscr,
679 "subscriber data is not available\n");
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100680
681 gsup_msg.message_type = GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
682 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100683}
684
685void gprs_subscr_update(struct gsm_subscriber *subscr)
686{
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100687 LOGGSUBSCRP(LOGL_DEBUG, subscr, "Updating subscriber data\n");
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100688
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100689 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100690 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
691
Jacob Erlbeck359cafa2014-12-02 11:28:38 +0100692 sgsn_update_subscriber_data(subscr->sgsn_data->mm, subscr);
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100693}
694
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100695void gprs_subscr_update_auth_info(struct gsm_subscriber *subscr)
696{
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100697 LOGGSUBSCRP(LOGL_DEBUG, subscr,
698 "Updating subscriber authentication info\n");
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100699
700 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
701 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
702
703 sgsn_update_subscriber_data(subscr->sgsn_data->mm, subscr);
704}
705
706struct gsm_subscriber *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx)
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100707{
708 struct gsm_subscriber *subscr = NULL;
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100709
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100710 if (mmctx->subscr)
711 return subscr_get(mmctx->subscr);
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100712
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100713 if (mmctx->imsi[0])
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100714 subscr = gprs_subscr_get_by_imsi(mmctx->imsi);
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100715
716 if (!subscr) {
717 subscr = gprs_subscr_get_or_create(mmctx->imsi);
718 subscr->flags |= GSM_SUBSCRIBER_FIRST_CONTACT;
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100719 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100720 }
721
722 if (strcpy(subscr->equipment.imei, mmctx->imei) != 0) {
723 strncpy(subscr->equipment.imei, mmctx->imei, GSM_IMEI_LENGTH-1);
724 subscr->equipment.imei[GSM_IMEI_LENGTH-1] = 0;
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100725 }
726
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100727 if (subscr->lac != mmctx->ra.lac)
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100728 subscr->lac = mmctx->ra.lac;
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100729
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100730 subscr->sgsn_data->mm = mmctx;
731 mmctx->subscr = subscr_get(subscr);
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100732
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100733 return subscr;
734}
735
736int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx)
737{
738 struct gsm_subscriber *subscr = NULL;
739 int rc;
740
741 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber data update\n");
742
743 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
744
745 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
746
747 rc = gprs_subscr_location_update(subscr);
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100748 subscr_put(subscr);
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100749 return rc;
750}
751
752int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx)
753{
754 struct gsm_subscriber *subscr = NULL;
755 int rc;
756
757 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber authentication info\n");
758
759 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
760
761 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
762
763 rc = gprs_subscr_query_auth_info(subscr);
764 subscr_put(subscr);
765 return rc;
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100766}