blob: 58203bab8c944cbca4841e87b88b18b86c659f60 [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 Erlbeck33b6dad2014-11-12 10:12:11 +010035extern void *tall_bsc_ctx;
36
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010037static int gsup_read_cb(struct gprs_gsup_client *gsupc, struct msgb *msg);
38
39/* TODO: Some functions are specific to the SGSN, but this file is more general
40 * (it has gprs_* name). Either move these functions elsewhere, split them and
41 * move a part, or replace the gprs_ prefix by sgsn_. The applies to
42 * gprs_subscr_init, gsup_read_cb, and gprs_subscr_tx_gsup_message.
43 */
44
45int gprs_subscr_init(struct sgsn_instance *sgi)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010046{
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010047 const char *addr_str;
48
49 if (!sgi->cfg.gsup_server_addr.sin_addr.s_addr)
50 return 0;
51
52 addr_str = inet_ntoa(sgi->cfg.gsup_server_addr.sin_addr);
53
54 sgi->gsup_client = gprs_gsup_client_create(
55 addr_str, sgi->cfg.gsup_server_port,
56 &gsup_read_cb);
57
58 if (!sgi->gsup_client)
59 return -1;
60
61 return 1;
62}
63
64static int gsup_read_cb(struct gprs_gsup_client *gsupc, struct msgb *msg)
65{
66 int rc;
67
68 rc = gprs_subscr_rx_gsup_message(msg);
Jacob Erlbecke154d8b2014-12-19 19:15:55 +010069 msgb_free(msg);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010070 if (rc < 0)
71 return -1;
72
73 return rc;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010074}
75
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +010076static void sgsn_subscriber_timeout_cb(void *subscr_);
77int gprs_subscr_purge(struct gsm_subscriber *subscr);
78
79void gprs_subscr_stop_timer(struct gsm_subscriber *subscr)
80{
81 if (subscr->sgsn_data->timer.data) {
82 osmo_timer_del(&subscr->sgsn_data->timer);
83 subscr->sgsn_data->timer.cb = NULL;
84 OSMO_ASSERT(subscr->sgsn_data->timer.data == subscr);
85 subscr->sgsn_data->timer.data = NULL;
86 subscr_put(subscr);
87 }
88}
89
90void gprs_subscr_start_timer(struct gsm_subscriber *subscr, unsigned seconds)
91{
92 if (!subscr->sgsn_data->timer.data) {
93 subscr->sgsn_data->timer.cb = sgsn_subscriber_timeout_cb;
94 subscr->sgsn_data->timer.data = subscr_get(subscr);
95 }
96
97 osmo_timer_schedule(&subscr->sgsn_data->timer, seconds, 0);
98}
99
100static void sgsn_subscriber_timeout_cb(void *subscr_)
101{
102 struct gsm_subscriber *subscr = subscr_;
103
104 LOGGSUBSCRP(LOGL_INFO, subscr,
105 "Expired, deleting subscriber entry\n");
106
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100107 subscr_get(subscr);
108
109 /* Check, whether to cleanup immediately */
110 if (!(subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE))
111 goto force_cleanup;
112
113 /* Send a 'purge MS' message to the HLR */
114 if (gprs_subscr_purge(subscr) < 0)
115 goto force_cleanup;
116
117 /* Purge request has been sent */
118
119 subscr_put(subscr);
120 return;
121
122force_cleanup:
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +0100123 /* Make sure, the timer is cleaned up */
124 subscr->keep_in_ram = 0;
125 gprs_subscr_stop_timer(subscr);
126 /* The subscr is freed now, if the timer was the last user */
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100127 subscr_put(subscr);
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +0100128}
129
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100130static struct sgsn_subscriber_data *sgsn_subscriber_data_alloc(void *ctx)
131{
132 struct sgsn_subscriber_data *sdata;
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100133 int idx;
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100134
135 sdata = talloc_zero(ctx, struct sgsn_subscriber_data);
136
Jacob Erlbeck7921ab12014-12-08 15:52:00 +0100137 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
138 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
139
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100140 return sdata;
141}
142
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100143struct gsm_subscriber *gprs_subscr_get_or_create(const char *imsi)
144{
145 struct gsm_subscriber *subscr;
146
147 subscr = subscr_get_or_create(NULL, imsi);
148 if (!subscr)
149 return NULL;
150
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100151 if (!subscr->sgsn_data)
152 subscr->sgsn_data = sgsn_subscriber_data_alloc(subscr);
153
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +0100154 gprs_subscr_stop_timer(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100155
156 return subscr;
157}
158
159struct gsm_subscriber *gprs_subscr_get_by_imsi(const char *imsi)
160{
161 return subscr_active_by_imsi(NULL, imsi);
162}
163
164void gprs_subscr_delete(struct gsm_subscriber *subscr)
165{
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100166 if (subscr->sgsn_data->mm) {
167 subscr_put(subscr->sgsn_data->mm->subscr);
168 subscr->sgsn_data->mm->subscr = NULL;
169 subscr->sgsn_data->mm = NULL;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100170 }
171
172 if ((subscr->flags & GPRS_SUBSCRIBER_CANCELLED) ||
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +0100173 (subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT)) {
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100174 subscr->keep_in_ram = 0;
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +0100175 gprs_subscr_stop_timer(subscr);
176 } else if (sgsn->cfg.subscriber_expiry_timeout != SGSN_TIMEOUT_NEVER) {
177 gprs_subscr_start_timer(subscr, sgsn->cfg.subscriber_expiry_timeout);
178 } else {
179 subscr->keep_in_ram = 1;
180 }
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100181
182 subscr_put(subscr);
183}
184
185void gprs_subscr_put_and_cancel(struct gsm_subscriber *subscr)
186{
187 subscr->authorized = 0;
188 subscr->flags |= GPRS_SUBSCRIBER_CANCELLED;
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100189 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100190
191 gprs_subscr_update(subscr);
192
193 gprs_subscr_delete(subscr);
194}
195
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100196static int gprs_subscr_tx_gsup_message(struct gsm_subscriber *subscr,
197 struct gprs_gsup_message *gsup_msg)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100198{
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100199 struct msgb *msg = gprs_gsup_msgb_alloc();
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100200
201 strncpy(gsup_msg->imsi, subscr->imsi, sizeof(gsup_msg->imsi) - 1);
202
203 gprs_gsup_encode(msg, gsup_msg);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100204
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100205 LOGGSUBSCRP(LOGL_INFO, subscr,
206 "Sending GSUP, will send: %s\n", msgb_hexdump(msg));
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100207
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100208 if (!sgsn->gsup_client) {
209 msgb_free(msg);
210 return -ENOTSUP;
211 }
212
213 return gprs_gsup_client_send(sgsn->gsup_client, msg);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100214}
215
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100216static int gprs_subscr_handle_gsup_auth_res(struct gsm_subscriber *subscr,
217 struct gprs_gsup_message *gsup_msg)
218{
219 unsigned idx;
220 struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
221
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100222 LOGGSUBSCRP(LOGL_INFO, subscr,
223 "Got SendAuthenticationInfoResult, num_auth_tuples = %d\n",
224 gsup_msg->num_auth_tuples);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100225
226 if (gsup_msg->num_auth_tuples > 0) {
227 memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
228
229 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
230 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
231 }
232
233 for (idx = 0; idx < gsup_msg->num_auth_tuples; idx++) {
234 size_t key_seq = gsup_msg->auth_tuples[idx].key_seq;
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100235 LOGGSUBSCRP(LOGL_DEBUG, subscr,
236 "Adding auth tuple, cksn = %d\n", key_seq);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100237 if (key_seq >= ARRAY_SIZE(sdata->auth_triplets)) {
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100238 LOGGSUBSCRP(LOGL_NOTICE, subscr,
239 "Skipping auth triplet with invalid cksn %d\n",
240 key_seq);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100241 continue;
242 }
243 sdata->auth_triplets[key_seq] = gsup_msg->auth_tuples[idx];
244 }
245
246 sdata->auth_triplets_updated = 1;
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100247 sdata->error_cause = 0;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100248
249 gprs_subscr_update_auth_info(subscr);
250
251 return 0;
252}
253
254static int gprs_subscr_handle_gsup_upd_loc_res(struct gsm_subscriber *subscr,
255 struct gprs_gsup_message *gsup_msg)
256{
257 unsigned idx;
258
259 if (gsup_msg->pdp_info_compl) {
260 LOGP(DGPRS, LOGL_INFO, "Would clear existing PDP info\n");
261
262 /* TODO: clear existing PDP info entries */
263 }
264
265 for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) {
266 struct gprs_gsup_pdp_info *pdp_info = &gsup_msg->pdp_infos[idx];
267 size_t ctx_id = pdp_info->context_id;
268
269 LOGP(DGPRS, LOGL_INFO,
270 "Would set PDP info, context id = %d, APN = %s\n",
271 ctx_id, osmo_hexdump(pdp_info->apn_enc, pdp_info->apn_enc_len));
272
273 /* TODO: set PDP info [ctx_id] */
274 }
275
276 subscr->authorized = 1;
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100277 subscr->sgsn_data->error_cause = 0;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100278
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100279 subscr->flags |= GPRS_SUBSCRIBER_ENABLE_PURGE;
280
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100281 gprs_subscr_update(subscr);
282 return 0;
283}
284
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100285static int check_cause(int cause)
286{
287 switch (cause) {
288 case GMM_CAUSE_IMSI_UNKNOWN ... GMM_CAUSE_ILLEGAL_ME:
289 case GMM_CAUSE_GPRS_NOTALLOWED ... GMM_CAUSE_NO_GPRS_PLMN:
290 return EACCES;
291
292 case GMM_CAUSE_MSC_TEMP_NOTREACH ... GMM_CAUSE_CONGESTION:
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100293 return EHOSTUNREACH;
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100294
295 case GMM_CAUSE_SEM_INCORR_MSG ... GMM_CAUSE_PROTO_ERR_UNSPEC:
296 default:
297 return EINVAL;
298 }
299}
300
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100301static int gprs_subscr_handle_gsup_auth_err(struct gsm_subscriber *subscr,
302 struct gprs_gsup_message *gsup_msg)
303{
304 unsigned idx;
305 struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100306 int cause_err;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100307
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100308 cause_err = check_cause(gsup_msg->cause);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100309
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100310 LOGGSUBSCRP(LOGL_DEBUG, subscr,
311 "Send authentication info has failed with cause %d, "
312 "handled as: %s\n",
313 gsup_msg->cause, strerror(cause_err));
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100314
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100315 switch (cause_err) {
316 case EACCES:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100317 LOGGSUBSCRP(LOGL_NOTICE, subscr,
318 "GPRS send auth info req failed, access denied, "
319 "GMM cause = '%s' (%d)\n",
320 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
321 gsup_msg->cause);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100322 /* Clear auth tuples */
323 memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
324 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
325 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100326
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100327 subscr->authorized = 0;
328 sdata->error_cause = gsup_msg->cause;
329 gprs_subscr_update_auth_info(subscr);
330 break;
331
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100332 case EHOSTUNREACH:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100333 LOGGSUBSCRP(LOGL_NOTICE, subscr,
334 "GPRS send auth info req failed, GMM cause = '%s' (%d)\n",
335 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
336 gsup_msg->cause);
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100337
338 sdata->error_cause = gsup_msg->cause;
339 gprs_subscr_update_auth_info(subscr);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100340 break;
341
342 default:
343 case EINVAL:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100344 LOGGSUBSCRP(LOGL_ERROR, subscr,
345 "GSUP protocol remote error, 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 break;
349 }
350
351 return -gsup_msg->cause;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100352}
353
354static int gprs_subscr_handle_gsup_upd_loc_err(struct gsm_subscriber *subscr,
355 struct gprs_gsup_message *gsup_msg)
356{
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100357 int cause_err;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100358
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100359 cause_err = check_cause(gsup_msg->cause);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100360
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100361 LOGGSUBSCRP(LOGL_DEBUG, subscr,
362 "Update location has failed with cause %d, handled as: %s\n",
363 gsup_msg->cause, strerror(cause_err));
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100364
365 switch (cause_err) {
366 case EACCES:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100367 LOGGSUBSCRP(LOGL_NOTICE, subscr,
368 "GPRS update location 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 Erlbeck9aa99912015-01-05 18:38:41 +0100372
373 subscr->authorized = 0;
374 subscr->sgsn_data->error_cause = gsup_msg->cause;
375 gprs_subscr_update_auth_info(subscr);
376 break;
377
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100378 case EHOSTUNREACH:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100379 LOGGSUBSCRP(LOGL_NOTICE, subscr,
380 "GPRS update location failed, GMM cause = '%s' (%d)\n",
381 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
382 gsup_msg->cause);
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100383
384 subscr->sgsn_data->error_cause = gsup_msg->cause;
385 gprs_subscr_update_auth_info(subscr);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100386 break;
387
388 default:
389 case EINVAL:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100390 LOGGSUBSCRP(LOGL_ERROR, subscr,
391 "GSUP protocol remote error, GMM cause = '%s' (%d)\n",
392 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
393 gsup_msg->cause);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100394 break;
395 }
396
397 return -gsup_msg->cause;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100398}
399
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100400static int gprs_subscr_handle_gsup_purge_res(struct gsm_subscriber *subscr,
401 struct gprs_gsup_message *gsup_msg)
402{
403 LOGGSUBSCRP(LOGL_INFO, subscr, "Completing purge MS\n");
404
405 /* Force silent cancellation */
406 subscr->sgsn_data->error_cause = 0;
407 gprs_subscr_put_and_cancel(subscr_get(subscr));
408
409 return 0;
410}
411
412static int gprs_subscr_handle_gsup_purge_err(struct gsm_subscriber *subscr,
413 struct gprs_gsup_message *gsup_msg)
414{
415 LOGGSUBSCRP(LOGL_NOTICE, subscr,
416 "Purge MS has failed with cause '%s' (%d)\n",
417 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
418 gsup_msg->cause);
419
420 /* In GSM 09.02, 19.1.4.4, the text and the SDL diagram imply that
421 * the subscriber data is not removed if the request has failed. On the
422 * other hand, keeping the subscriber data in either error case
423 * (subscriber unknown, syntactical message error, connection error)
424 * doesn't seem to give any advantage, since the data will be restored
425 * on the next Attach Request anyway.
426 * This approach ensures, that the subscriber record will not stick if
427 * an error happens.
428 */
429
430 /* TODO: Check whether this behaviour is acceptable and either just
431 * remove this TODO-notice or change the implementation to not delete
432 * the subscriber data (eventually resetting the ENABLE_PURGE flag and
433 * restarting the expiry timer based on the cause).
434 *
435 * Subscriber Unknown: cancel subscr
436 * Temporary network problems: do nothing (handled by timer based retry)
437 * Message problems (syntax, nyi, ...): cancel subscr (retry won't help)
438 */
439
440 gprs_subscr_handle_gsup_purge_res(subscr, gsup_msg);
441
442 return -gsup_msg->cause;
443}
444
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100445int gprs_subscr_rx_gsup_message(struct msgb *msg)
446{
447 uint8_t *data = msgb_l2(msg);
448 size_t data_len = msgb_l2len(msg);
449 int rc = 0;
450
451 struct gprs_gsup_message gsup_msg = {0};
452 struct gsm_subscriber *subscr;
453
454 rc = gprs_gsup_decode(data, data_len, &gsup_msg);
455 if (rc < 0) {
456 LOGP(DGPRS, LOGL_ERROR,
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100457 "decoding GSUP message fails with error '%s' (%d)\n",
458 get_value_string(gsm48_gmm_cause_names, -rc), -rc);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100459 return rc;
460 }
461
462 if (!gsup_msg.imsi[0])
463 return -GMM_CAUSE_INV_MAND_INFO;
464
465 if (gsup_msg.message_type == GPRS_GSUP_MSGT_INSERT_DATA_REQUEST)
466 subscr = gprs_subscr_get_or_create(gsup_msg.imsi);
467 else
468 subscr = gprs_subscr_get_by_imsi(gsup_msg.imsi);
469
470 if (!subscr) {
471 LOGP(DGPRS, LOGL_NOTICE,
472 "Unknown IMSI %s, discarding GSUP message\n", gsup_msg.imsi);
473 return -GMM_CAUSE_IMSI_UNKNOWN;
474 }
475
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100476 LOGGSUBSCRP(LOGL_INFO, subscr,
477 "Received GSUP message of type 0x%02x\n", gsup_msg.message_type);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100478
479 switch (gsup_msg.message_type) {
480 case GPRS_GSUP_MSGT_LOCATION_CANCEL_REQUEST:
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100481 subscr->sgsn_data->error_cause = 0;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100482 gprs_subscr_put_and_cancel(subscr);
483 subscr = NULL;
484 break;
485
486 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100487 rc = gprs_subscr_handle_gsup_auth_res(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100488 break;
489
490 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100491 rc = gprs_subscr_handle_gsup_auth_err(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100492 break;
493
494 case GPRS_GSUP_MSGT_UPDATE_LOCATION_RESULT:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100495 rc = gprs_subscr_handle_gsup_upd_loc_res(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100496 break;
497
498 case GPRS_GSUP_MSGT_UPDATE_LOCATION_ERROR:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100499 rc = gprs_subscr_handle_gsup_upd_loc_err(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100500 break;
501
502 case GPRS_GSUP_MSGT_PURGE_MS_ERROR:
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100503 rc = gprs_subscr_handle_gsup_purge_err(subscr, &gsup_msg);
504 break;
505
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100506 case GPRS_GSUP_MSGT_PURGE_MS_RESULT:
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100507 rc = gprs_subscr_handle_gsup_purge_res(subscr, &gsup_msg);
508 break;
509
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100510 case GPRS_GSUP_MSGT_INSERT_DATA_REQUEST:
511 case GPRS_GSUP_MSGT_DELETE_DATA_REQUEST:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100512 LOGGSUBSCRP(LOGL_ERROR, subscr,
513 "Rx GSUP message type %d not yet implemented\n",
514 gsup_msg.message_type);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100515 rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
516 break;
517
518 default:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100519 LOGGSUBSCRP(LOGL_ERROR, subscr,
520 "Rx GSUP message type %d not valid at SGSN\n",
521 gsup_msg.message_type);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100522 rc = -GMM_CAUSE_MSGT_INCOMP_P_STATE;
523 break;
524 };
525
526 if (subscr)
527 subscr_put(subscr);
528
529 return rc;
530}
531
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100532int gprs_subscr_purge(struct gsm_subscriber *subscr)
533{
534 struct gprs_gsup_message gsup_msg = {0};
535
536 LOGGSUBSCRP(LOGL_INFO, subscr, "purging MS subscriber\n");
537
538 gsup_msg.message_type = GPRS_GSUP_MSGT_PURGE_MS_REQUEST;
539 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
540}
541
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100542int gprs_subscr_query_auth_info(struct gsm_subscriber *subscr)
543{
544 struct gprs_gsup_message gsup_msg = {0};
545
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100546 LOGGSUBSCRP(LOGL_INFO, subscr,
547 "subscriber auth info is not available\n");
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100548
549 gsup_msg.message_type = GPRS_GSUP_MSGT_SEND_AUTH_INFO_REQUEST;
550 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
551}
552
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100553int gprs_subscr_location_update(struct gsm_subscriber *subscr)
554{
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100555 struct gprs_gsup_message gsup_msg = {0};
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100556
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100557 LOGGSUBSCRP(LOGL_INFO, subscr,
558 "subscriber data is not available\n");
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100559
560 gsup_msg.message_type = GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
561 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100562}
563
564void gprs_subscr_update(struct gsm_subscriber *subscr)
565{
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100566 LOGGSUBSCRP(LOGL_DEBUG, subscr, "Updating subscriber data\n");
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100567
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100568 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100569 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
570
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100571 sgsn_update_subscriber_data(subscr->sgsn_data->mm, subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100572}
573
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100574void gprs_subscr_update_auth_info(struct gsm_subscriber *subscr)
575{
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100576 LOGGSUBSCRP(LOGL_DEBUG, subscr,
577 "Updating subscriber authentication info\n");
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100578
579 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
580 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
581
582 sgsn_update_subscriber_data(subscr->sgsn_data->mm, subscr);
583}
584
585struct gsm_subscriber *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100586{
587 struct gsm_subscriber *subscr = NULL;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100588
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100589 if (mmctx->subscr)
590 return subscr_get(mmctx->subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100591
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100592 if (mmctx->imsi[0])
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100593 subscr = gprs_subscr_get_by_imsi(mmctx->imsi);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100594
595 if (!subscr) {
596 subscr = gprs_subscr_get_or_create(mmctx->imsi);
597 subscr->flags |= GSM_SUBSCRIBER_FIRST_CONTACT;
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100598 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100599 }
600
601 if (strcpy(subscr->equipment.imei, mmctx->imei) != 0) {
602 strncpy(subscr->equipment.imei, mmctx->imei, GSM_IMEI_LENGTH-1);
603 subscr->equipment.imei[GSM_IMEI_LENGTH-1] = 0;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100604 }
605
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100606 if (subscr->lac != mmctx->ra.lac)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100607 subscr->lac = mmctx->ra.lac;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100608
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100609 subscr->sgsn_data->mm = mmctx;
610 mmctx->subscr = subscr_get(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100611
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100612 return subscr;
613}
614
615int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx)
616{
617 struct gsm_subscriber *subscr = NULL;
618 int rc;
619
620 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber data update\n");
621
622 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
623
624 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
625
626 rc = gprs_subscr_location_update(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100627 subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100628 return rc;
629}
630
631int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx)
632{
633 struct gsm_subscriber *subscr = NULL;
634 int rc;
635
636 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber authentication info\n");
637
638 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
639
640 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
641
642 rc = gprs_subscr_query_auth_info(subscr);
643 subscr_put(subscr);
644 return rc;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100645}