blob: e3da0f88fb7e4ebb0f1bb8a6f5b119c534063e11 [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 Erlbeck0e8add62014-12-17 14:03:35 +010029#include <openbsc/gprs_utils.h>
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010030
31#include <openbsc/debug.h>
32
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010033#include <netinet/in.h>
34#include <arpa/inet.h>
35
Jacob Erlbeck743dec42015-01-08 15:18:39 +010036#define SGSN_SUBSCR_MAX_RETRIES 3
37#define SGSN_SUBSCR_RETRY_INTERVAL 10
38
Jacob Erlbeck929acdf2015-01-27 13:47:24 +010039#define LOGGSUPP(level, gsup, fmt, args...) \
40 LOGP(DGPRS, level, "GSUP(%s) " fmt, \
41 (gsup)->imsi, \
42 ## args)
43
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010044extern void *tall_bsc_ctx;
45
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010046static int gsup_read_cb(struct gprs_gsup_client *gsupc, struct msgb *msg);
47
48/* TODO: Some functions are specific to the SGSN, but this file is more general
49 * (it has gprs_* name). Either move these functions elsewhere, split them and
50 * move a part, or replace the gprs_ prefix by sgsn_. The applies to
51 * gprs_subscr_init, gsup_read_cb, and gprs_subscr_tx_gsup_message.
52 */
53
54int gprs_subscr_init(struct sgsn_instance *sgi)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010055{
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010056 const char *addr_str;
57
58 if (!sgi->cfg.gsup_server_addr.sin_addr.s_addr)
59 return 0;
60
61 addr_str = inet_ntoa(sgi->cfg.gsup_server_addr.sin_addr);
62
63 sgi->gsup_client = gprs_gsup_client_create(
64 addr_str, sgi->cfg.gsup_server_port,
65 &gsup_read_cb);
66
67 if (!sgi->gsup_client)
68 return -1;
69
70 return 1;
71}
72
73static int gsup_read_cb(struct gprs_gsup_client *gsupc, struct msgb *msg)
74{
75 int rc;
76
77 rc = gprs_subscr_rx_gsup_message(msg);
Jacob Erlbecke154d8b2014-12-19 19:15:55 +010078 msgb_free(msg);
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010079 if (rc < 0)
80 return -1;
81
82 return rc;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010083}
84
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +010085int gprs_subscr_purge(struct gsm_subscriber *subscr);
86
Jacob Erlbecka1e03732014-12-02 11:28:38 +010087static struct sgsn_subscriber_data *sgsn_subscriber_data_alloc(void *ctx)
88{
89 struct sgsn_subscriber_data *sdata;
Jacob Erlbeck7921ab12014-12-08 15:52:00 +010090 int idx;
Jacob Erlbecka1e03732014-12-02 11:28:38 +010091
92 sdata = talloc_zero(ctx, struct sgsn_subscriber_data);
93
Jacob Erlbeckd6267d12015-01-19 11:10:04 +010094 sdata->error_cause = SGSN_ERROR_CAUSE_NONE;
95
Jacob Erlbeck7921ab12014-12-08 15:52:00 +010096 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
97 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
98
Jacob Erlbeck0e8add62014-12-17 14:03:35 +010099 INIT_LLIST_HEAD(&sdata->pdp_list);
100
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100101 return sdata;
102}
103
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100104struct sgsn_subscriber_pdp_data* sgsn_subscriber_pdp_data_alloc(
105 struct sgsn_subscriber_data *sdata)
106{
107 struct sgsn_subscriber_pdp_data* pdata;
108
109 pdata = talloc_zero(sdata, struct sgsn_subscriber_pdp_data);
110
111 llist_add_tail(&pdata->list, &sdata->pdp_list);
112
113 return pdata;
114}
115
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100116struct gsm_subscriber *gprs_subscr_get_or_create(const char *imsi)
117{
118 struct gsm_subscriber *subscr;
119
120 subscr = subscr_get_or_create(NULL, imsi);
121 if (!subscr)
122 return NULL;
123
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100124 if (!subscr->sgsn_data)
125 subscr->sgsn_data = sgsn_subscriber_data_alloc(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100126 return subscr;
127}
128
129struct gsm_subscriber *gprs_subscr_get_by_imsi(const char *imsi)
130{
131 return subscr_active_by_imsi(NULL, imsi);
132}
133
Jacob Erlbeck3e4e58f2015-01-26 11:07:24 +0100134void gprs_subscr_cleanup(struct gsm_subscriber *subscr)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100135{
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100136 if (subscr->sgsn_data->mm) {
137 subscr_put(subscr->sgsn_data->mm->subscr);
138 subscr->sgsn_data->mm->subscr = NULL;
139 subscr->sgsn_data->mm = NULL;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100140 }
141
Holger Hans Peter Freyther1d778fd2015-01-20 21:14:03 +0100142 if (subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE) {
143 gprs_subscr_purge(subscr);
144 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbeck0f47b8f2015-01-06 16:32:41 +0100145 }
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100146}
147
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100148void gprs_subscr_cancel(struct gsm_subscriber *subscr)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100149{
150 subscr->authorized = 0;
151 subscr->flags |= GPRS_SUBSCRIBER_CANCELLED;
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100152 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100153
154 gprs_subscr_update(subscr);
Jacob Erlbeck3e4e58f2015-01-26 11:07:24 +0100155 gprs_subscr_cleanup(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100156}
157
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100158static int gprs_subscr_tx_gsup_message(struct gsm_subscriber *subscr,
159 struct gprs_gsup_message *gsup_msg)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100160{
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100161 struct msgb *msg = gprs_gsup_msgb_alloc();
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100162
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100163 if (strlen(gsup_msg->imsi) == 0 && subscr)
164 strncpy(gsup_msg->imsi, subscr->imsi, sizeof(gsup_msg->imsi) - 1);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100165
166 gprs_gsup_encode(msg, gsup_msg);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100167
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100168 LOGGSUBSCRP(LOGL_INFO, subscr,
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100169 "Sending GSUP, will send: %s\n", msgb_hexdump(msg));
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100170
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100171 if (!sgsn->gsup_client) {
172 msgb_free(msg);
173 return -ENOTSUP;
174 }
175
176 return gprs_gsup_client_send(sgsn->gsup_client, msg);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100177}
178
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100179static int gprs_subscr_tx_gsup_error_reply(struct gsm_subscriber *subscr,
180 struct gprs_gsup_message *gsup_orig,
181 enum gsm48_gmm_cause cause)
182{
183 struct gprs_gsup_message gsup_reply = {0};
184
185 strncpy(gsup_reply.imsi, gsup_orig->imsi, sizeof(gsup_reply.imsi) - 1);
186 gsup_reply.cause = cause;
187 gsup_reply.message_type =
188 GPRS_GSUP_TO_MSGT_ERROR(gsup_orig->message_type);
189
190 return gprs_subscr_tx_gsup_message(subscr, &gsup_reply);
191}
192
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100193static int gprs_subscr_handle_gsup_auth_res(struct gsm_subscriber *subscr,
194 struct gprs_gsup_message *gsup_msg)
195{
196 unsigned idx;
197 struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
198
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100199 LOGGSUBSCRP(LOGL_INFO, subscr,
200 "Got SendAuthenticationInfoResult, num_auth_tuples = %d\n",
201 gsup_msg->num_auth_tuples);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100202
203 if (gsup_msg->num_auth_tuples > 0) {
204 memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
205
206 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
207 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
208 }
209
210 for (idx = 0; idx < gsup_msg->num_auth_tuples; idx++) {
211 size_t key_seq = gsup_msg->auth_tuples[idx].key_seq;
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100212 LOGGSUBSCRP(LOGL_DEBUG, subscr,
213 "Adding auth tuple, cksn = %d\n", key_seq);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100214 if (key_seq >= ARRAY_SIZE(sdata->auth_triplets)) {
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100215 LOGGSUBSCRP(LOGL_NOTICE, subscr,
216 "Skipping auth triplet with invalid cksn %d\n",
217 key_seq);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100218 continue;
219 }
220 sdata->auth_triplets[key_seq] = gsup_msg->auth_tuples[idx];
221 }
222
223 sdata->auth_triplets_updated = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100224 sdata->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100225
226 gprs_subscr_update_auth_info(subscr);
227
228 return 0;
229}
230
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100231static int gprs_subscr_pdp_data_clear(struct gsm_subscriber *subscr)
232{
233 struct sgsn_subscriber_pdp_data *pdp, *pdp2;
234 int count = 0;
235
236 llist_for_each_entry_safe(pdp, pdp2, &subscr->sgsn_data->pdp_list, list) {
237 llist_del(&pdp->list);
238 talloc_free(pdp);
239 count += 1;
240 }
241
242 return count;
243}
244
245static struct sgsn_subscriber_pdp_data *gprs_subscr_pdp_data_get_by_id(
246 struct gsm_subscriber *subscr, unsigned context_id)
247{
248 struct sgsn_subscriber_pdp_data *pdp;
249
250 llist_for_each_entry(pdp, &subscr->sgsn_data->pdp_list, list) {
251 if (pdp->context_id == context_id)
252 return pdp;
253 }
254
255 return NULL;
256}
257
258
259static void gprs_subscr_gsup_insert_data(struct gsm_subscriber *subscr,
260 struct gprs_gsup_message *gsup_msg)
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100261{
262 unsigned idx;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100263 int rc;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100264
265 if (gsup_msg->pdp_info_compl) {
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100266 rc = gprs_subscr_pdp_data_clear(subscr);
267 if (rc > 0)
268 LOGP(DGPRS, LOGL_INFO, "Cleared existing PDP info\n");
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100269 }
270
271 for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) {
272 struct gprs_gsup_pdp_info *pdp_info = &gsup_msg->pdp_infos[idx];
273 size_t ctx_id = pdp_info->context_id;
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100274 struct sgsn_subscriber_pdp_data *pdp_data;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100275
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100276 if (pdp_info->apn_enc_len >= sizeof(pdp_data->apn_str)-1) {
277 LOGGSUBSCRP(LOGL_ERROR, subscr,
278 "APN too long, context id = %d, APN = %s\n",
279 ctx_id, osmo_hexdump(pdp_info->apn_enc,
280 pdp_info->apn_enc_len));
281 continue;
282 }
283
284 LOGGSUBSCRP(LOGL_INFO, subscr,
285 "Will set PDP info, context id = %d, APN = %s\n",
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100286 ctx_id, osmo_hexdump(pdp_info->apn_enc, pdp_info->apn_enc_len));
287
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100288 /* Set PDP info [ctx_id] */
289 pdp_data = gprs_subscr_pdp_data_get_by_id(subscr, ctx_id);
290 if (!pdp_data) {
291 pdp_data = sgsn_subscriber_pdp_data_alloc(subscr->sgsn_data);
292 pdp_data->context_id = ctx_id;
293 }
294
295 OSMO_ASSERT(pdp_data != NULL);
296 pdp_data->pdp_type = pdp_info->pdp_type;
297 gprs_apn_to_str(pdp_data->apn_str,
298 pdp_info->apn_enc, pdp_info->apn_enc_len);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100299 }
Jacob Erlbeck0e8add62014-12-17 14:03:35 +0100300}
301
302static int gprs_subscr_handle_gsup_upd_loc_res(struct gsm_subscriber *subscr,
303 struct gprs_gsup_message *gsup_msg)
304{
305 gprs_subscr_gsup_insert_data(subscr, gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100306
307 subscr->authorized = 1;
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100308 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100309
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100310 subscr->flags |= GPRS_SUBSCRIBER_ENABLE_PURGE;
311
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100312 gprs_subscr_update(subscr);
313 return 0;
314}
315
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100316static int check_cause(int cause)
317{
318 switch (cause) {
319 case GMM_CAUSE_IMSI_UNKNOWN ... GMM_CAUSE_ILLEGAL_ME:
320 case GMM_CAUSE_GPRS_NOTALLOWED ... GMM_CAUSE_NO_GPRS_PLMN:
321 return EACCES;
322
323 case GMM_CAUSE_MSC_TEMP_NOTREACH ... GMM_CAUSE_CONGESTION:
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100324 return EHOSTUNREACH;
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100325
326 case GMM_CAUSE_SEM_INCORR_MSG ... GMM_CAUSE_PROTO_ERR_UNSPEC:
327 default:
328 return EINVAL;
329 }
330}
331
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100332static int gprs_subscr_handle_gsup_auth_err(struct gsm_subscriber *subscr,
333 struct gprs_gsup_message *gsup_msg)
334{
335 unsigned idx;
336 struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100337 int cause_err;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100338
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100339 cause_err = check_cause(gsup_msg->cause);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100340
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100341 LOGGSUBSCRP(LOGL_DEBUG, subscr,
342 "Send authentication info has failed with cause %d, "
343 "handled as: %s\n",
344 gsup_msg->cause, strerror(cause_err));
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100345
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100346 switch (cause_err) {
347 case EACCES:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100348 LOGGSUBSCRP(LOGL_NOTICE, subscr,
349 "GPRS send auth info req failed, access denied, "
350 "GMM cause = '%s' (%d)\n",
351 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
352 gsup_msg->cause);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100353 /* Clear auth tuples */
354 memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
355 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
356 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100357
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100358 subscr->authorized = 0;
359 sdata->error_cause = gsup_msg->cause;
360 gprs_subscr_update_auth_info(subscr);
361 break;
362
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100363 case EHOSTUNREACH:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100364 LOGGSUBSCRP(LOGL_NOTICE, subscr,
365 "GPRS send auth info req failed, GMM cause = '%s' (%d)\n",
366 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
367 gsup_msg->cause);
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100368
369 sdata->error_cause = gsup_msg->cause;
370 gprs_subscr_update_auth_info(subscr);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100371 break;
372
373 default:
374 case EINVAL:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100375 LOGGSUBSCRP(LOGL_ERROR, subscr,
376 "GSUP protocol remote error, GMM cause = '%s' (%d)\n",
377 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
378 gsup_msg->cause);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100379 break;
380 }
381
382 return -gsup_msg->cause;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100383}
384
385static int gprs_subscr_handle_gsup_upd_loc_err(struct gsm_subscriber *subscr,
386 struct gprs_gsup_message *gsup_msg)
387{
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100388 int cause_err;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100389
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100390 cause_err = check_cause(gsup_msg->cause);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100391
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100392 LOGGSUBSCRP(LOGL_DEBUG, subscr,
393 "Update location has failed with cause %d, handled as: %s\n",
394 gsup_msg->cause, strerror(cause_err));
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100395
396 switch (cause_err) {
397 case EACCES:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100398 LOGGSUBSCRP(LOGL_NOTICE, subscr,
399 "GPRS update location failed, access denied, "
400 "GMM cause = '%s' (%d)\n",
401 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
402 gsup_msg->cause);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100403
404 subscr->authorized = 0;
405 subscr->sgsn_data->error_cause = gsup_msg->cause;
406 gprs_subscr_update_auth_info(subscr);
407 break;
408
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100409 case EHOSTUNREACH:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100410 LOGGSUBSCRP(LOGL_NOTICE, subscr,
411 "GPRS update location failed, GMM cause = '%s' (%d)\n",
412 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
413 gsup_msg->cause);
Jacob Erlbeckf06fe292015-01-05 16:20:47 +0100414
415 subscr->sgsn_data->error_cause = gsup_msg->cause;
416 gprs_subscr_update_auth_info(subscr);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100417 break;
418
419 default:
420 case EINVAL:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100421 LOGGSUBSCRP(LOGL_ERROR, subscr,
422 "GSUP protocol remote error, GMM cause = '%s' (%d)\n",
423 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
424 gsup_msg->cause);
Jacob Erlbeck9aa99912015-01-05 18:38:41 +0100425 break;
426 }
427
428 return -gsup_msg->cause;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100429}
430
Jacob Erlbeck929acdf2015-01-27 13:47:24 +0100431static int gprs_subscr_handle_gsup_purge_no_subscr(
432 struct gprs_gsup_message *gsup_msg)
433{
434 if (GPRS_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
435 LOGGSUPP(LOGL_NOTICE, gsup_msg,
436 "Purge MS has failed with cause '%s' (%d)\n",
437 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
438 gsup_msg->cause);
439 return -gsup_msg->cause;
440 }
441
442 LOGGSUPP(LOGL_INFO, gsup_msg, "Completing purge MS\n");
443 return 0;
444}
445
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100446static int gprs_subscr_handle_gsup_purge_res(struct gsm_subscriber *subscr,
447 struct gprs_gsup_message *gsup_msg)
448{
449 LOGGSUBSCRP(LOGL_INFO, subscr, "Completing purge MS\n");
450
451 /* Force silent cancellation */
Jacob Erlbeckd6267d12015-01-19 11:10:04 +0100452 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100453 gprs_subscr_cancel(subscr);
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100454
455 return 0;
456}
457
458static int gprs_subscr_handle_gsup_purge_err(struct gsm_subscriber *subscr,
459 struct gprs_gsup_message *gsup_msg)
460{
461 LOGGSUBSCRP(LOGL_NOTICE, subscr,
462 "Purge MS has failed with cause '%s' (%d)\n",
463 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
464 gsup_msg->cause);
465
466 /* In GSM 09.02, 19.1.4.4, the text and the SDL diagram imply that
467 * the subscriber data is not removed if the request has failed. On the
468 * other hand, keeping the subscriber data in either error case
469 * (subscriber unknown, syntactical message error, connection error)
470 * doesn't seem to give any advantage, since the data will be restored
471 * on the next Attach Request anyway.
472 * This approach ensures, that the subscriber record will not stick if
473 * an error happens.
474 */
475
476 /* TODO: Check whether this behaviour is acceptable and either just
477 * remove this TODO-notice or change the implementation to not delete
478 * the subscriber data (eventually resetting the ENABLE_PURGE flag and
479 * restarting the expiry timer based on the cause).
480 *
481 * Subscriber Unknown: cancel subscr
482 * Temporary network problems: do nothing (handled by timer based retry)
483 * Message problems (syntax, nyi, ...): cancel subscr (retry won't help)
484 */
485
486 gprs_subscr_handle_gsup_purge_res(subscr, gsup_msg);
487
488 return -gsup_msg->cause;
489}
490
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100491static int gprs_subscr_handle_loc_cancel_req(struct gsm_subscriber *subscr,
492 struct gprs_gsup_message *gsup_msg)
493{
494 struct gprs_gsup_message gsup_reply = {0};
Jacob Erlbeck5b512052015-04-07 17:49:48 +0200495 int is_update_procedure = !gsup_msg->cancel_type ||
496 gsup_msg->cancel_type == GPRS_GSUP_CANCEL_TYPE_UPDATE;
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100497
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100498 LOGGSUBSCRP(LOGL_INFO, subscr, "Cancelling MS subscriber (%s)\n",
499 is_update_procedure ?
500 "update procedure" : "subscription withdraw");
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100501
502 gsup_reply.message_type = GPRS_GSUP_MSGT_LOCATION_CANCEL_RESULT;
503 gprs_subscr_tx_gsup_message(subscr, &gsup_reply);
504
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100505 if (is_update_procedure)
506 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
507 else
508 /* Since a withdraw cause is not specified, just abort the
509 * current attachment. The following re-attachment should then
510 * be rejected with a proper cause value.
511 */
512 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
513
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100514 gprs_subscr_cancel(subscr);
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100515
516 return 0;
517}
518
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100519static int gprs_subscr_handle_unknown_imsi(struct gprs_gsup_message *gsup_msg)
520{
521 if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg->message_type)) {
522 gprs_subscr_tx_gsup_error_reply(NULL, gsup_msg,
523 GMM_CAUSE_IMSI_UNKNOWN);
524 LOGP(DGPRS, LOGL_NOTICE,
525 "Unknown IMSI %s, discarding GSUP request "
526 "of type 0x%02x\n",
527 gsup_msg->imsi, gsup_msg->message_type);
528 } else if (GPRS_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
529 LOGP(DGPRS, LOGL_NOTICE,
530 "Unknown IMSI %s, discarding GSUP error "
531 "of type 0x%02x, cause '%s' (%d)\n",
532 gsup_msg->imsi, gsup_msg->message_type,
533 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
534 gsup_msg->cause);
535 } else {
536 LOGP(DGPRS, LOGL_NOTICE,
537 "Unknown IMSI %s, discarding GSUP response "
538 "of type 0x%02x\n",
539 gsup_msg->imsi, gsup_msg->message_type);
540 }
541
542 return -GMM_CAUSE_IMSI_UNKNOWN;
543}
544
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100545int gprs_subscr_rx_gsup_message(struct msgb *msg)
546{
547 uint8_t *data = msgb_l2(msg);
548 size_t data_len = msgb_l2len(msg);
549 int rc = 0;
550
551 struct gprs_gsup_message gsup_msg = {0};
552 struct gsm_subscriber *subscr;
553
554 rc = gprs_gsup_decode(data, data_len, &gsup_msg);
555 if (rc < 0) {
556 LOGP(DGPRS, LOGL_ERROR,
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100557 "decoding GSUP message fails with error '%s' (%d)\n",
558 get_value_string(gsm48_gmm_cause_names, -rc), -rc);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100559 return rc;
560 }
561
Jacob Erlbeck07f6e362015-01-29 14:00:28 +0100562 if (!gsup_msg.imsi[0]) {
563 LOGP(DGPRS, LOGL_ERROR, "Missing IMSI in GSUP message\n");
564
565 if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
566 gprs_subscr_tx_gsup_error_reply(NULL, &gsup_msg,
567 GMM_CAUSE_INV_MAND_INFO);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100568 return -GMM_CAUSE_INV_MAND_INFO;
Jacob Erlbeck07f6e362015-01-29 14:00:28 +0100569 }
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100570
Jacob Erlbeck9ff82892015-01-29 14:17:51 +0100571 if (!gsup_msg.cause && GPRS_GSUP_IS_MSGT_ERROR(gsup_msg.message_type))
572 gsup_msg.cause = GMM_CAUSE_NET_FAIL;
573
Jacob Erlbeck4dedb272015-01-15 17:50:16 +0100574 subscr = gprs_subscr_get_by_imsi(gsup_msg.imsi);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100575
Jacob Erlbeck929acdf2015-01-27 13:47:24 +0100576 if (!subscr) {
577 switch (gsup_msg.message_type) {
578 case GPRS_GSUP_MSGT_PURGE_MS_RESULT:
579 case GPRS_GSUP_MSGT_PURGE_MS_ERROR:
580 return gprs_subscr_handle_gsup_purge_no_subscr(&gsup_msg);
581 default:
582 return gprs_subscr_handle_unknown_imsi(&gsup_msg);
583 }
584 }
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100585
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100586 LOGGSUBSCRP(LOGL_INFO, subscr,
587 "Received GSUP message of type 0x%02x\n", gsup_msg.message_type);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100588
589 switch (gsup_msg.message_type) {
590 case GPRS_GSUP_MSGT_LOCATION_CANCEL_REQUEST:
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100591 rc = gprs_subscr_handle_loc_cancel_req(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100592 break;
593
594 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100595 rc = gprs_subscr_handle_gsup_auth_res(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100596 break;
597
598 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100599 rc = gprs_subscr_handle_gsup_auth_err(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100600 break;
601
602 case GPRS_GSUP_MSGT_UPDATE_LOCATION_RESULT:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100603 rc = gprs_subscr_handle_gsup_upd_loc_res(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100604 break;
605
606 case GPRS_GSUP_MSGT_UPDATE_LOCATION_ERROR:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100607 rc = gprs_subscr_handle_gsup_upd_loc_err(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100608 break;
609
610 case GPRS_GSUP_MSGT_PURGE_MS_ERROR:
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100611 rc = gprs_subscr_handle_gsup_purge_err(subscr, &gsup_msg);
612 break;
613
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100614 case GPRS_GSUP_MSGT_PURGE_MS_RESULT:
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100615 rc = gprs_subscr_handle_gsup_purge_res(subscr, &gsup_msg);
616 break;
617
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100618 case GPRS_GSUP_MSGT_INSERT_DATA_REQUEST:
619 case GPRS_GSUP_MSGT_DELETE_DATA_REQUEST:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100620 LOGGSUBSCRP(LOGL_ERROR, subscr,
621 "Rx GSUP message type %d not yet implemented\n",
622 gsup_msg.message_type);
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100623 gprs_subscr_tx_gsup_error_reply(subscr, &gsup_msg,
624 GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100625 rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
626 break;
627
628 default:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100629 LOGGSUBSCRP(LOGL_ERROR, subscr,
630 "Rx GSUP message type %d not valid at SGSN\n",
631 gsup_msg.message_type);
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100632 if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
633 gprs_subscr_tx_gsup_error_reply(
634 subscr, &gsup_msg, GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
635 rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100636 break;
637 };
638
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100639 subscr_put(subscr);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100640
641 return rc;
642}
643
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100644int gprs_subscr_purge(struct gsm_subscriber *subscr)
645{
646 struct gprs_gsup_message gsup_msg = {0};
647
648 LOGGSUBSCRP(LOGL_INFO, subscr, "purging MS subscriber\n");
649
650 gsup_msg.message_type = GPRS_GSUP_MSGT_PURGE_MS_REQUEST;
Jacob Erlbeckca69b0f2015-02-03 19:45:46 +0100651 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100652}
653
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100654int gprs_subscr_query_auth_info(struct gsm_subscriber *subscr)
655{
656 struct gprs_gsup_message gsup_msg = {0};
657
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100658 LOGGSUBSCRP(LOGL_INFO, subscr,
659 "subscriber auth info is not available\n");
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100660
661 gsup_msg.message_type = GPRS_GSUP_MSGT_SEND_AUTH_INFO_REQUEST;
662 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
663}
664
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100665int gprs_subscr_location_update(struct gsm_subscriber *subscr)
666{
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100667 struct gprs_gsup_message gsup_msg = {0};
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100668
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100669 LOGGSUBSCRP(LOGL_INFO, subscr,
670 "subscriber data is not available\n");
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100671
672 gsup_msg.message_type = GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
673 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100674}
675
676void gprs_subscr_update(struct gsm_subscriber *subscr)
677{
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100678 LOGGSUBSCRP(LOGL_DEBUG, subscr, "Updating subscriber data\n");
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100679
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100680 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100681 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
682
Jacob Erlbeck555b2e52015-01-26 13:52:42 +0100683 if (subscr->sgsn_data->mm)
684 sgsn_update_subscriber_data(subscr->sgsn_data->mm);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100685}
686
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100687void gprs_subscr_update_auth_info(struct gsm_subscriber *subscr)
688{
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100689 LOGGSUBSCRP(LOGL_DEBUG, subscr,
690 "Updating subscriber authentication info\n");
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100691
692 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
693 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
694
Jacob Erlbeck555b2e52015-01-26 13:52:42 +0100695 if (subscr->sgsn_data->mm)
696 sgsn_update_subscriber_data(subscr->sgsn_data->mm);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100697}
698
699struct gsm_subscriber *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100700{
701 struct gsm_subscriber *subscr = NULL;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100702
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100703 if (mmctx->subscr)
704 return subscr_get(mmctx->subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100705
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100706 if (mmctx->imsi[0])
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100707 subscr = gprs_subscr_get_by_imsi(mmctx->imsi);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100708
709 if (!subscr) {
710 subscr = gprs_subscr_get_or_create(mmctx->imsi);
711 subscr->flags |= GSM_SUBSCRIBER_FIRST_CONTACT;
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100712 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100713 }
714
715 if (strcpy(subscr->equipment.imei, mmctx->imei) != 0) {
716 strncpy(subscr->equipment.imei, mmctx->imei, GSM_IMEI_LENGTH-1);
717 subscr->equipment.imei[GSM_IMEI_LENGTH-1] = 0;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100718 }
719
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100720 if (subscr->lac != mmctx->ra.lac)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100721 subscr->lac = mmctx->ra.lac;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100722
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100723 subscr->sgsn_data->mm = mmctx;
724 mmctx->subscr = subscr_get(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100725
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100726 return subscr;
727}
728
729int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx)
730{
731 struct gsm_subscriber *subscr = NULL;
732 int rc;
733
734 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber data update\n");
735
736 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
737
738 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
739
740 rc = gprs_subscr_location_update(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100741 subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100742 return rc;
743}
744
745int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx)
746{
747 struct gsm_subscriber *subscr = NULL;
748 int rc;
749
750 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber authentication info\n");
751
752 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
753
754 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
755
756 rc = gprs_subscr_query_auth_info(subscr);
757 subscr_put(subscr);
758 return rc;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100759}