blob: 8486834391ab99e73e9002cbed8aa049d91edb92 [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 Erlbeck8000e0e2015-01-27 14:56:40 +0100495 int is_update_procedure = !gsup_msg->cancel_type || gsup_msg->cancel_type;
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100496
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100497 LOGGSUBSCRP(LOGL_INFO, subscr, "Cancelling MS subscriber (%s)\n",
498 is_update_procedure ?
499 "update procedure" : "subscription withdraw");
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100500
501 gsup_reply.message_type = GPRS_GSUP_MSGT_LOCATION_CANCEL_RESULT;
502 gprs_subscr_tx_gsup_message(subscr, &gsup_reply);
503
Jacob Erlbeck8000e0e2015-01-27 14:56:40 +0100504 if (is_update_procedure)
505 subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
506 else
507 /* Since a withdraw cause is not specified, just abort the
508 * current attachment. The following re-attachment should then
509 * be rejected with a proper cause value.
510 */
511 subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
512
Jacob Erlbeck37139e52015-01-23 13:52:55 +0100513 gprs_subscr_cancel(subscr);
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100514
515 return 0;
516}
517
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100518static int gprs_subscr_handle_unknown_imsi(struct gprs_gsup_message *gsup_msg)
519{
520 if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg->message_type)) {
521 gprs_subscr_tx_gsup_error_reply(NULL, gsup_msg,
522 GMM_CAUSE_IMSI_UNKNOWN);
523 LOGP(DGPRS, LOGL_NOTICE,
524 "Unknown IMSI %s, discarding GSUP request "
525 "of type 0x%02x\n",
526 gsup_msg->imsi, gsup_msg->message_type);
527 } else if (GPRS_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
528 LOGP(DGPRS, LOGL_NOTICE,
529 "Unknown IMSI %s, discarding GSUP error "
530 "of type 0x%02x, cause '%s' (%d)\n",
531 gsup_msg->imsi, gsup_msg->message_type,
532 get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
533 gsup_msg->cause);
534 } else {
535 LOGP(DGPRS, LOGL_NOTICE,
536 "Unknown IMSI %s, discarding GSUP response "
537 "of type 0x%02x\n",
538 gsup_msg->imsi, gsup_msg->message_type);
539 }
540
541 return -GMM_CAUSE_IMSI_UNKNOWN;
542}
543
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100544int gprs_subscr_rx_gsup_message(struct msgb *msg)
545{
546 uint8_t *data = msgb_l2(msg);
547 size_t data_len = msgb_l2len(msg);
548 int rc = 0;
549
550 struct gprs_gsup_message gsup_msg = {0};
551 struct gsm_subscriber *subscr;
552
553 rc = gprs_gsup_decode(data, data_len, &gsup_msg);
554 if (rc < 0) {
555 LOGP(DGPRS, LOGL_ERROR,
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100556 "decoding GSUP message fails with error '%s' (%d)\n",
557 get_value_string(gsm48_gmm_cause_names, -rc), -rc);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100558 return rc;
559 }
560
Jacob Erlbeck07f6e362015-01-29 14:00:28 +0100561 if (!gsup_msg.imsi[0]) {
562 LOGP(DGPRS, LOGL_ERROR, "Missing IMSI in GSUP message\n");
563
564 if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
565 gprs_subscr_tx_gsup_error_reply(NULL, &gsup_msg,
566 GMM_CAUSE_INV_MAND_INFO);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100567 return -GMM_CAUSE_INV_MAND_INFO;
Jacob Erlbeck07f6e362015-01-29 14:00:28 +0100568 }
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100569
Jacob Erlbeck9ff82892015-01-29 14:17:51 +0100570 if (!gsup_msg.cause && GPRS_GSUP_IS_MSGT_ERROR(gsup_msg.message_type))
571 gsup_msg.cause = GMM_CAUSE_NET_FAIL;
572
Jacob Erlbeck4dedb272015-01-15 17:50:16 +0100573 subscr = gprs_subscr_get_by_imsi(gsup_msg.imsi);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100574
Jacob Erlbeck929acdf2015-01-27 13:47:24 +0100575 if (!subscr) {
576 switch (gsup_msg.message_type) {
577 case GPRS_GSUP_MSGT_PURGE_MS_RESULT:
578 case GPRS_GSUP_MSGT_PURGE_MS_ERROR:
579 return gprs_subscr_handle_gsup_purge_no_subscr(&gsup_msg);
580 default:
581 return gprs_subscr_handle_unknown_imsi(&gsup_msg);
582 }
583 }
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100584
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100585 LOGGSUBSCRP(LOGL_INFO, subscr,
586 "Received GSUP message of type 0x%02x\n", gsup_msg.message_type);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100587
588 switch (gsup_msg.message_type) {
589 case GPRS_GSUP_MSGT_LOCATION_CANCEL_REQUEST:
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100590 rc = gprs_subscr_handle_loc_cancel_req(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100591 break;
592
593 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100594 rc = gprs_subscr_handle_gsup_auth_res(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100595 break;
596
597 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100598 rc = gprs_subscr_handle_gsup_auth_err(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100599 break;
600
601 case GPRS_GSUP_MSGT_UPDATE_LOCATION_RESULT:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100602 rc = gprs_subscr_handle_gsup_upd_loc_res(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100603 break;
604
605 case GPRS_GSUP_MSGT_UPDATE_LOCATION_ERROR:
Jacob Erlbeckbce20612015-01-05 18:57:32 +0100606 rc = gprs_subscr_handle_gsup_upd_loc_err(subscr, &gsup_msg);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100607 break;
608
609 case GPRS_GSUP_MSGT_PURGE_MS_ERROR:
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100610 rc = gprs_subscr_handle_gsup_purge_err(subscr, &gsup_msg);
611 break;
612
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100613 case GPRS_GSUP_MSGT_PURGE_MS_RESULT:
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100614 rc = gprs_subscr_handle_gsup_purge_res(subscr, &gsup_msg);
615 break;
616
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100617 case GPRS_GSUP_MSGT_INSERT_DATA_REQUEST:
618 case GPRS_GSUP_MSGT_DELETE_DATA_REQUEST:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100619 LOGGSUBSCRP(LOGL_ERROR, subscr,
620 "Rx GSUP message type %d not yet implemented\n",
621 gsup_msg.message_type);
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100622 gprs_subscr_tx_gsup_error_reply(subscr, &gsup_msg,
623 GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100624 rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
625 break;
626
627 default:
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100628 LOGGSUBSCRP(LOGL_ERROR, subscr,
629 "Rx GSUP message type %d not valid at SGSN\n",
630 gsup_msg.message_type);
Jacob Erlbeck9999fd92015-01-15 17:08:30 +0100631 if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
632 gprs_subscr_tx_gsup_error_reply(
633 subscr, &gsup_msg, GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
634 rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100635 break;
636 };
637
Jacob Erlbeck87c7ffc2015-01-08 15:29:01 +0100638 subscr_put(subscr);
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100639
640 return rc;
641}
642
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100643int gprs_subscr_purge(struct gsm_subscriber *subscr)
644{
645 struct gprs_gsup_message gsup_msg = {0};
646
647 LOGGSUBSCRP(LOGL_INFO, subscr, "purging MS subscriber\n");
648
649 gsup_msg.message_type = GPRS_GSUP_MSGT_PURGE_MS_REQUEST;
Jacob Erlbeckca69b0f2015-02-03 19:45:46 +0100650 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100651}
652
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100653int gprs_subscr_query_auth_info(struct gsm_subscriber *subscr)
654{
655 struct gprs_gsup_message gsup_msg = {0};
656
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100657 LOGGSUBSCRP(LOGL_INFO, subscr,
658 "subscriber auth info is not available\n");
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100659
660 gsup_msg.message_type = GPRS_GSUP_MSGT_SEND_AUTH_INFO_REQUEST;
661 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
662}
663
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100664int gprs_subscr_location_update(struct gsm_subscriber *subscr)
665{
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100666 struct gprs_gsup_message gsup_msg = {0};
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100667
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100668 LOGGSUBSCRP(LOGL_INFO, subscr,
669 "subscriber data is not available\n");
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100670
671 gsup_msg.message_type = GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
672 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100673}
674
675void gprs_subscr_update(struct gsm_subscriber *subscr)
676{
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100677 LOGGSUBSCRP(LOGL_DEBUG, subscr, "Updating subscriber data\n");
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100678
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100679 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100680 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
681
Jacob Erlbeck555b2e52015-01-26 13:52:42 +0100682 if (subscr->sgsn_data->mm)
683 sgsn_update_subscriber_data(subscr->sgsn_data->mm);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100684}
685
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100686void gprs_subscr_update_auth_info(struct gsm_subscriber *subscr)
687{
Jacob Erlbeckbf34c672014-12-23 14:24:16 +0100688 LOGGSUBSCRP(LOGL_DEBUG, subscr,
689 "Updating subscriber authentication info\n");
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100690
691 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
692 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
693
Jacob Erlbeck555b2e52015-01-26 13:52:42 +0100694 if (subscr->sgsn_data->mm)
695 sgsn_update_subscriber_data(subscr->sgsn_data->mm);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100696}
697
698struct gsm_subscriber *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100699{
700 struct gsm_subscriber *subscr = NULL;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100701
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100702 if (mmctx->subscr)
703 return subscr_get(mmctx->subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100704
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100705 if (mmctx->imsi[0])
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100706 subscr = gprs_subscr_get_by_imsi(mmctx->imsi);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100707
708 if (!subscr) {
709 subscr = gprs_subscr_get_or_create(mmctx->imsi);
710 subscr->flags |= GSM_SUBSCRIBER_FIRST_CONTACT;
Jacob Erlbeck65fa3f72015-01-06 16:32:41 +0100711 subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100712 }
713
714 if (strcpy(subscr->equipment.imei, mmctx->imei) != 0) {
715 strncpy(subscr->equipment.imei, mmctx->imei, GSM_IMEI_LENGTH-1);
716 subscr->equipment.imei[GSM_IMEI_LENGTH-1] = 0;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100717 }
718
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100719 if (subscr->lac != mmctx->ra.lac)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100720 subscr->lac = mmctx->ra.lac;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100721
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100722 subscr->sgsn_data->mm = mmctx;
723 mmctx->subscr = subscr_get(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100724
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100725 return subscr;
726}
727
728int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx)
729{
730 struct gsm_subscriber *subscr = NULL;
731 int rc;
732
733 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber data update\n");
734
735 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
736
737 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
738
739 rc = gprs_subscr_location_update(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100740 subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100741 return rc;
742}
743
744int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx)
745{
746 struct gsm_subscriber *subscr = NULL;
747 int rc;
748
749 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber authentication info\n");
750
751 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
752
753 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
754
755 rc = gprs_subscr_query_auth_info(subscr);
756 subscr_put(subscr);
757 return rc;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100758}