blob: 04debff2454ce907820d936267e4d725dd357595 [file] [log] [blame]
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +01001/* MS subscriber data handling */
2
3/* (C) 2014 by sysmocom s.f.m.c. GmbH
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include <openbsc/gsm_subscriber.h>
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010023#include <openbsc/gprs_gsup_client.h>
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010024
25#include <openbsc/sgsn.h>
26#include <openbsc/gprs_sgsn.h>
27#include <openbsc/gprs_gmm.h>
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +010028#include <openbsc/gprs_gsup_messages.h>
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010029
30#include <openbsc/debug.h>
31
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010032#include <netinet/in.h>
33#include <arpa/inet.h>
34
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010035extern void *tall_bsc_ctx;
36
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010037static int gsup_read_cb(struct gprs_gsup_client *gsupc, struct msgb *msg);
38
39/* TODO: Some functions are specific to the SGSN, but this file is more general
40 * (it has gprs_* name). Either move these functions elsewhere, split them and
41 * move a part, or replace the gprs_ prefix by sgsn_. The applies to
42 * gprs_subscr_init, gsup_read_cb, and gprs_subscr_tx_gsup_message.
43 */
44
45int gprs_subscr_init(struct sgsn_instance *sgi)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010046{
Jacob Erlbeck39f040d2014-12-18 12:46:47 +010047 const char *addr_str;
48
49 if (!sgi->cfg.gsup_server_addr.sin_addr.s_addr)
50 return 0;
51
52 addr_str = inet_ntoa(sgi->cfg.gsup_server_addr.sin_addr);
53
54 sgi->gsup_client = gprs_gsup_client_create(
55 addr_str, sgi->cfg.gsup_server_port,
56 &gsup_read_cb);
57
58 if (!sgi->gsup_client)
59 return -1;
60
61 return 1;
62}
63
64static int gsup_read_cb(struct gprs_gsup_client *gsupc, struct msgb *msg)
65{
66 int rc;
67
68 rc = gprs_subscr_rx_gsup_message(msg);
69 if (rc < 0)
70 return -1;
71
72 return rc;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010073}
74
Jacob Erlbecka1e03732014-12-02 11:28:38 +010075static struct sgsn_subscriber_data *sgsn_subscriber_data_alloc(void *ctx)
76{
77 struct sgsn_subscriber_data *sdata;
Jacob Erlbeck7921ab12014-12-08 15:52:00 +010078 int idx;
Jacob Erlbecka1e03732014-12-02 11:28:38 +010079
80 sdata = talloc_zero(ctx, struct sgsn_subscriber_data);
81
Jacob Erlbeck7921ab12014-12-08 15:52:00 +010082 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
83 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
84
Jacob Erlbecka1e03732014-12-02 11:28:38 +010085 return sdata;
86}
87
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010088struct gsm_subscriber *gprs_subscr_get_or_create(const char *imsi)
89{
90 struct gsm_subscriber *subscr;
91
92 subscr = subscr_get_or_create(NULL, imsi);
93 if (!subscr)
94 return NULL;
95
Jacob Erlbecka1e03732014-12-02 11:28:38 +010096 if (!subscr->sgsn_data)
97 subscr->sgsn_data = sgsn_subscriber_data_alloc(subscr);
98
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +010099 subscr->keep_in_ram = 1;
100
101 return subscr;
102}
103
104struct gsm_subscriber *gprs_subscr_get_by_imsi(const char *imsi)
105{
106 return subscr_active_by_imsi(NULL, imsi);
107}
108
109void gprs_subscr_delete(struct gsm_subscriber *subscr)
110{
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100111 if (subscr->sgsn_data->mm) {
112 subscr_put(subscr->sgsn_data->mm->subscr);
113 subscr->sgsn_data->mm->subscr = NULL;
114 subscr->sgsn_data->mm = NULL;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100115 }
116
117 if ((subscr->flags & GPRS_SUBSCRIBER_CANCELLED) ||
118 (subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT))
119 subscr->keep_in_ram = 0;
120
121 subscr_put(subscr);
122}
123
124void gprs_subscr_put_and_cancel(struct gsm_subscriber *subscr)
125{
126 subscr->authorized = 0;
127 subscr->flags |= GPRS_SUBSCRIBER_CANCELLED;
128
129 gprs_subscr_update(subscr);
130
131 gprs_subscr_delete(subscr);
132}
133
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100134static int gprs_subscr_tx_gsup_message(struct gsm_subscriber *subscr,
135 struct gprs_gsup_message *gsup_msg)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100136{
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100137 struct msgb *msg = gprs_gsup_msgb_alloc();
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100138
139 strncpy(gsup_msg->imsi, subscr->imsi, sizeof(gsup_msg->imsi) - 1);
140
141 gprs_gsup_encode(msg, gsup_msg);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100142
143 LOGMMCTXP(LOGL_INFO, subscr->sgsn_data->mm,
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100144 "Sending GSUP, will send: %s\n", msgb_hexdump(msg));
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100145
Jacob Erlbeck39f040d2014-12-18 12:46:47 +0100146 if (!sgsn->gsup_client) {
147 msgb_free(msg);
148 return -ENOTSUP;
149 }
150
151 return gprs_gsup_client_send(sgsn->gsup_client, msg);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100152}
153
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100154static int gprs_subscr_handle_gsup_auth_res(struct gsm_subscriber *subscr,
155 struct gprs_gsup_message *gsup_msg)
156{
157 unsigned idx;
158 struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
159
160 LOGP(DGPRS, LOGL_INFO,
161 "Got SendAuthenticationInfoResult, num_auth_tuples = %d\n",
162 gsup_msg->num_auth_tuples);
163
164 if (gsup_msg->num_auth_tuples > 0) {
165 memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
166
167 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
168 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
169 }
170
171 for (idx = 0; idx < gsup_msg->num_auth_tuples; idx++) {
172 size_t key_seq = gsup_msg->auth_tuples[idx].key_seq;
173 LOGP(DGPRS, LOGL_DEBUG, "Adding auth tuple, cksn = %d\n", key_seq);
174 if (key_seq >= ARRAY_SIZE(sdata->auth_triplets)) {
175 LOGP(DGPRS, LOGL_NOTICE,
176 "Skipping auth triplet with invalid cksn %d\n",
177 key_seq);
178 continue;
179 }
180 sdata->auth_triplets[key_seq] = gsup_msg->auth_tuples[idx];
181 }
182
183 sdata->auth_triplets_updated = 1;
184
185 gprs_subscr_update_auth_info(subscr);
186
187 return 0;
188}
189
190static int gprs_subscr_handle_gsup_upd_loc_res(struct gsm_subscriber *subscr,
191 struct gprs_gsup_message *gsup_msg)
192{
193 unsigned idx;
194
195 if (gsup_msg->pdp_info_compl) {
196 LOGP(DGPRS, LOGL_INFO, "Would clear existing PDP info\n");
197
198 /* TODO: clear existing PDP info entries */
199 }
200
201 for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) {
202 struct gprs_gsup_pdp_info *pdp_info = &gsup_msg->pdp_infos[idx];
203 size_t ctx_id = pdp_info->context_id;
204
205 LOGP(DGPRS, LOGL_INFO,
206 "Would set PDP info, context id = %d, APN = %s\n",
207 ctx_id, osmo_hexdump(pdp_info->apn_enc, pdp_info->apn_enc_len));
208
209 /* TODO: set PDP info [ctx_id] */
210 }
211
212 subscr->authorized = 1;
213
214 gprs_subscr_update(subscr);
215 return 0;
216}
217
218static int gprs_subscr_handle_gsup_auth_err(struct gsm_subscriber *subscr,
219 struct gprs_gsup_message *gsup_msg)
220{
221 unsigned idx;
222 struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
223
224 LOGP(DGPRS, LOGL_INFO,
225 "Send authentication info has failed for IMSI %s with cause %d\n",
226 gsup_msg->imsi, gsup_msg->cause);
227
228 /* Clear auth tuples */
229 memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
230 for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
231 sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
232
233 subscr->authorized = 0;
234
235 gprs_subscr_update_auth_info(subscr);
236 return 0;
237}
238
239static int gprs_subscr_handle_gsup_upd_loc_err(struct gsm_subscriber *subscr,
240 struct gprs_gsup_message *gsup_msg)
241{
242 LOGP(DGPRS, LOGL_INFO,
243 "Update location has failed for IMSI %s with cause %d\n",
244 gsup_msg->imsi, gsup_msg->cause);
245
246 subscr->authorized = 0;
247
248 gprs_subscr_update(subscr);
249 return 0;
250}
251
252int gprs_subscr_rx_gsup_message(struct msgb *msg)
253{
254 uint8_t *data = msgb_l2(msg);
255 size_t data_len = msgb_l2len(msg);
256 int rc = 0;
257
258 struct gprs_gsup_message gsup_msg = {0};
259 struct gsm_subscriber *subscr;
260
261 rc = gprs_gsup_decode(data, data_len, &gsup_msg);
262 if (rc < 0) {
263 LOGP(DGPRS, LOGL_ERROR,
264 "decoding GSUP message fails with error code %d\n", -rc);
265 return rc;
266 }
267
268 if (!gsup_msg.imsi[0])
269 return -GMM_CAUSE_INV_MAND_INFO;
270
271 if (gsup_msg.message_type == GPRS_GSUP_MSGT_INSERT_DATA_REQUEST)
272 subscr = gprs_subscr_get_or_create(gsup_msg.imsi);
273 else
274 subscr = gprs_subscr_get_by_imsi(gsup_msg.imsi);
275
276 if (!subscr) {
277 LOGP(DGPRS, LOGL_NOTICE,
278 "Unknown IMSI %s, discarding GSUP message\n", gsup_msg.imsi);
279 return -GMM_CAUSE_IMSI_UNKNOWN;
280 }
281
282 LOGP(DGPRS, LOGL_INFO,
283 "Received GSUP message of type 0x%02x for IMSI %s\n",
284 gsup_msg.message_type, gsup_msg.imsi);
285
286 switch (gsup_msg.message_type) {
287 case GPRS_GSUP_MSGT_LOCATION_CANCEL_REQUEST:
288 gprs_subscr_put_and_cancel(subscr);
289 subscr = NULL;
290 break;
291
292 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
293 gprs_subscr_handle_gsup_auth_res(subscr, &gsup_msg);
294 break;
295
296 case GPRS_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
297 gprs_subscr_handle_gsup_auth_err(subscr, &gsup_msg);
298 break;
299
300 case GPRS_GSUP_MSGT_UPDATE_LOCATION_RESULT:
301 gprs_subscr_handle_gsup_upd_loc_res(subscr, &gsup_msg);
302 break;
303
304 case GPRS_GSUP_MSGT_UPDATE_LOCATION_ERROR:
305 gprs_subscr_handle_gsup_upd_loc_err(subscr, &gsup_msg);
306 break;
307
308 case GPRS_GSUP_MSGT_PURGE_MS_ERROR:
309 case GPRS_GSUP_MSGT_PURGE_MS_RESULT:
310 case GPRS_GSUP_MSGT_INSERT_DATA_REQUEST:
311 case GPRS_GSUP_MSGT_DELETE_DATA_REQUEST:
312 LOGP(DGPRS, LOGL_ERROR,
313 "Rx GSUP message type %d not yet implemented\n",
314 gsup_msg.message_type);
315 rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
316 break;
317
318 default:
319 LOGP(DGPRS, LOGL_ERROR,
320 "Rx GSUP message type %d not valid at SGSN\n",
321 gsup_msg.message_type);
322 rc = -GMM_CAUSE_MSGT_INCOMP_P_STATE;
323 break;
324 };
325
326 if (subscr)
327 subscr_put(subscr);
328
329 return rc;
330}
331
332int gprs_subscr_query_auth_info(struct gsm_subscriber *subscr)
333{
334 struct gprs_gsup_message gsup_msg = {0};
335
336 LOGMMCTXP(LOGL_INFO, subscr->sgsn_data->mm,
337 "subscriber auth info is not available\n");
338
339 gsup_msg.message_type = GPRS_GSUP_MSGT_SEND_AUTH_INFO_REQUEST;
340 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
341}
342
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100343int gprs_subscr_location_update(struct gsm_subscriber *subscr)
344{
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100345 struct gprs_gsup_message gsup_msg = {0};
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100346
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100347 LOGMMCTXP(LOGL_INFO, subscr->sgsn_data->mm,
Jacob Erlbecka6ddc2d2014-12-12 15:01:37 +0100348 "subscriber data is not available\n");
349
350 gsup_msg.message_type = GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
351 return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100352}
353
354void gprs_subscr_update(struct gsm_subscriber *subscr)
355{
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100356 LOGMMCTXP(LOGL_DEBUG, subscr->sgsn_data->mm, "Updating subscriber data\n");
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100357
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100358 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100359 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
360
Jacob Erlbecka1e03732014-12-02 11:28:38 +0100361 sgsn_update_subscriber_data(subscr->sgsn_data->mm, subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100362}
363
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100364void gprs_subscr_update_auth_info(struct gsm_subscriber *subscr)
365{
366 LOGMMCTXP(LOGL_DEBUG, subscr->sgsn_data->mm,
367 "Updating subscriber authentication info\n");
368
369 subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
370 subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
371
372 sgsn_update_subscriber_data(subscr->sgsn_data->mm, subscr);
373}
374
375struct gsm_subscriber *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100376{
377 struct gsm_subscriber *subscr = NULL;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100378
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100379 if (mmctx->subscr)
380 return subscr_get(mmctx->subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100381
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100382 if (mmctx->imsi[0])
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100383 subscr = gprs_subscr_get_by_imsi(mmctx->imsi);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100384
385 if (!subscr) {
386 subscr = gprs_subscr_get_or_create(mmctx->imsi);
387 subscr->flags |= GSM_SUBSCRIBER_FIRST_CONTACT;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100388 }
389
390 if (strcpy(subscr->equipment.imei, mmctx->imei) != 0) {
391 strncpy(subscr->equipment.imei, mmctx->imei, GSM_IMEI_LENGTH-1);
392 subscr->equipment.imei[GSM_IMEI_LENGTH-1] = 0;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100393 }
394
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100395 if (subscr->lac != mmctx->ra.lac)
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100396 subscr->lac = mmctx->ra.lac;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100397
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100398 subscr->sgsn_data->mm = mmctx;
399 mmctx->subscr = subscr_get(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100400
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100401 return subscr;
402}
403
404int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx)
405{
406 struct gsm_subscriber *subscr = NULL;
407 int rc;
408
409 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber data update\n");
410
411 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
412
413 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
414
415 rc = gprs_subscr_location_update(subscr);
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100416 subscr_put(subscr);
Jacob Erlbeck98a95ac2014-11-28 14:55:25 +0100417 return rc;
418}
419
420int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx)
421{
422 struct gsm_subscriber *subscr = NULL;
423 int rc;
424
425 LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber authentication info\n");
426
427 subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
428
429 subscr->flags |= GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
430
431 rc = gprs_subscr_query_auth_info(subscr);
432 subscr_put(subscr);
433 return rc;
Jacob Erlbeck33b6dad2014-11-12 10:12:11 +0100434}