blob: 461b3a573087084a8397b34824f35bd03d15f68a [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>
23
24#include <openbsc/sgsn.h>
25#include <openbsc/gprs_sgsn.h>
26#include <openbsc/gprs_gmm.h>
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +010027#include <openbsc/gprs_gsup_messages.h>
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010028
29#include <openbsc/debug.h>
30
31extern void *tall_bsc_ctx;
32
33void gprs_subscr_init(struct sgsn_instance *sgi)
34{
35}
36
Jacob Erlbecka1e03732014-12-02 11:28:38 +010037static struct sgsn_subscriber_data *sgsn_subscriber_data_alloc(void *ctx)
38{
39 struct sgsn_subscriber_data *sdata;
Jacob Erlbeck7921ab12014-12-08 15:52:00 +010040 int idx;
Jacob Erlbecka1e03732014-12-02 11:28:38 +010041
42 sdata = talloc_zero(ctx, struct sgsn_subscriber_data);
43
Jacob Erlbeck7921ab12014-12-08 15:52:00 +010044 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
45 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
46
Jacob Erlbecka1e03732014-12-02 11:28:38 +010047 return sdata;
48}
49
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010050struct gsm_subscriber *gprs_subscr_get_or_create(const char *imsi)
51{
52 struct gsm_subscriber *subscr;
53
54 subscr = subscr_get_or_create(NULL, imsi);
55 if (!subscr)
56 return NULL;
57
Jacob Erlbecka1e03732014-12-02 11:28:38 +010058 if (!subscr->sgsn_data)
59 subscr->sgsn_data = sgsn_subscriber_data_alloc(subscr);
60
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010061 subscr->keep_in_ram = 1;
62
63 return subscr;
64}
65
66struct gsm_subscriber *gprs_subscr_get_by_imsi(const char *imsi)
67{
68 return subscr_active_by_imsi(NULL, imsi);
69}
70
71void gprs_subscr_delete(struct gsm_subscriber *subscr)
72{
Jacob Erlbecka1e03732014-12-02 11:28:38 +010073 if (subscr->sgsn_data->mm) {
74 subscr_put(subscr->sgsn_data->mm->subscr);
75 subscr->sgsn_data->mm->subscr = NULL;
76 subscr->sgsn_data->mm = NULL;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010077 }
78
79 if ((subscr->flags & GPRS_SUBSCRIBER_CANCELLED) ||
80 (subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT))
81 subscr->keep_in_ram = 0;
82
83 subscr_put(subscr);
84}
85
86void gprs_subscr_put_and_cancel(struct gsm_subscriber *subscr)
87{
88 subscr->authorized = 0;
89 subscr->flags |= GPRS_SUBSCRIBER_CANCELLED;
90
91 gprs_subscr_update(subscr);
92
93 gprs_subscr_delete(subscr);
94}
95
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +010096static int gprs_subscr_tx_gsup_message(struct gsm_subscriber *subscr,
97 struct gprs_gsup_message *gsup_msg)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010098{
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +010099 struct msgb *msg = msgb_alloc(4096, __func__);
100
101 strncpy(gsup_msg->imsi, subscr->imsi, sizeof(gsup_msg->imsi) - 1);
102
103 gprs_gsup_encode(msg, gsup_msg);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100104
105 LOGMMCTXP(LOGL_INFO, subscr->sgsn_data->mm,
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100106 "Sending GSUP NYI, would send: %s\n", msgb_hexdump(msg));
107 msgb_free(msg);
108
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100109 return -ENOTSUP;
110}
111
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100112static int gprs_subscr_handle_gsup_auth_res(struct gsm_subscriber *subscr,
113 struct gprs_gsup_message *gsup_msg)
114{
115 unsigned idx;
116 struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
117
118 LOGP(DGPRS, LOGL_INFO,
119 "Got SendAuthenticationInfoResult, num_auth_tuples = %d\n",
120 gsup_msg->num_auth_tuples);
121
122 if (gsup_msg->num_auth_tuples > 0) {
123 memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
124
125 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
126 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
127 }
128
129 for (idx = 0; idx < gsup_msg->num_auth_tuples; idx++) {
130 size_t key_seq = gsup_msg->auth_tuples[idx].key_seq;
131 LOGP(DGPRS, LOGL_DEBUG, "Adding auth tuple, cksn = %d\n", key_seq);
132 if (key_seq >= ARRAY_SIZE(sdata->auth_triplets)) {
133 LOGP(DGPRS, LOGL_NOTICE,
134 "Skipping auth triplet with invalid cksn %d\n",
135 key_seq);
136 continue;
137 }
138 sdata->auth_triplets[key_seq] = gsup_msg->auth_tuples[idx];
139 }
140
141 sdata->auth_triplets_updated = 1;
142
143 gprs_subscr_update_auth_info(subscr);
144
145 return 0;
146}
147
148static int gprs_subscr_handle_gsup_upd_loc_res(struct gsm_subscriber *subscr,
149 struct gprs_gsup_message *gsup_msg)
150{
151 unsigned idx;
152
153 if (gsup_msg->pdp_info_compl) {
154 LOGP(DGPRS, LOGL_INFO, "Would clear existing PDP info\n");
155
156 /* TODO: clear existing PDP info entries */
157 }
158
159 for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) {
160 struct gprs_gsup_pdp_info *pdp_info = &gsup_msg->pdp_infos[idx];
161 size_t ctx_id = pdp_info->context_id;
162
163 LOGP(DGPRS, LOGL_INFO,
164 "Would set PDP info, context id = %d, APN = %s\n",
165 ctx_id, osmo_hexdump(pdp_info->apn_enc, pdp_info->apn_enc_len));
166
167 /* TODO: set PDP info [ctx_id] */
168 }
169
170 subscr->authorized = 1;
171
172 gprs_subscr_update(subscr);
173 return 0;
174}
175
176static int gprs_subscr_handle_gsup_auth_err(struct gsm_subscriber *subscr,
177 struct gprs_gsup_message *gsup_msg)
178{
179 unsigned idx;
180 struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
181
182 LOGP(DGPRS, LOGL_INFO,
183 "Send authentication info has failed for IMSI %s with cause %d\n",
184 gsup_msg->imsi, gsup_msg->cause);
185
186 /* Clear auth tuples */
187 memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
188 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
189 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
190
191 subscr->authorized = 0;
192
193 gprs_subscr_update_auth_info(subscr);
194 return 0;
195}
196
197static int gprs_subscr_handle_gsup_upd_loc_err(struct gsm_subscriber *subscr,
198 struct gprs_gsup_message *gsup_msg)
199{
200 LOGP(DGPRS, LOGL_INFO,
201 "Update location has failed for IMSI %s with cause %d\n",
202 gsup_msg->imsi, gsup_msg->cause);
203
204 subscr->authorized = 0;
205
206 gprs_subscr_update(subscr);
207 return 0;
208}
209
210int gprs_subscr_rx_gsup_message(struct msgb *msg)
211{
212 uint8_t *data = msgb_l2(msg);
213 size_t data_len = msgb_l2len(msg);
214 int rc = 0;
215
216 struct gprs_gsup_message gsup_msg = {0};
217 struct gsm_subscriber *subscr;
218
219 rc = gprs_gsup_decode(data, data_len, &gsup_msg);
220 if (rc < 0) {
221 LOGP(DGPRS, LOGL_ERROR,
222 "decoding GSUP message fails with error code %d\n", -rc);
223 return rc;
224 }
225
226 if (!gsup_msg.imsi[0])
227 return -GMM_CAUSE_INV_MAND_INFO;
228
229 if (gsup_msg.message_type == GPRS_GSUP_MSGT_INSERT_DATA_REQUEST)
230 subscr = gprs_subscr_get_or_create(gsup_msg.imsi);
231 else
232 subscr = gprs_subscr_get_by_imsi(gsup_msg.imsi);
233
234 if (!subscr) {
235 LOGP(DGPRS, LOGL_NOTICE,
236 "Unknown IMSI %s, discarding GSUP message\n", gsup_msg.imsi);
237 return -GMM_CAUSE_IMSI_UNKNOWN;
238 }
239
240 LOGP(DGPRS, LOGL_INFO,
241 "Received GSUP message of type 0x%02x for IMSI %s\n",
242 gsup_msg.message_type, gsup_msg.imsi);
243
244 switch (gsup_msg.message_type) {
245 case GPRS_GSUP_MSGT_LOCATION_CANCEL_REQUEST:
246 gprs_subscr_put_and_cancel(subscr);
247 subscr = NULL;
248 break;
249
250 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
251 gprs_subscr_handle_gsup_auth_res(subscr, &gsup_msg);
252 break;
253
254 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
255 gprs_subscr_handle_gsup_auth_err(subscr, &gsup_msg);
256 break;
257
258 case GPRS_GSUP_MSGT_UPDATE_LOCATION_RESULT:
259 gprs_subscr_handle_gsup_upd_loc_res(subscr, &gsup_msg);
260 break;
261
262 case GPRS_GSUP_MSGT_UPDATE_LOCATION_ERROR:
263 gprs_subscr_handle_gsup_upd_loc_err(subscr, &gsup_msg);
264 break;
265
266 case GPRS_GSUP_MSGT_PURGE_MS_ERROR:
267 case GPRS_GSUP_MSGT_PURGE_MS_RESULT:
268 case GPRS_GSUP_MSGT_INSERT_DATA_REQUEST:
269 case GPRS_GSUP_MSGT_DELETE_DATA_REQUEST:
270 LOGP(DGPRS, LOGL_ERROR,
271 "Rx GSUP message type %d not yet implemented\n",
272 gsup_msg.message_type);
273 rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
274 break;
275
276 default:
277 LOGP(DGPRS, LOGL_ERROR,
278 "Rx GSUP message type %d not valid at SGSN\n",
279 gsup_msg.message_type);
280 rc = -GMM_CAUSE_MSGT_INCOMP_P_STATE;
281 break;
282 };
283
284 if (subscr)
285 subscr_put(subscr);
286
287 return rc;
288}
289
290int gprs_subscr_query_auth_info(struct gsm_subscriber *subscr)
291{
292 struct gprs_gsup_message gsup_msg = {0};
293
294 LOGMMCTXP(LOGL_INFO, subscr->sgsn_data->mm,
295 "subscriber auth info is not available\n");
296
297 gsup_msg.message_type = GPRS_GSUP_MSGT_SEND_AUTH_INFO_REQUEST;
298 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
299}
300
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100301int gprs_subscr_location_update(struct gsm_subscriber *subscr)
302{
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100303 struct gprs_gsup_message gsup_msg = {0};
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100304
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100305 LOGMMCTXP(LOGL_INFO, subscr->sgsn_data->mm,
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100306 "subscriber data is not available\n");
307
308 gsup_msg.message_type = GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
309 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100310}
311
312void gprs_subscr_update(struct gsm_subscriber *subscr)
313{
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100314 LOGMMCTXP(LOGL_DEBUG, subscr->sgsn_data->mm, "Updating subscriber data\n");
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100315
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100316 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100317 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
318
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100319 sgsn_update_subscriber_data(subscr->sgsn_data->mm, subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100320}
321
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100322void gprs_subscr_update_auth_info(struct gsm_subscriber *subscr)
323{
324 LOGMMCTXP(LOGL_DEBUG, subscr->sgsn_data->mm,
325 "Updating subscriber authentication info\n");
326
327 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
328 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
329
330 sgsn_update_subscriber_data(subscr->sgsn_data->mm, subscr);
331}
332
333struct gsm_subscriber *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100334{
335 struct gsm_subscriber *subscr = NULL;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100336
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100337 if (mmctx->subscr)
338 return subscr_get(mmctx->subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100339
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100340 if (mmctx->imsi[0])
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100341 subscr = gprs_subscr_get_by_imsi(mmctx->imsi);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100342
343 if (!subscr) {
344 subscr = gprs_subscr_get_or_create(mmctx->imsi);
345 subscr->flags |= GSM_SUBSCRIBER_FIRST_CONTACT;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100346 }
347
348 if (strcpy(subscr->equipment.imei, mmctx->imei) != 0) {
349 strncpy(subscr->equipment.imei, mmctx->imei, GSM_IMEI_LENGTH-1);
350 subscr->equipment.imei[GSM_IMEI_LENGTH-1] = 0;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100351 }
352
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100353 if (subscr->lac != mmctx->ra.lac)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100354 subscr->lac = mmctx->ra.lac;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100355
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100356 subscr->sgsn_data->mm = mmctx;
357 mmctx->subscr = subscr_get(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100358
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100359 return subscr;
360}
361
362int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx)
363{
364 struct gsm_subscriber *subscr = NULL;
365 int rc;
366
367 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber data update\n");
368
369 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
370
371 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
372
373 rc = gprs_subscr_location_update(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100374 subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100375 return rc;
376}
377
378int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx)
379{
380 struct gsm_subscriber *subscr = NULL;
381 int rc;
382
383 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber authentication info\n");
384
385 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
386
387 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
388
389 rc = gprs_subscr_query_auth_info(subscr);
390 subscr_put(subscr);
391 return rc;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100392}