blob: 8399ea137802c8ae1992aa15a5b2b3f4b6e9e418 [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 Erlbeck9bf4be92015-01-06 16:32:41 +010079static void sgsn_subscriber_timeout_cb(void *subscr_);
80int gprs_subscr_purge(struct gsm_subscriber *subscr);
81
82void gprs_subscr_stop_timer(struct gsm_subscriber *subscr)
83{
84 if (subscr->sgsn_data->timer.data) {
85 osmo_timer_del(&subscr->sgsn_data->timer);
86 subscr->sgsn_data->timer.cb = NULL;
87 OSMO_ASSERT(subscr->sgsn_data->timer.data == subscr);
88 subscr->sgsn_data->timer.data = NULL;
89 subscr_put(subscr);
90 }
91}
92
93void gprs_subscr_start_timer(struct gsm_subscriber *subscr, unsigned seconds)
94{
95 if (!subscr->sgsn_data->timer.data) {
96 subscr->sgsn_data->timer.cb = sgsn_subscriber_timeout_cb;
97 subscr->sgsn_data->timer.data = subscr_get(subscr);
Jacob Erlbeck87972662015-01-08 15:18:39 +010098 subscr->sgsn_data->retries = 0;
Jacob Erlbeck9bf4be92015-01-06 16:32:41 +010099 }
100
101 osmo_timer_schedule(&subscr->sgsn_data->timer, seconds, 0);
102}
103
104static void sgsn_subscriber_timeout_cb(void *subscr_)
105{
106 struct gsm_subscriber *subscr = subscr_;
107
108 LOGGSUBSCRP(LOGL_INFO, subscr,
109 "Expired, deleting subscriber entry\n");
110
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100111 subscr_get(subscr);
112
113 /* Check, whether to cleanup immediately */
Jacob Erlbeck87972662015-01-08 15:18:39 +0100114 if (!(subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE) ||
115 subscr->sgsn_data->retries >= SGSN_SUBSCR_MAX_RETRIES)
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100116 goto force_cleanup;
117
118 /* Send a 'purge MS' message to the HLR */
119 if (gprs_subscr_purge(subscr) < 0)
120 goto force_cleanup;
121
122 /* Purge request has been sent */
123
Jacob Erlbeck87972662015-01-08 15:18:39 +0100124 /* Check, whether purge is still enabled */
125 if (!(subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE))
126 goto force_cleanup;
127
128 /* Make sure this will be tried again if there is no response in time */
129 subscr->sgsn_data->retries += 1;
130 gprs_subscr_start_timer(subscr, SGSN_SUBSCR_RETRY_INTERVAL);
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100131 subscr_put(subscr);
132 return;
133
134force_cleanup:
Jacob Erlbeck9bf4be92015-01-06 16:32:41 +0100135 /* Make sure, the timer is cleaned up */
136 subscr->keep_in_ram = 0;
137 gprs_subscr_stop_timer(subscr);
138 /* The subscr is freed now, if the timer was the last user */
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100139 subscr_put(subscr);
Jacob Erlbeck9bf4be92015-01-06 16:32:41 +0100140}
141
Jacob Erlbeck359cafa2014-12-02 11:28:38 +0100142static struct sgsn_subscriber_data *sgsn_subscriber_data_alloc(void *ctx)
143{
144 struct sgsn_subscriber_data *sdata;
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100145 int idx;
Jacob Erlbeck359cafa2014-12-02 11:28:38 +0100146
147 sdata = talloc_zero(ctx, struct sgsn_subscriber_data);
148
Jacob Erlbeckb1332b62014-12-08 15:52:00 +0100149 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
150 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
151
Jacob Erlbeck359cafa2014-12-02 11:28:38 +0100152 return sdata;
153}
154
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100155struct gsm_subscriber *gprs_subscr_get_or_create(const char *imsi)
156{
157 struct gsm_subscriber *subscr;
158
159 subscr = subscr_get_or_create(NULL, imsi);
160 if (!subscr)
161 return NULL;
162
Jacob Erlbeck359cafa2014-12-02 11:28:38 +0100163 if (!subscr->sgsn_data)
164 subscr->sgsn_data = sgsn_subscriber_data_alloc(subscr);
165
Jacob Erlbeck9bf4be92015-01-06 16:32:41 +0100166 gprs_subscr_stop_timer(subscr);
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100167
168 return subscr;
169}
170
171struct gsm_subscriber *gprs_subscr_get_by_imsi(const char *imsi)
172{
173 return subscr_active_by_imsi(NULL, imsi);
174}
175
176void gprs_subscr_delete(struct gsm_subscriber *subscr)
177{
Jacob Erlbeck359cafa2014-12-02 11:28:38 +0100178 if (subscr->sgsn_data->mm) {
179 subscr_put(subscr->sgsn_data->mm->subscr);
180 subscr->sgsn_data->mm->subscr = NULL;
181 subscr->sgsn_data->mm = NULL;
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100182 }
183
184 if ((subscr->flags & GPRS_SUBSCRIBER_CANCELLED) ||
Jacob Erlbeck9bf4be92015-01-06 16:32:41 +0100185 (subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT)) {
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100186 subscr->keep_in_ram = 0;
Jacob Erlbeck9bf4be92015-01-06 16:32:41 +0100187 gprs_subscr_stop_timer(subscr);
188 } else if (sgsn->cfg.subscriber_expiry_timeout != SGSN_TIMEOUT_NEVER) {
189 gprs_subscr_start_timer(subscr, sgsn->cfg.subscriber_expiry_timeout);
190 } else {
191 subscr->keep_in_ram = 1;
192 }
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100193
194 subscr_put(subscr);
195}
196
197void gprs_subscr_put_and_cancel(struct gsm_subscriber *subscr)
198{
199 subscr->authorized = 0;
200 subscr->flags |= GPRS_SUBSCRIBER_CANCELLED;
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100201 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100202
203 gprs_subscr_update(subscr);
204
205 gprs_subscr_delete(subscr);
206}
207
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100208static int gprs_subscr_tx_gsup_message(struct gsm_subscriber *subscr,
209 struct gprs_gsup_message *gsup_msg)
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100210{
Jacob Erlbeck233715c2014-12-18 12:46:47 +0100211 struct msgb *msg = gprs_gsup_msgb_alloc();
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100212
213 strncpy(gsup_msg->imsi, subscr->imsi, sizeof(gsup_msg->imsi) - 1);
214
215 gprs_gsup_encode(msg, gsup_msg);
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100216
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100217 LOGGSUBSCRP(LOGL_INFO, subscr,
218 "Sending GSUP, will send: %s\n", msgb_hexdump(msg));
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100219
Jacob Erlbeck233715c2014-12-18 12:46:47 +0100220 if (!sgsn->gsup_client) {
221 msgb_free(msg);
222 return -ENOTSUP;
223 }
224
225 return gprs_gsup_client_send(sgsn->gsup_client, msg);
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100226}
227
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100228static int gprs_subscr_handle_gsup_auth_res(struct gsm_subscriber *subscr,
229 struct gprs_gsup_message *gsup_msg)
230{
231 unsigned idx;
232 struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
233
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100234 LOGGSUBSCRP(LOGL_INFO, subscr,
235 "Got SendAuthenticationInfoResult, num_auth_tuples = %d\n",
236 gsup_msg->num_auth_tuples);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100237
238 if (gsup_msg->num_auth_tuples > 0) {
239 memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
240
241 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
242 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
243 }
244
245 for (idx = 0; idx < gsup_msg->num_auth_tuples; idx++) {
246 size_t key_seq = gsup_msg->auth_tuples[idx].key_seq;
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100247 LOGGSUBSCRP(LOGL_DEBUG, subscr,
248 "Adding auth tuple, cksn = %d\n", key_seq);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100249 if (key_seq >= ARRAY_SIZE(sdata->auth_triplets)) {
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100250 LOGGSUBSCRP(LOGL_NOTICE, subscr,
251 "Skipping auth triplet with invalid cksn %d\n",
252 key_seq);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100253 continue;
254 }
255 sdata->auth_triplets[key_seq] = gsup_msg->auth_tuples[idx];
256 }
257
258 sdata->auth_triplets_updated = 1;
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100259 sdata->error_cause = 0;
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100260
261 gprs_subscr_update_auth_info(subscr);
262
263 return 0;
264}
265
266static int gprs_subscr_handle_gsup_upd_loc_res(struct gsm_subscriber *subscr,
267 struct gprs_gsup_message *gsup_msg)
268{
269 unsigned idx;
270
271 if (gsup_msg->pdp_info_compl) {
272 LOGP(DGPRS, LOGL_INFO, "Would clear existing PDP info\n");
273
274 /* TODO: clear existing PDP info entries */
275 }
276
277 for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) {
278 struct gprs_gsup_pdp_info *pdp_info = &gsup_msg->pdp_infos[idx];
279 size_t ctx_id = pdp_info->context_id;
280
281 LOGP(DGPRS, LOGL_INFO,
282 "Would set PDP info, context id = %d, APN = %s\n",
283 ctx_id, osmo_hexdump(pdp_info->apn_enc, pdp_info->apn_enc_len));
284
285 /* TODO: set PDP info [ctx_id] */
286 }
287
288 subscr->authorized = 1;
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100289 subscr->sgsn_data->error_cause = 0;
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100290
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100291 subscr->flags |= GPRS_SUBSCRIBER_ENABLE_PURGE;
292
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100293 gprs_subscr_update(subscr);
294 return 0;
295}
296
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100297static int check_cause(int cause)
298{
299 switch (cause) {
300 case GMM_CAUSE_IMSI_UNKNOWN ... GMM_CAUSE_ILLEGAL_ME:
301 case GMM_CAUSE_GPRS_NOTALLOWED ... GMM_CAUSE_NO_GPRS_PLMN:
302 return EACCES;
303
304 case GMM_CAUSE_MSC_TEMP_NOTREACH ... GMM_CAUSE_CONGESTION:
Jacob Erlbecke4dc7fc2015-01-05 16:20:47 +0100305 return EHOSTUNREACH;
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100306
307 case GMM_CAUSE_SEM_INCORR_MSG ... GMM_CAUSE_PROTO_ERR_UNSPEC:
308 default:
309 return EINVAL;
310 }
311}
312
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100313static int gprs_subscr_handle_gsup_auth_err(struct gsm_subscriber *subscr,
314 struct gprs_gsup_message *gsup_msg)
315{
316 unsigned idx;
317 struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100318 int cause_err;
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100319
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100320 cause_err = check_cause(gsup_msg->cause);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100321
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100322 LOGGSUBSCRP(LOGL_DEBUG, subscr,
323 "Send authentication info has failed with cause %d, "
324 "handled as: %s\n",
325 gsup_msg->cause, strerror(cause_err));
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100326
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100327 switch (cause_err) {
328 case EACCES:
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100329 LOGGSUBSCRP(LOGL_NOTICE, subscr,
330 "GPRS send auth info req failed, access denied, "
331 "GMM cause = '%s' (%d)\n",
332 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
333 gsup_msg->cause);
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100334 /* Clear auth tuples */
335 memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
336 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
337 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100338
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100339 subscr->authorized = 0;
340 sdata->error_cause = gsup_msg->cause;
341 gprs_subscr_update_auth_info(subscr);
342 break;
343
Jacob Erlbecke4dc7fc2015-01-05 16:20:47 +0100344 case EHOSTUNREACH:
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100345 LOGGSUBSCRP(LOGL_NOTICE, subscr,
346 "GPRS send auth info req failed, GMM cause = '%s' (%d)\n",
347 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
348 gsup_msg->cause);
Jacob Erlbecke4dc7fc2015-01-05 16:20:47 +0100349
350 sdata->error_cause = gsup_msg->cause;
351 gprs_subscr_update_auth_info(subscr);
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100352 break;
353
354 default:
355 case EINVAL:
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100356 LOGGSUBSCRP(LOGL_ERROR, subscr,
357 "GSUP protocol remote error, GMM cause = '%s' (%d)\n",
358 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
359 gsup_msg->cause);
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100360 break;
361 }
362
363 return -gsup_msg->cause;
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100364}
365
366static int gprs_subscr_handle_gsup_upd_loc_err(struct gsm_subscriber *subscr,
367 struct gprs_gsup_message *gsup_msg)
368{
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100369 int cause_err;
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100370
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100371 cause_err = check_cause(gsup_msg->cause);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100372
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100373 LOGGSUBSCRP(LOGL_DEBUG, subscr,
374 "Update location has failed with cause %d, handled as: %s\n",
375 gsup_msg->cause, strerror(cause_err));
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100376
377 switch (cause_err) {
378 case EACCES:
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100379 LOGGSUBSCRP(LOGL_NOTICE, subscr,
380 "GPRS update location failed, access denied, "
381 "GMM cause = '%s' (%d)\n",
382 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
383 gsup_msg->cause);
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100384
385 subscr->authorized = 0;
386 subscr->sgsn_data->error_cause = gsup_msg->cause;
387 gprs_subscr_update_auth_info(subscr);
388 break;
389
Jacob Erlbecke4dc7fc2015-01-05 16:20:47 +0100390 case EHOSTUNREACH:
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100391 LOGGSUBSCRP(LOGL_NOTICE, subscr,
392 "GPRS update location failed, GMM cause = '%s' (%d)\n",
393 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
394 gsup_msg->cause);
Jacob Erlbecke4dc7fc2015-01-05 16:20:47 +0100395
396 subscr->sgsn_data->error_cause = gsup_msg->cause;
397 gprs_subscr_update_auth_info(subscr);
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100398 break;
399
400 default:
401 case EINVAL:
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100402 LOGGSUBSCRP(LOGL_ERROR, subscr,
403 "GSUP protocol remote error, GMM cause = '%s' (%d)\n",
404 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
405 gsup_msg->cause);
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100406 break;
407 }
408
409 return -gsup_msg->cause;
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100410}
411
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100412static int gprs_subscr_handle_gsup_purge_res(struct gsm_subscriber *subscr,
413 struct gprs_gsup_message *gsup_msg)
414{
415 LOGGSUBSCRP(LOGL_INFO, subscr, "Completing purge MS\n");
416
417 /* Force silent cancellation */
418 subscr->sgsn_data->error_cause = 0;
419 gprs_subscr_put_and_cancel(subscr_get(subscr));
420
421 return 0;
422}
423
424static int gprs_subscr_handle_gsup_purge_err(struct gsm_subscriber *subscr,
425 struct gprs_gsup_message *gsup_msg)
426{
427 LOGGSUBSCRP(LOGL_NOTICE, subscr,
428 "Purge MS has failed with cause '%s' (%d)\n",
429 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
430 gsup_msg->cause);
431
432 /* In GSM 09.02, 19.1.4.4, the text and the SDL diagram imply that
433 * the subscriber data is not removed if the request has failed. On the
434 * other hand, keeping the subscriber data in either error case
435 * (subscriber unknown, syntactical message error, connection error)
436 * doesn't seem to give any advantage, since the data will be restored
437 * on the next Attach Request anyway.
438 * This approach ensures, that the subscriber record will not stick if
439 * an error happens.
440 */
441
442 /* TODO: Check whether this behaviour is acceptable and either just
443 * remove this TODO-notice or change the implementation to not delete
444 * the subscriber data (eventually resetting the ENABLE_PURGE flag and
445 * restarting the expiry timer based on the cause).
446 *
447 * Subscriber Unknown: cancel subscr
448 * Temporary network problems: do nothing (handled by timer based retry)
449 * Message problems (syntax, nyi, ...): cancel subscr (retry won't help)
450 */
451
452 gprs_subscr_handle_gsup_purge_res(subscr, gsup_msg);
453
454 return -gsup_msg->cause;
455}
456
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100457int gprs_subscr_rx_gsup_message(struct msgb *msg)
458{
459 uint8_t *data = msgb_l2(msg);
460 size_t data_len = msgb_l2len(msg);
461 int rc = 0;
462
463 struct gprs_gsup_message gsup_msg = {0};
464 struct gsm_subscriber *subscr;
465
466 rc = gprs_gsup_decode(data, data_len, &gsup_msg);
467 if (rc < 0) {
468 LOGP(DGPRS, LOGL_ERROR,
Jacob Erlbeck092bbc82015-01-05 18:57:32 +0100469 "decoding GSUP message fails with error '%s' (%d)\n",
470 get_value_string(gsm48_gmm_cause_names, -rc), -rc);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100471 return rc;
472 }
473
474 if (!gsup_msg.imsi[0])
475 return -GMM_CAUSE_INV_MAND_INFO;
476
477 if (gsup_msg.message_type == GPRS_GSUP_MSGT_INSERT_DATA_REQUEST)
478 subscr = gprs_subscr_get_or_create(gsup_msg.imsi);
479 else
480 subscr = gprs_subscr_get_by_imsi(gsup_msg.imsi);
481
482 if (!subscr) {
483 LOGP(DGPRS, LOGL_NOTICE,
484 "Unknown IMSI %s, discarding GSUP message\n", gsup_msg.imsi);
485 return -GMM_CAUSE_IMSI_UNKNOWN;
486 }
487
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100488 LOGGSUBSCRP(LOGL_INFO, subscr,
489 "Received GSUP message of type 0x%02x\n", gsup_msg.message_type);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100490
491 switch (gsup_msg.message_type) {
492 case GPRS_GSUP_MSGT_LOCATION_CANCEL_REQUEST:
Jacob Erlbeckd1892d42015-01-05 18:38:41 +0100493 subscr->sgsn_data->error_cause = 0;
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100494 gprs_subscr_put_and_cancel(subscr);
495 subscr = NULL;
496 break;
497
498 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
Jacob Erlbeck092bbc82015-01-05 18:57:32 +0100499 rc = gprs_subscr_handle_gsup_auth_res(subscr, &gsup_msg);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100500 break;
501
502 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
Jacob Erlbeck092bbc82015-01-05 18:57:32 +0100503 rc = gprs_subscr_handle_gsup_auth_err(subscr, &gsup_msg);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100504 break;
505
506 case GPRS_GSUP_MSGT_UPDATE_LOCATION_RESULT:
Jacob Erlbeck092bbc82015-01-05 18:57:32 +0100507 rc = gprs_subscr_handle_gsup_upd_loc_res(subscr, &gsup_msg);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100508 break;
509
510 case GPRS_GSUP_MSGT_UPDATE_LOCATION_ERROR:
Jacob Erlbeck092bbc82015-01-05 18:57:32 +0100511 rc = gprs_subscr_handle_gsup_upd_loc_err(subscr, &gsup_msg);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100512 break;
513
514 case GPRS_GSUP_MSGT_PURGE_MS_ERROR:
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100515 rc = gprs_subscr_handle_gsup_purge_err(subscr, &gsup_msg);
516 break;
517
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100518 case GPRS_GSUP_MSGT_PURGE_MS_RESULT:
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100519 rc = gprs_subscr_handle_gsup_purge_res(subscr, &gsup_msg);
520 break;
521
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100522 case GPRS_GSUP_MSGT_INSERT_DATA_REQUEST:
523 case GPRS_GSUP_MSGT_DELETE_DATA_REQUEST:
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100524 LOGGSUBSCRP(LOGL_ERROR, subscr,
525 "Rx GSUP message type %d not yet implemented\n",
526 gsup_msg.message_type);
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100527 rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
528 break;
529
530 default:
Jacob Erlbeck387d6d92014-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 Erlbeck5641cfc2014-12-12 15:01:37 +0100534 rc = -GMM_CAUSE_MSGT_INCOMP_P_STATE;
535 break;
536 };
537
538 if (subscr)
539 subscr_put(subscr);
540
541 return rc;
542}
543
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100544int gprs_subscr_purge(struct gsm_subscriber *subscr)
545{
546 struct gprs_gsup_message gsup_msg = {0};
547
548 LOGGSUBSCRP(LOGL_INFO, subscr, "purging MS subscriber\n");
549
550 gsup_msg.message_type = GPRS_GSUP_MSGT_PURGE_MS_REQUEST;
551 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
552}
553
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100554int gprs_subscr_query_auth_info(struct gsm_subscriber *subscr)
555{
556 struct gprs_gsup_message gsup_msg = {0};
557
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100558 LOGGSUBSCRP(LOGL_INFO, subscr,
559 "subscriber auth info is not available\n");
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100560
561 gsup_msg.message_type = GPRS_GSUP_MSGT_SEND_AUTH_INFO_REQUEST;
562 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
563}
564
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100565int gprs_subscr_location_update(struct gsm_subscriber *subscr)
566{
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100567 struct gprs_gsup_message gsup_msg = {0};
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100568
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100569 LOGGSUBSCRP(LOGL_INFO, subscr,
570 "subscriber data is not available\n");
Jacob Erlbeck5641cfc2014-12-12 15:01:37 +0100571
572 gsup_msg.message_type = GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
573 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100574}
575
576void gprs_subscr_update(struct gsm_subscriber *subscr)
577{
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100578 LOGGSUBSCRP(LOGL_DEBUG, subscr, "Updating subscriber data\n");
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100579
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100580 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100581 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
582
Jacob Erlbeck359cafa2014-12-02 11:28:38 +0100583 sgsn_update_subscriber_data(subscr->sgsn_data->mm, subscr);
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100584}
585
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100586void gprs_subscr_update_auth_info(struct gsm_subscriber *subscr)
587{
Jacob Erlbeck387d6d92014-12-23 14:24:16 +0100588 LOGGSUBSCRP(LOGL_DEBUG, subscr,
589 "Updating subscriber authentication info\n");
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100590
591 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
592 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
593
594 sgsn_update_subscriber_data(subscr->sgsn_data->mm, subscr);
595}
596
597struct gsm_subscriber *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx)
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100598{
599 struct gsm_subscriber *subscr = NULL;
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100600
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100601 if (mmctx->subscr)
602 return subscr_get(mmctx->subscr);
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100603
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100604 if (mmctx->imsi[0])
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100605 subscr = gprs_subscr_get_by_imsi(mmctx->imsi);
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100606
607 if (!subscr) {
608 subscr = gprs_subscr_get_or_create(mmctx->imsi);
609 subscr->flags |= GSM_SUBSCRIBER_FIRST_CONTACT;
Jacob Erlbeckb3982c12015-01-06 16:32:41 +0100610 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100611 }
612
613 if (strcpy(subscr->equipment.imei, mmctx->imei) != 0) {
614 strncpy(subscr->equipment.imei, mmctx->imei, GSM_IMEI_LENGTH-1);
615 subscr->equipment.imei[GSM_IMEI_LENGTH-1] = 0;
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100616 }
617
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100618 if (subscr->lac != mmctx->ra.lac)
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100619 subscr->lac = mmctx->ra.lac;
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100620
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100621 subscr->sgsn_data->mm = mmctx;
622 mmctx->subscr = subscr_get(subscr);
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100623
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100624 return subscr;
625}
626
627int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx)
628{
629 struct gsm_subscriber *subscr = NULL;
630 int rc;
631
632 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber data update\n");
633
634 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
635
636 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
637
638 rc = gprs_subscr_location_update(subscr);
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100639 subscr_put(subscr);
Jacob Erlbeck828059f2014-11-28 14:55:25 +0100640 return rc;
641}
642
643int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx)
644{
645 struct gsm_subscriber *subscr = NULL;
646 int rc;
647
648 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber authentication info\n");
649
650 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
651
652 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
653
654 rc = gprs_subscr_query_auth_info(subscr);
655 subscr_put(subscr);
656 return rc;
Jacob Erlbecke8b69682014-11-12 10:12:11 +0100657}