blob: d5ca2fddaa70adb4423a0375ae98f703f1812cd5 [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>
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +010021#include <openbsc/osmo_msc_data.h>
22#include <openbsc/gsm_04_80.h>
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +010023#include <openbsc/gsm_subscriber.h>
Holger Hans Peter Freytherd65305f2010-11-05 11:31:08 +010024#include <openbsc/debug.h>
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +010025#include <openbsc/paging.h>
26
27#include <stdlib.h>
Holger Hans Peter Freytherd65305f2010-11-05 11:31:08 +010028
29static void handle_lu_request(struct gsm_subscriber_connection *conn,
30 struct msgb *msg)
31{
32 struct gsm48_hdr *gh;
33 struct gsm48_loc_upd_req *lu;
34 struct gsm48_loc_area_id lai;
35 struct gsm_network *net;
36
37 if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*lu)) {
38 LOGP(DMSC, LOGL_ERROR, "LU too small to look at: %u\n", msgb_l3len(msg));
39 return;
40 }
41
42 net = conn->bts->network;
43
44 gh = msgb_l3(msg);
45 lu = (struct gsm48_loc_upd_req *) gh->data;
46
47 gsm48_generate_lai(&lai, net->country_code, net->network_code,
48 conn->bts->location_area_code);
49
50 if (memcmp(&lai, &lu->lai, sizeof(lai)) != 0) {
51 LOGP(DMSC, LOGL_DEBUG, "Marking con for welcome USSD.\n");
52 conn->sccp_con->new_subscriber = 1;
53 }
54}
Holger Hans Peter Freyther5bb874d2010-11-05 11:21:18 +010055
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +020056/* extract a subscriber from the paging response */
57static struct gsm_subscriber *extract_sub(struct gsm_subscriber_connection *conn,
58 struct msgb *msg)
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +010059{
60 uint8_t mi_type;
61 char mi_string[GSM48_MI_SIZE];
62 struct gsm48_hdr *gh;
63 struct gsm48_pag_resp *resp;
64 struct gsm_subscriber *subscr;
65
66 if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*resp)) {
67 LOGP(DMSC, LOGL_ERROR, "PagingResponse too small: %u\n", msgb_l3len(msg));
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +020068 return NULL;
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +010069 }
70
71 gh = msgb_l3(msg);
72 resp = (struct gsm48_pag_resp *) &gh->data[0];
73
74 gsm48_paging_extract_mi(resp, msgb_l3len(msg) - sizeof(*gh),
75 mi_string, &mi_type);
Harald Welteb9845f92015-08-16 18:07:48 +020076 DEBUGP(DRR, "PAGING RESPONSE: MI(%s)=%s\n",
77 gsm48_mi_type_name(mi_type), mi_string);
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +010078
79 switch (mi_type) {
80 case GSM_MI_TYPE_TMSI:
Jacob Erlbeck1e30a282014-12-03 09:28:24 +010081 subscr = subscr_active_by_tmsi(conn->bts->network->subscr_group,
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +010082 tmsi_from_string(mi_string));
83 break;
84 case GSM_MI_TYPE_IMSI:
Jacob Erlbeck1e30a282014-12-03 09:28:24 +010085 subscr = subscr_active_by_imsi(conn->bts->network->subscr_group,
86 mi_string);
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +010087 break;
Holger Hans Peter Freyther3fbd2442011-01-16 18:18:56 +010088 default:
89 subscr = NULL;
90 break;
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +010091 }
92
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +020093 return subscr;
94}
95
96/* we will need to stop the paging request */
97static int handle_page_resp(struct gsm_subscriber_connection *conn, struct msgb *msg)
98{
99 struct gsm_subscriber *subscr = extract_sub(conn, msg);
100
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +0100101 if (!subscr) {
102 LOGP(DMSC, LOGL_ERROR, "Non active subscriber got paged.\n");
103 return -1;
104 }
105
Harald Weltef604bba2010-12-15 15:33:08 +0100106 paging_request_stop(conn->bts, subscr, conn, msg);
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +0100107 subscr_put(subscr);
108 return 0;
109}
Holger Hans Peter Freyther18fa70a2011-06-08 19:25:38 +0200110
111static int is_cm_service_for_emerg(struct msgb *msg)
112{
113 struct gsm48_service_request *cm;
114 struct gsm48_hdr *gh = msgb_l3(msg);
115
116 if (msgb_l3len(msg) < sizeof(*gh) + sizeof(*cm)) {
117 LOGP(DMSC, LOGL_ERROR, "CM ServiceRequest does not fit.\n");
118 return 0;
119 }
120
121 cm = (struct gsm48_service_request *) &gh->data[0];
122 return cm->cm_service_type == GSM48_CMSERV_EMERGENCY;
123}
124
Holger Hans Peter Freyther076af1c2011-06-07 19:57:02 +0200125struct osmo_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn,
126 struct msgb *msg)
127{
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +0200128 struct gsm48_hdr *gh;
129 int8_t pdisc;
130 uint8_t mtype;
Holger Hans Peter Freyther076af1c2011-06-07 19:57:02 +0200131 struct osmo_bsc_data *bsc;
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +0200132 struct osmo_msc_data *msc, *pag_msc;
133 struct gsm_subscriber *subscr;
Holger Hans Peter Freyther18fa70a2011-06-08 19:25:38 +0200134 int is_emerg = 0;
Holger Hans Peter Freyther076af1c2011-06-07 19:57:02 +0200135
136 bsc = conn->bts->network->bsc_data;
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +0200137
138 if (msgb_l3len(msg) < sizeof(*gh)) {
139 LOGP(DMSC, LOGL_ERROR, "There is no GSM48 header here.\n");
140 return NULL;
141 }
142
143 gh = msgb_l3(msg);
Neels Hofmeyr531734a2016-03-14 16:13:24 +0100144 pdisc = gsm48_hdr_pdisc(gh);
145 mtype = gsm48_hdr_msg_type(gh);
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +0200146
147 /*
148 * We are asked to select a MSC here but they are not equal. We
149 * want to respond to a paging request on the MSC where we got the
150 * request from. This is where we need to decide where this connection
151 * will go.
152 */
153 if (pdisc == GSM48_PDISC_RR && mtype == GSM48_MT_RR_PAG_RESP)
154 goto paging;
Holger Hans Peter Freyther18fa70a2011-06-08 19:25:38 +0200155 else if (pdisc == GSM48_PDISC_MM && mtype == GSM48_MT_MM_CM_SERV_REQ) {
156 is_emerg = is_cm_service_for_emerg(msg);
157 goto round_robin;
158 } else
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +0200159 goto round_robin;
160
161round_robin:
Holger Hans Peter Freyther076af1c2011-06-07 19:57:02 +0200162 llist_for_each_entry(msc, &bsc->mscs, entry) {
163 if (!msc->msc_con->is_authenticated)
164 continue;
Holger Hans Peter Freyther18fa70a2011-06-08 19:25:38 +0200165 if (!is_emerg && msc->type != MSC_CON_TYPE_NORMAL)
166 continue;
167 if (is_emerg && !msc->allow_emerg)
Holger Hans Peter Freyther210565e2011-06-07 20:56:18 +0200168 continue;
Holger Hans Peter Freyther076af1c2011-06-07 19:57:02 +0200169
170 /* force round robin by moving it to the end */
171 llist_move_tail(&msc->entry, &bsc->mscs);
172 return msc;
173 }
174
175 return NULL;
Holger Hans Peter Freytherf67d9a92011-06-07 20:12:33 +0200176
177paging:
178 subscr = extract_sub(conn, msg);
179
180 if (!subscr) {
181 LOGP(DMSC, LOGL_ERROR, "Got paged but no subscriber found.\n");
182 return NULL;
183 }
184
185 pag_msc = paging_get_data(conn->bts, subscr);
186 subscr_put(subscr);
187
188 llist_for_each_entry(msc, &bsc->mscs, entry) {
189 if (msc != pag_msc)
190 continue;
191
192 /*
193 * We don't check if the MSC is connected. In case it
194 * is not the connection will be dropped.
195 */
196
197 /* force round robin by moving it to the end */
198 llist_move_tail(&msc->entry, &bsc->mscs);
199 return msc;
200 }
201
202 LOGP(DMSC, LOGL_ERROR, "Got paged but no request found.\n");
203 return NULL;
Holger Hans Peter Freyther076af1c2011-06-07 19:57:02 +0200204}
205
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +0100206
Holger Hans Peter Freyther5bb874d2010-11-05 11:21:18 +0100207/**
208 * This is used to scan a message for extra functionality of the BSC. This
209 * includes scanning for location updating requests/acceptd and then send
210 * a welcome USSD message to the subscriber.
211 */
212int bsc_scan_bts_msg(struct gsm_subscriber_connection *conn, struct msgb *msg)
213{
Holger Hans Peter Freytherd65305f2010-11-05 11:31:08 +0100214 struct gsm48_hdr *gh = msgb_l3(msg);
Neels Hofmeyr531734a2016-03-14 16:13:24 +0100215 uint8_t pdisc = gsm48_hdr_pdisc(gh);
216 uint8_t mtype = gsm48_hdr_msg_type(gh);
Holger Hans Peter Freytherd65305f2010-11-05 11:31:08 +0100217
218 if (pdisc == GSM48_PDISC_MM) {
219 if (mtype == GSM48_MT_MM_LOC_UPD_REQUEST)
220 handle_lu_request(conn, msg);
Holger Hans Peter Freyther16e958d2010-11-15 13:34:03 +0100221 } else if (pdisc == GSM48_PDISC_RR) {
222 if (mtype == GSM48_MT_RR_PAG_RESP)
223 handle_page_resp(conn, msg);
Holger Hans Peter Freytherd65305f2010-11-05 11:31:08 +0100224 }
225
Holger Hans Peter Freyther5bb874d2010-11-05 11:21:18 +0100226 return 0;
227}
Holger Hans Peter Freythera54732d2010-11-05 18:11:19 +0100228
Holger Hans Peter Freytherd2361d92012-12-03 15:32:54 +0100229static int send_welcome_ussd(struct gsm_subscriber_connection *conn)
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100230{
Holger Hans Peter Freyther383d3c32012-07-19 14:22:42 +0200231 struct osmo_bsc_sccp_con *bsc_con;
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100232
Holger Hans Peter Freyther383d3c32012-07-19 14:22:42 +0200233 bsc_con = conn->sccp_con;
Holger Hans Peter Freytherf5892212012-08-30 13:05:15 +0200234 if (!bsc_con) {
235 LOGP(DMSC, LOGL_DEBUG, "No SCCP connection associated.\n");
Holger Hans Peter Freytherd2361d92012-12-03 15:32:54 +0100236 return 0;
Holger Hans Peter Freytherf5892212012-08-30 13:05:15 +0200237 }
238
239 if (!bsc_con->msc->ussd_welcome_txt) {
240 LOGP(DMSC, LOGL_DEBUG, "No USSD Welcome text defined.\n");
Holger Hans Peter Freytherd2361d92012-12-03 15:32:54 +0100241 return 0;
Holger Hans Peter Freytherf5892212012-08-30 13:05:15 +0200242 }
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100243
Holger Hans Peter Freytherd2361d92012-12-03 15:32:54 +0100244 return BSS_SEND_USSD;
245}
246
247int bsc_send_welcome_ussd(struct gsm_subscriber_connection *conn)
248{
Neels Hofmeyr43273c62016-05-10 12:50:31 +0200249 bsc_send_ussd_notify(conn, 1, conn->sccp_con->msc->ussd_welcome_txt);
250 bsc_send_ussd_release_complete(conn);
Holger Hans Peter Freytherd2361d92012-12-03 15:32:54 +0100251
252 return 0;
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100253}
254
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200255static int bsc_patch_mm_info(struct gsm_subscriber_connection *conn,
256 uint8_t *data, unsigned int length)
257{
258 struct tlv_parsed tp;
259 int parse_res;
260 struct gsm_bts *bts = conn->bts;
261 int tzunits;
262 uint8_t tzbsd = 0;
263 uint8_t dst = 0;
264
265 parse_res = tlv_parse(&tp, &gsm48_mm_att_tlvdef, data, length, 0, 0);
266 if (parse_res <= 0 && parse_res != -3)
Neels Hofmeyra7313dd2016-02-29 09:35:54 +0100267 /* FIXME: -3 means unknown IE error, so this accepts messages
268 * with unknown IEs. But parsing has aborted with the unknown
269 * IE and the message is broken or parsed incompletely. */
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200270 return 0;
271
272 /* Is TZ patching enabled? */
Neels Hofmeyr73983952016-05-10 13:29:33 +0200273 struct gsm_tz *tz = &bts->network->tz;
274 if (!tz->override)
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200275 return 0;
276
277 /* Convert tz.hr and tz.mn to units */
Neels Hofmeyr73983952016-05-10 13:29:33 +0200278 if (tz->hr < 0) {
279 tzunits = -tz->hr*4;
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200280 tzbsd |= 0x08;
281 } else
Neels Hofmeyr73983952016-05-10 13:29:33 +0200282 tzunits = tz->hr*4;
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200283
Neels Hofmeyr73983952016-05-10 13:29:33 +0200284 tzunits = tzunits + (tz->mn/15);
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200285
286 tzbsd |= (tzunits % 10)*0x10 + (tzunits / 10);
287
288 /* Convert DST value */
Neels Hofmeyr73983952016-05-10 13:29:33 +0200289 if (tz->dst >= 0 && tz->dst <= 2)
290 dst = tz->dst;
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200291
292 if (TLVP_PRESENT(&tp, GSM48_IE_UTC)) {
293 LOGP(DMSC, LOGL_DEBUG,
294 "Changing 'Local time zone' from 0x%02x to 0x%02x.\n",
295 TLVP_VAL(&tp, GSM48_IE_UTC)[6], tzbsd);
296 ((uint8_t *)(TLVP_VAL(&tp, GSM48_IE_UTC)))[0] = tzbsd;
297 }
298 if (TLVP_PRESENT(&tp, GSM48_IE_NET_TIME_TZ)) {
299 LOGP(DMSC, LOGL_DEBUG,
300 "Changing 'Universal time and local time zone' TZ from "
301 "0x%02x to 0x%02x.\n",
302 TLVP_VAL(&tp, GSM48_IE_NET_TIME_TZ)[6], tzbsd);
303 ((uint8_t *)(TLVP_VAL(&tp, GSM48_IE_NET_TIME_TZ)))[6] = tzbsd;
304 }
305#ifdef GSM48_IE_NET_DST
306 if (TLVP_PRESENT(&tp, GSM48_IE_NET_DST)) {
307 LOGP(DMSC, LOGL_DEBUG,
308 "Changing 'Network daylight saving time' from "
309 "0x%02x to 0x%02x.\n",
310 TLVP_VAL(&tp, GSM48_IE_NET_DST)[0], dst);
311 ((uint8_t *)(TLVP_VAL(&tp, GSM48_IE_NET_DST)))[0] = dst;
312 }
313#endif
314
315 return 0;
316}
317
Holger Hans Peter Freyther32dd2f32015-04-01 18:15:48 +0200318static int has_core_identity(struct osmo_msc_data *msc)
319{
Holger Hans Peter Freyther1e365472015-07-13 11:06:10 +0200320 if (msc->core_mnc != -1)
Holger Hans Peter Freyther32dd2f32015-04-01 18:15:48 +0200321 return 1;
322 if (msc->core_mcc != -1)
323 return 1;
324 if (msc->core_lac != -1)
325 return 1;
326 if (msc->core_ci != -1)
327 return 1;
328 return 0;
329}
330
Holger Hans Peter Freythera54732d2010-11-05 18:11:19 +0100331/**
332 * Messages coming back from the MSC.
333 */
334int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg)
335{
Holger Hans Peter Freytherf936fb42011-06-04 15:12:57 +0200336 struct osmo_msc_data *msc;
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100337 struct gsm_network *net;
338 struct gsm48_loc_area_id *lai;
339 struct gsm48_hdr *gh;
Neels Hofmeyr10cd1132016-03-14 16:15:02 +0100340 uint8_t pdisc;
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100341 uint8_t mtype;
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200342 int length = msgb_l3len(msg);
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100343
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200344 if (length < sizeof(*gh)) {
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100345 LOGP(DMSC, LOGL_ERROR, "GSM48 header does not fit.\n");
346 return -1;
347 }
348
349 gh = (struct gsm48_hdr *) msgb_l3(msg);
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200350 length -= (const char *)&gh->data[0] - (const char *)gh;
351
Neels Hofmeyr10cd1132016-03-14 16:15:02 +0100352 pdisc = gsm48_hdr_pdisc(gh);
353 if (pdisc != GSM48_PDISC_MM)
354 return 0;
355
Neels Hofmeyr531734a2016-03-14 16:13:24 +0100356 mtype = gsm48_hdr_msg_type(gh);
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100357 net = conn->bts->network;
Holger Hans Peter Freytherf936fb42011-06-04 15:12:57 +0200358 msc = conn->sccp_con->msc;
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100359
360 if (mtype == GSM48_MT_MM_LOC_UPD_ACCEPT) {
Holger Hans Peter Freyther32dd2f32015-04-01 18:15:48 +0200361 if (has_core_identity(msc)) {
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100362 if (msgb_l3len(msg) >= sizeof(*gh) + sizeof(*lai)) {
Neels Hofmeyr49b83d82016-02-29 09:40:22 +0100363 /* overwrite LAI in the message */
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100364 lai = (struct gsm48_loc_area_id *) &gh->data[0];
365 gsm48_generate_lai(lai, net->country_code,
366 net->network_code,
367 conn->bts->location_area_code);
368 }
369 }
370
371 if (conn->sccp_con->new_subscriber)
Holger Hans Peter Freytherd2361d92012-12-03 15:32:54 +0100372 return send_welcome_ussd(conn);
373 return 0;
Jacob Erlbeck946d1412013-09-17 13:59:29 +0200374 } else if (mtype == GSM48_MT_MM_INFO) {
375 bsc_patch_mm_info(conn, &gh->data[0], length);
Holger Hans Peter Freyther52d42ab2010-11-05 18:41:04 +0100376 }
377
Holger Hans Peter Freythera54732d2010-11-05 18:11:19 +0100378 return 0;
379}