blob: 2c84b169f2ab64098c80b56cc384fbb153f76ab0 [file] [log] [blame]
Holger Hans Peter Freyther8ec49522011-08-15 15:53:00 +02001/* (C) 2009-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
2 * (C) 2009-2011 by On-Waves
Holger Hans Peter Freyther5bb874d2010-11-05 11:21:18 +01003 * All Rights Reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01006 * it under the terms of the GNU Affero General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
Holger Hans Peter Freyther5bb874d2010-11-05 11:21:18 +01008 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010013 * GNU Affero General Public License for more details.
Holger Hans Peter Freyther5bb874d2010-11-05 11:21:18 +010014 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010015 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Holger Hans Peter Freyther5bb874d2010-11-05 11:21:18 +010017 *
18 */
19
20#include <openbsc/osmo_bsc.h>
Neels Hofmeyra42855f2017-02-23 21:49:55 +010021#include <openbsc/bsc_msc_data.h>
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +010022#include <openbsc/gsm_04_80.h>
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +010023#include <openbsc/gsm_subscriber.h>
Neels Hofmeyr6d804b12017-02-18 22:20:46 +010024#include <openbsc/bsc_subscriber.h>
Holger Hans Peter Freytherd65305f2010-11-05 11:31:08 +010025#include <openbsc/debug.h>
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +010026#include <openbsc/paging.h>
27
28#include <stdlib.h>
Holger Hans Peter Freytherd65305f2010-11-05 11:31:08 +010029
30static void handle_lu_request(struct gsm_subscriber_connection *conn,
31 struct msgb *msg)
32{
33 struct gsm48_hdr *gh;
34 struct gsm48_loc_upd_req *lu;
35 struct gsm48_loc_area_id lai;
36 struct gsm_network *net;
37
38 if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*lu)) {
39 LOGP(DMSC, LOGL_ERROR, "LU too small to look at: %u\n", msgb_l3len(msg));
40 return;
41 }
42
43 net = conn->bts->network;
44
45 gh = msgb_l3(msg);
46 lu = (struct gsm48_loc_upd_req *) gh->data;
47
48 gsm48_generate_lai(&lai, net->country_code, net->network_code,
49 conn->bts->location_area_code);
50
51 if (memcmp(&lai, &lu->lai, sizeof(lai)) != 0) {
52 LOGP(DMSC, LOGL_DEBUG, "Marking con for welcome USSD.\n");
53 conn->sccp_con->new_subscriber = 1;
54 }
55}
Holger Hans Peter Freyther5bb874d2010-11-05 11:21:18 +010056
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +020057/* extract a subscriber from the paging response */
Neels Hofmeyr6d804b12017-02-18 22:20:46 +010058static struct bsc_subscr *extract_sub(struct gsm_subscriber_connection *conn,
59 struct msgb *msg)
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +010060{
61 uint8_t mi_type;
62 char mi_string[GSM48_MI_SIZE];
63 struct gsm48_hdr *gh;
64 struct gsm48_pag_resp *resp;
Neels Hofmeyr6d804b12017-02-18 22:20:46 +010065 struct bsc_subscr *subscr;
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +010066
67 if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*resp)) {
68 LOGP(DMSC, LOGL_ERROR, "PagingResponse too small: %u\n", msgb_l3len(msg));
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +020069 return NULL;
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +010070 }
71
72 gh = msgb_l3(msg);
73 resp = (struct gsm48_pag_resp *) &gh->data[0];
74
75 gsm48_paging_extract_mi(resp, msgb_l3len(msg) - sizeof(*gh),
76 mi_string, &mi_type);
Harald Welteb9845f92015-08-16 18:07:48 +020077 DEBUGP(DRR, "PAGING RESPONSE: MI(%s)=%s\n",
78 gsm48_mi_type_name(mi_type), mi_string);
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +010079
80 switch (mi_type) {
81 case GSM_MI_TYPE_TMSI:
Neels Hofmeyr6d804b12017-02-18 22:20:46 +010082 subscr = bsc_subscr_find_by_tmsi(conn->network->bsc_subscribers,
83 tmsi_from_string(mi_string));
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +010084 break;
85 case GSM_MI_TYPE_IMSI:
Neels Hofmeyr6d804b12017-02-18 22:20:46 +010086 subscr = bsc_subscr_find_by_imsi(conn->network->bsc_subscribers,
87 mi_string);
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +010088 break;
Holger Hans Peter Freyther3fbd2442011-01-16 18:18:56 +010089 default:
90 subscr = NULL;
91 break;
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +010092 }
93
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +020094 return subscr;
95}
96
97/* we will need to stop the paging request */
98static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb *msg)
99{
Neels Hofmeyr6d804b12017-02-18 22:20:46 +0100100 struct bsc_subscr *subscr = extract_sub(conn, msg);
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +0200101
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +0100102 if (!subscr) {
103 LOGP(DMSC, LOGL_ERROR, "Non active subscriber got paged.\n");
104 return -1;
105 }
106
Neels Hofmeyr6d804b12017-02-18 22:20:46 +0100107 paging_request_stop(&conn->network->bts_list, conn->bts, subscr, conn,
108 msg);
109 bsc_subscr_put(subscr);
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +0100110 return 0;
111}
Holger Hans Peter Freyther18fa70a2011-06-08 19:25:38 +0200112
113static int is_cm_service_for_emerg(struct msgb *msg)
114{
115 struct gsm48_service_request *cm;
116 struct gsm48_hdr *gh = msgb_l3(msg);
117
118 if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*cm)) {
119 LOGP(DMSC, LOGL_ERROR, "CM ServiceRequest does not fit.\n");
120 return 0;
121 }
122
123 cm = (struct gsm48_service_request *) &gh->data[0];
124 return cm->cm_service_type == GSM48_CMSERV_EMERGENCY;
125}
126
Neels Hofmeyra369e242017-02-23 21:57:23 +0100127struct bsc_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn,
Holger Hans Peter Freyther076af1c2011-06-07 19:57:02 +0200128 struct msgb *msg)
129{
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +0200130 struct gsm48_hdr *gh;
131 int8_t pdisc;
132 uint8_t mtype;
Holger Hans Peter Freyther076af1c2011-06-07 19:57:02 +0200133 struct osmo_bsc_data *bsc;
Neels Hofmeyra369e242017-02-23 21:57:23 +0100134 struct bsc_msc_data *msc, *pag_msc;
Neels Hofmeyr6d804b12017-02-18 22:20:46 +0100135 struct bsc_subscr *subscr;
Holger Hans Peter Freyther18fa70a2011-06-08 19:25:38 +0200136 int is_emerg = 0;
Holger Hans Peter Freyther076af1c2011-06-07 19:57:02 +0200137
138 bsc = conn->bts->network->bsc_data;
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +0200139
140 if (msgb_l3len(msg) < sizeof(*gh)) {
141 LOGP(DMSC, LOGL_ERROR, "There is no GSM48 header here.\n");
142 return NULL;
143 }
144
145 gh = msgb_l3(msg);
Neels Hofmeyr531734a2016-03-14 16:13:24 +0100146 pdisc = gsm48_hdr_pdisc(gh);
147 mtype = gsm48_hdr_msg_type(gh);
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +0200148
149 /*
150 * We are asked to select a MSC here but they are not equal. We
151 * want to respond to a paging request on the MSC where we got the
152 * request from. This is where we need to decide where this connection
153 * will go.
154 */
155 if (pdisc == GSM48_PDISC_RR && mtype == GSM48_MT_RR_PAG_RESP)
156 goto paging;
Holger Hans Peter Freyther18fa70a2011-06-08 19:25:38 +0200157 else if (pdisc == GSM48_PDISC_MM && mtype == GSM48_MT_MM_CM_SERV_REQ) {
158 is_emerg = is_cm_service_for_emerg(msg);
159 goto round_robin;
160 } else
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +0200161 goto round_robin;
162
163round_robin:
Holger Hans Peter Freyther076af1c2011-06-07 19:57:02 +0200164 llist_for_each_entry(msc, &bsc->mscs, entry) {
165 if (!msc->msc_con->is_authenticated)
166 continue;
Holger Hans Peter Freyther18fa70a2011-06-08 19:25:38 +0200167 if (!is_emerg && msc->type != MSC_CON_TYPE_NORMAL)
168 continue;
169 if (is_emerg && !msc->allow_emerg)
Holger Hans Peter Freyther210565e2011-06-07 20:56:18 +0200170 continue;
Holger Hans Peter Freyther076af1c2011-06-07 19:57:02 +0200171
172 /* force round robin by moving it to the end */
173 llist_move_tail(&msc->entry, &bsc->mscs);
174 return msc;
175 }
176
177 return NULL;
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +0200178
179paging:
180 subscr = extract_sub(conn, msg);
181
182 if (!subscr) {
183 LOGP(DMSC, LOGL_ERROR, "Got paged but no subscriber found.\n");
184 return NULL;
185 }
186
187 pag_msc = paging_get_data(conn->bts, subscr);
Neels Hofmeyr6d804b12017-02-18 22:20:46 +0100188 bsc_subscr_put(subscr);
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +0200189
190 llist_for_each_entry(msc, &bsc->mscs, entry) {
191 if (msc != pag_msc)
192 continue;
193
194 /*
195 * We don't check if the MSC is connected. In case it
196 * is not the connection will be dropped.
197 */
198
199 /* force round robin by moving it to the end */
200 llist_move_tail(&msc->entry, &bsc->mscs);
201 return msc;
202 }
203
204 LOGP(DMSC, LOGL_ERROR, "Got paged but no request found.\n");
205 return NULL;
Holger Hans Peter Freyther076af1c2011-06-07 19:57:02 +0200206}
207
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +0100208
Holger Hans Peter Freyther5bb874d2010-11-05 11:21:18 +0100209/**
210 * This is used to scan a message for extra functionality of the BSC. This
211 * includes scanning for location updating requests/acceptd and then send
212 * a welcome USSD message to the subscriber.
213 */
214int bsc_scan_bts_msg(struct gsm_subscriber_connection *conn, struct msgb *msg)
215{
Holger Hans Peter Freytherd65305f2010-11-05 11:31:08 +0100216 struct gsm48_hdr *gh = msgb_l3(msg);
Neels Hofmeyr531734a2016-03-14 16:13:24 +0100217 uint8_t pdisc = gsm48_hdr_pdisc(gh);
218 uint8_t mtype = gsm48_hdr_msg_type(gh);
Holger Hans Peter Freytherd65305f2010-11-05 11:31:08 +0100219
220 if (pdisc == GSM48_PDISC_MM) {
221 if (mtype == GSM48_MT_MM_LOC_UPD_REQUEST)
222 handle_lu_request(conn, msg);
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +0100223 } else if (pdisc == GSM48_PDISC_RR) {
224 if (mtype == GSM48_MT_RR_PAG_RESP)
225 handle_page_resp(conn, msg);
Holger Hans Peter Freytherd65305f2010-11-05 11:31:08 +0100226 }
227
Holger Hans Peter Freyther5bb874d2010-11-05 11:21:18 +0100228 return 0;
229}
Holger Hans Peter Freythera54732d2010-11-05 18:11:19 +0100230
Holger Hans Peter Freytherd2361d92012-12-03 15:32:54 +0100231static int send_welcome_ussd(struct gsm_subscriber_connection *conn)
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100232{
Holger Hans Peter Freyther383d3c32012-07-19 14:22:42 +0200233 struct osmo_bsc_sccp_con *bsc_con;
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100234
Holger Hans Peter Freyther383d3c32012-07-19 14:22:42 +0200235 bsc_con = conn->sccp_con;
Holger Hans Peter Freytherf5892212012-08-30 13:05:15 +0200236 if (!bsc_con) {
237 LOGP(DMSC, LOGL_DEBUG, "No SCCP connection associated.\n");
Holger Hans Peter Freytherd2361d92012-12-03 15:32:54 +0100238 return 0;
Holger Hans Peter Freytherf5892212012-08-30 13:05:15 +0200239 }
240
241 if (!bsc_con->msc->ussd_welcome_txt) {
242 LOGP(DMSC, LOGL_DEBUG, "No USSD Welcome text defined.\n");
Holger Hans Peter Freytherd2361d92012-12-03 15:32:54 +0100243 return 0;
Holger Hans Peter Freytherf5892212012-08-30 13:05:15 +0200244 }
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100245
Holger Hans Peter Freytherd2361d92012-12-03 15:32:54 +0100246 return BSS_SEND_USSD;
247}
248
249int bsc_send_welcome_ussd(struct gsm_subscriber_connection *conn)
250{
Neels Hofmeyr43273c62016-05-10 12:50:31 +0200251 bsc_send_ussd_notify(conn, 1, conn->sccp_con->msc->ussd_welcome_txt);
252 bsc_send_ussd_release_complete(conn);
Holger Hans Peter Freytherd2361d92012-12-03 15:32:54 +0100253
254 return 0;
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100255}
256
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200257static int bsc_patch_mm_info(struct gsm_subscriber_connection *conn,
258 uint8_t *data, unsigned int length)
259{
260 struct tlv_parsed tp;
261 int parse_res;
262 struct gsm_bts *bts = conn->bts;
263 int tzunits;
264 uint8_t tzbsd = 0;
265 uint8_t dst = 0;
266
267 parse_res = tlv_parse(&tp, &gsm48_mm_att_tlvdef, data, length, 0, 0);
268 if (parse_res <= 0 && parse_res != -3)
Neels Hofmeyra7313dd2016-02-29 09:35:54 +0100269 /* FIXME: -3 means unknown IE error, so this accepts messages
270 * with unknown IEs. But parsing has aborted with the unknown
271 * IE and the message is broken or parsed incompletely. */
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200272 return 0;
273
274 /* Is TZ patching enabled? */
Neels Hofmeyr73983952016-05-10 13:29:33 +0200275 struct gsm_tz *tz = &bts->network->tz;
276 if (!tz->override)
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200277 return 0;
278
279 /* Convert tz.hr and tz.mn to units */
Neels Hofmeyr73983952016-05-10 13:29:33 +0200280 if (tz->hr < 0) {
281 tzunits = -tz->hr*4;
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200282 tzbsd |= 0x08;
283 } else
Neels Hofmeyr73983952016-05-10 13:29:33 +0200284 tzunits = tz->hr*4;
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200285
Neels Hofmeyr73983952016-05-10 13:29:33 +0200286 tzunits = tzunits + (tz->mn/15);
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200287
288 tzbsd |= (tzunits % 10)*0x10 + (tzunits / 10);
289
290 /* Convert DST value */
Neels Hofmeyr73983952016-05-10 13:29:33 +0200291 if (tz->dst >= 0 && tz->dst <= 2)
292 dst = tz->dst;
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200293
294 if (TLVP_PRESENT(&tp, GSM48_IE_UTC)) {
295 LOGP(DMSC, LOGL_DEBUG,
296 "Changing 'Local time zone' from 0x%02x to 0x%02x.\n",
297 TLVP_VAL(&tp, GSM48_IE_UTC)[6], tzbsd);
298 ((uint8_t *)(TLVP_VAL(&tp, GSM48_IE_UTC)))[0] = tzbsd;
299 }
300 if (TLVP_PRESENT(&tp, GSM48_IE_NET_TIME_TZ)) {
301 LOGP(DMSC, LOGL_DEBUG,
302 "Changing 'Universal time and local time zone' TZ from "
303 "0x%02x to 0x%02x.\n",
304 TLVP_VAL(&tp, GSM48_IE_NET_TIME_TZ)[6], tzbsd);
305 ((uint8_t *)(TLVP_VAL(&tp, GSM48_IE_NET_TIME_TZ)))[6] = tzbsd;
306 }
307#ifdef GSM48_IE_NET_DST
308 if (TLVP_PRESENT(&tp, GSM48_IE_NET_DST)) {
309 LOGP(DMSC, LOGL_DEBUG,
310 "Changing 'Network daylight saving time' from "
311 "0x%02x to 0x%02x.\n",
312 TLVP_VAL(&tp, GSM48_IE_NET_DST)[0], dst);
313 ((uint8_t *)(TLVP_VAL(&tp, GSM48_IE_NET_DST)))[0] = dst;
314 }
315#endif
316
317 return 0;
318}
319
Neels Hofmeyra369e242017-02-23 21:57:23 +0100320static int has_core_identity(struct bsc_msc_data *msc)
Holger Hans Peter Freyther32dd2f32015-04-01 18:15:48 +0200321{
Holger Hans Peter Freyther1e365472015-07-13 11:06:10 +0200322 if (msc->core_mnc != -1)
Holger Hans Peter Freyther32dd2f32015-04-01 18:15:48 +0200323 return 1;
324 if (msc->core_mcc != -1)
325 return 1;
326 if (msc->core_lac != -1)
327 return 1;
328 if (msc->core_ci != -1)
329 return 1;
330 return 0;
331}
332
Holger Hans Peter Freythera54732d2010-11-05 18:11:19 +0100333/**
334 * Messages coming back from the MSC.
335 */
336int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg)
337{
Neels Hofmeyra369e242017-02-23 21:57:23 +0100338 struct bsc_msc_data *msc;
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100339 struct gsm_network *net;
340 struct gsm48_loc_area_id *lai;
341 struct gsm48_hdr *gh;
Neels Hofmeyr10cd1132016-03-14 16:15:02 +0100342 uint8_t pdisc;
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100343 uint8_t mtype;
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200344 int length = msgb_l3len(msg);
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100345
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200346 if (length < sizeof(*gh)) {
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100347 LOGP(DMSC, LOGL_ERROR, "GSM48 header does not fit.\n");
348 return -1;
349 }
350
351 gh = (struct gsm48_hdr *) msgb_l3(msg);
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200352 length -= (const char *)&gh->data[0] - (const char *)gh;
353
Neels Hofmeyr10cd1132016-03-14 16:15:02 +0100354 pdisc = gsm48_hdr_pdisc(gh);
355 if (pdisc != GSM48_PDISC_MM)
356 return 0;
357
Neels Hofmeyr531734a2016-03-14 16:13:24 +0100358 mtype = gsm48_hdr_msg_type(gh);
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100359 net = conn->bts->network;
Holger Hans Peter Freytherf936fb42011-06-04 15:12:57 +0200360 msc = conn->sccp_con->msc;
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100361
362 if (mtype == GSM48_MT_MM_LOC_UPD_ACCEPT) {
Holger Hans Peter Freyther32dd2f32015-04-01 18:15:48 +0200363 if (has_core_identity(msc)) {
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100364 if (msgb_l3len(msg) >= sizeof(*gh) + sizeof(*lai)) {
Neels Hofmeyr49b83d82016-02-29 09:40:22 +0100365 /* overwrite LAI in the message */
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100366 lai = (struct gsm48_loc_area_id *) &gh->data[0];
367 gsm48_generate_lai(lai, net->country_code,
368 net->network_code,
369 conn->bts->location_area_code);
370 }
371 }
372
373 if (conn->sccp_con->new_subscriber)
Holger Hans Peter Freytherd2361d92012-12-03 15:32:54 +0100374 return send_welcome_ussd(conn);
375 return 0;
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200376 } else if (mtype == GSM48_MT_MM_INFO) {
377 bsc_patch_mm_info(conn, &gh->data[0], length);
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100378 }
379
Holger Hans Peter Freythera54732d2010-11-05 18:11:19 +0100380 return 0;
381}