blob: 97ce68a070af28ca75b0dfa2d937a3c370e2970c [file] [log] [blame]
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +01001/* GSM 08.08 BSSMAP handling */
2/* (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
3 * (C) 2009-2010 by On-Waves
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 */
21
22#include <openbsc/osmo_bsc.h>
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +010023#include <openbsc/osmo_bsc_grace.h>
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +010024#include <openbsc/osmo_msc_data.h>
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +010025#include <openbsc/debug.h>
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +010026#include <openbsc/mgcp.h>
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +010027
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +010028#include <osmocore/gsm0808.h>
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +010029#include <osmocore/protocol/gsm_08_08.h>
30
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +010031#include <arpa/inet.h>
32
33static uint16_t read_data16(const uint8_t *data)
34{
35 uint16_t res;
36
37 memcpy(&res, data, sizeof(res));
38 return res;
39}
40
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +010041/*
42 * helpers for the assignment command
43 */
44enum gsm0808_permitted_speech audio_support_to_gsm88(struct gsm_audio_support *audio)
45{
46 if (audio->hr) {
47 switch (audio->ver) {
48 case 1:
49 return GSM0808_PERM_HR1;
50 break;
51 case 2:
52 return GSM0808_PERM_HR2;
53 break;
54 case 3:
55 return GSM0808_PERM_HR3;
56 break;
57 default:
58 LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: %d\n", audio->ver);
59 return GSM0808_PERM_FR1;
60 }
61 } else {
62 switch (audio->ver) {
63 case 1:
64 return GSM0808_PERM_FR1;
65 break;
66 case 2:
67 return GSM0808_PERM_FR2;
68 break;
69 case 3:
70 return GSM0808_PERM_FR3;
71 break;
72 default:
73 LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: %d\n", audio->ver);
74 return GSM0808_PERM_HR1;
75 }
76 }
77}
78
79enum gsm48_chan_mode gsm88_to_chan_mode(enum gsm0808_permitted_speech speech)
80{
81 switch (speech) {
82 case GSM0808_PERM_HR1:
83 case GSM0808_PERM_FR1:
84 return GSM48_CMODE_SPEECH_V1;
85 break;
86 case GSM0808_PERM_HR2:
87 case GSM0808_PERM_FR2:
88 return GSM48_CMODE_SPEECH_EFR;
89 break;
90 case GSM0808_PERM_HR3:
91 case GSM0808_PERM_FR3:
92 return GSM48_CMODE_SPEECH_AMR;
93 break;
94 }
95
96 LOGP(DMSC, LOGL_FATAL, "Should not be reached.\n");
97 return GSM48_CMODE_SPEECH_AMR;
98}
99
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100100static int bssmap_handle_reset_ack(struct gsm_network *net,
101 struct msgb *msg, unsigned int length)
102{
103 LOGP(DMSC, LOGL_NOTICE, "Reset ACK from MSC\n");
104 return 0;
105}
106
107/* GSM 08.08 ยง 3.2.1.19 */
108static int bssmap_handle_paging(struct gsm_network *net,
109 struct msgb *msg, unsigned int payload_length)
110{
111 struct tlv_parsed tp;
112 char mi_string[GSM48_MI_SIZE];
113 uint32_t tmsi = GSM_RESERVED_TMSI;
114 unsigned int lac = GSM_LAC_RESERVED_ALL_BTS;
115 uint8_t data_length;
116 const uint8_t *data;
117 uint8_t chan_needed = RSL_CHANNEED_ANY;
118
119 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, payload_length - 1, 0, 0);
120
121 if (!TLVP_PRESENT(&tp, GSM0808_IE_IMSI)) {
122 LOGP(DMSC, LOGL_ERROR, "Mandantory IMSI not present.\n");
123 return -1;
124 } else if ((TLVP_VAL(&tp, GSM0808_IE_IMSI)[0] & GSM_MI_TYPE_MASK) != GSM_MI_TYPE_IMSI) {
125 LOGP(DMSC, LOGL_ERROR, "Wrong content in the IMSI\n");
126 return -1;
127 }
128
129 if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST)) {
130 LOGP(DMSC, LOGL_ERROR, "Mandantory CELL IDENTIFIER LIST not present.\n");
131 return -1;
132 }
133
134 if (TLVP_PRESENT(&tp, GSM0808_IE_TMSI)) {
135 gsm48_mi_to_string(mi_string, sizeof(mi_string),
136 TLVP_VAL(&tp, GSM0808_IE_TMSI), TLVP_LEN(&tp, GSM0808_IE_TMSI));
137 tmsi = strtoul(mi_string, NULL, 10);
138 }
139
140
141 /*
142 * parse the IMSI
143 */
144 gsm48_mi_to_string(mi_string, sizeof(mi_string),
145 TLVP_VAL(&tp, GSM0808_IE_IMSI), TLVP_LEN(&tp, GSM0808_IE_IMSI));
146
147 /*
148 * parse the cell identifier list
149 */
150 data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST);
151 data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST);
152
153 /*
154 * Support paging to all network or one BTS at one LAC
155 */
156 if (data_length == 3 && data[0] == CELL_IDENT_LAC) {
157 lac = ntohs(read_data16(&data[1]));
158 } else if (data_length > 1 || (data[0] & 0x0f) != CELL_IDENT_BSS) {
159 LOGP(DMSC, LOGL_ERROR, "Unsupported Cell Identifier List: %s\n", hexdump(data, data_length));
160 return -1;
161 }
162
163 if (TLVP_PRESENT(&tp, GSM0808_IE_CHANNEL_NEEDED) && TLVP_LEN(&tp, GSM0808_IE_CHANNEL_NEEDED) == 1)
164 chan_needed = TLVP_VAL(&tp, GSM0808_IE_CHANNEL_NEEDED)[0] & 0x03;
165
166 if (TLVP_PRESENT(&tp, GSM0808_IE_EMLPP_PRIORITY)) {
167 LOGP(DMSC, LOGL_ERROR, "eMLPP is not handled\n");
168 }
169
170 LOGP(DMSC, LOGL_DEBUG, "Paging request from MSC IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x\n", mi_string, tmsi, tmsi, lac);
171 LOGP(DMSC, LOGL_ERROR, "Paging is not implemented...\n");
172 return -1;
173}
174
Holger Hans Peter Freytherf1f57a82010-11-10 09:34:47 +0100175/*
176 * GSM 08.08 ยง 3.1.9.1 and 3.2.1.21...
177 * release our gsm_subscriber_connection and send message
178 */
179static int bssmap_handle_clear_command(struct osmo_bsc_sccp_con *conn,
180 struct msgb *msg, unsigned int payload_length)
181{
182 struct msgb *resp;
183
184 /* TODO: handle the cause of this package */
185
186 if (conn->conn) {
187 LOGP(DMSC, LOGL_DEBUG, "Releasing all transactions on %p\n", conn);
188 gsm0808_clear(conn->conn);
189 subscr_con_free(conn->conn);
190 conn->conn = NULL;
191 }
192
193 /* send the clear complete message */
194 resp = gsm0808_create_clear_complete();
195 if (!resp) {
196 LOGP(DMSC, LOGL_ERROR, "Sending clear complete failed.\n");
197 return -1;
198 }
199
200 bsc_queue_for_msc(conn, resp);
201 return 0;
202}
203
Holger Hans Peter Freytherfae3c652010-11-10 09:44:34 +0100204/*
205 * GSM 08.08 ยง 3.4.7 cipher mode handling. We will have to pick
206 * the cipher to be used for this. In case we are already using
207 * a cipher we will have to send cipher mode reject to the MSC,
208 * otherwise we will have to pick something that we and the MS
209 * is supporting. Currently we are doing it in a rather static
210 * way by picking one ecnryption or no encrytpion.
211 */
212static int bssmap_handle_cipher_mode(struct osmo_bsc_sccp_con *conn,
213 struct msgb *msg, unsigned int payload_length)
214{
215 uint16_t len;
216 struct gsm_network *network = NULL;
217 const uint8_t *data;
218 struct tlv_parsed tp;
219 struct msgb *resp;
220 int reject_cause = -1;
221 int include_imeisv = 1;
222
223 if (!conn->conn) {
224 LOGP(DMSC, LOGL_ERROR, "No lchan/msc_data in cipher mode command.\n");
225 goto reject;
226 }
227
228 if (conn->ciphering_handled) {
229 LOGP(DMSC, LOGL_ERROR, "Already seen ciphering command. Protocol Error.\n");
230 goto reject;
231 }
232
233 conn->ciphering_handled = 1;
234
235 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, payload_length - 1, 0, 0);
236 if (!TLVP_PRESENT(&tp, GSM0808_IE_ENCRYPTION_INFORMATION)) {
237 LOGP(DMSC, LOGL_ERROR, "IE Encryption Information missing.\n");
238 goto reject;
239 }
240
241 /*
242 * check if our global setting is allowed
243 * - Currently we check for A5/0 and A5/1
244 * - Copy the key if that is necessary
245 * - Otherwise reject
246 */
247 len = TLVP_LEN(&tp, GSM0808_IE_ENCRYPTION_INFORMATION);
248 if (len < 1) {
249 LOGP(DMSC, LOGL_ERROR, "IE Encryption Information is too short.\n");
250 goto reject;
251 }
252
253 network = conn->conn->bts->network;
254 data = TLVP_VAL(&tp, GSM0808_IE_ENCRYPTION_INFORMATION);
255
256 if (TLVP_PRESENT(&tp, GSM0808_IE_CIPHER_RESPONSE_MODE))
257 include_imeisv = TLVP_VAL(&tp, GSM0808_IE_CIPHER_RESPONSE_MODE)[0] & 0x1;
258
259 if (network->a5_encryption == 0 && (data[0] & 0x1) == 0x1) {
260 gsm0808_cipher_mode(conn->conn, 0, NULL, 0, include_imeisv);
261 } else if (network->a5_encryption != 0 && (data[0] & 0x2) == 0x2) {
262 gsm0808_cipher_mode(conn->conn, 1, &data[1], len - 1, include_imeisv);
263 } else {
264 LOGP(DMSC, LOGL_ERROR, "Can not select encryption...\n");
265 goto reject;
266 }
267
268reject:
269 resp = gsm0808_create_cipher_reject(reject_cause);
270 if (!resp) {
271 LOGP(DMSC, LOGL_ERROR, "Sending the cipher reject failed.\n");
272 return -1;
273 }
274
275 bsc_queue_for_msc(conn, resp);
276 return -1;
277}
278
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +0100279/*
280 * Handle the assignment request message.
281 *
282 * See ยง3.2.1.1 for the message type
283 */
284static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn,
285 struct msgb *msg, unsigned int length)
286{
287 struct msgb *resp;
288 struct gsm_network *network;
289 struct tlv_parsed tp;
290 uint8_t *data;
291 uint16_t cic;
292 uint8_t timeslot;
293 uint8_t multiplex;
294 enum gsm48_chan_mode chan_mode = GSM48_CMODE_SIGN;
295 int i, supported, port, full_rate = -1;
296
297 if (!conn->conn) {
298 LOGP(DMSC, LOGL_ERROR, "No lchan/msc_data in cipher mode command.\n");
299 return -1;
300 }
301
302 network = conn->conn->bts->network;
303 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, length - 1, 0, 0);
304
305 if (!TLVP_PRESENT(&tp, GSM0808_IE_CHANNEL_TYPE)) {
306 LOGP(DMSC, LOGL_ERROR, "Mandantory channel type not present.\n");
307 goto reject;
308 }
309
310 if (!TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) {
311 LOGP(DMSC, LOGL_ERROR, "Identity code missing. Audio routing will not work.\n");
312 goto reject;
313 }
314
315 cic = ntohs(read_data16(TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)));
316 timeslot = cic & 0x1f;
317 multiplex = (cic & ~0x1f) >> 5;
318
319 /*
320 * Currently we only support a limited subset of all
321 * possible channel types. The limitation ends by not using
322 * multi-slot, limiting the channel coding, speech...
323 */
324 if (TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE) < 3) {
325 LOGP(DMSC, LOGL_ERROR, "ChannelType len !=3 not supported: %d\n",
326 TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE));
327 goto reject;
328 }
329
330 /*
331 * Try to figure out if we support the proposed speech codecs. For
332 * now we will always pick the full rate codecs.
333 */
334
335 data = (uint8_t *) TLVP_VAL(&tp, GSM0808_IE_CHANNEL_TYPE);
336 if ((data[0] & 0xf) != 0x1) {
337 LOGP(DMSC, LOGL_ERROR, "ChannelType != speech: %d\n", data[0]);
338 goto reject;
339 }
340
341 if (data[1] != GSM0808_SPEECH_FULL_PREF && data[1] != GSM0808_SPEECH_HALF_PREF) {
342 LOGP(DMSC, LOGL_ERROR, "ChannelType full not allowed: %d\n", data[1]);
343 goto reject;
344 }
345
346 /*
347 * go through the list of preferred codecs of our gsm network
348 * and try to find it among the permitted codecs. If we found
349 * it we will send chan_mode to the right mode and break the
350 * inner loop. The outer loop will exit due chan_mode having
351 * the correct value.
352 */
353 full_rate = 0;
354 for (supported = 0;
355 chan_mode == GSM48_CMODE_SIGN && supported < network->msc_data->audio_length;
356 ++supported) {
357
358 int perm_val = audio_support_to_gsm88(network->msc_data->audio_support[supported]);
359 for (i = 2; i < TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE); ++i) {
360 if ((data[i] & 0x7f) == perm_val) {
361 chan_mode = gsm88_to_chan_mode(perm_val);
362 full_rate = (data[i] & 0x4) == 0;
363 break;
364 } else if ((data[i] & 0x80) == 0x00) {
365 break;
366 }
367 }
368 }
369
370 if (chan_mode == GSM48_CMODE_SIGN) {
371 LOGP(DMSC, LOGL_ERROR, "No supported audio type found.\n");
372 goto reject;
373 }
374
375 /* map it to a MGCP Endpoint and a RTP port */
376 port = mgcp_timeslot_to_endpoint(multiplex, timeslot);
377 conn->rtp_port = rtp_calculate_port(port,
378 network->msc_data->rtp_base);
379
380 return gsm0808_assign_req(conn->conn, chan_mode, full_rate);
381
382reject:
383 resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
384 if (!resp) {
385 LOGP(DMSC, LOGL_ERROR, "Channel allocation failure.\n");
386 return -1;
387 }
388
389 bsc_queue_for_msc(conn, resp);
390 return -1;
391}
392
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100393static int bssmap_rcvmsg_udt(struct gsm_network *net,
394 struct msgb *msg, unsigned int length)
395{
396 int ret = 0;
397
398 if (length < 1) {
399 LOGP(DMSC, LOGL_ERROR, "Not enough room: %d\n", length);
400 return -1;
401 }
402
403 switch (msg->l4h[0]) {
404 case BSS_MAP_MSG_RESET_ACKNOWLEDGE:
405 ret = bssmap_handle_reset_ack(net, msg, length);
406 break;
407 case BSS_MAP_MSG_PAGING:
408 if (bsc_grace_allow_new_connection(net))
409 ret = bssmap_handle_paging(net, msg, length);
410 break;
411 }
412
413 return ret;
414}
415
416static int bssmap_rcvmsg_dt1(struct osmo_bsc_sccp_con *conn,
417 struct msgb *msg, unsigned int length)
418{
Holger Hans Peter Freytherf1f57a82010-11-10 09:34:47 +0100419 int ret = 0;
420
421 if (length < 1) {
422 LOGP(DMSC, LOGL_ERROR, "Not enough room: %d\n", length);
423 return -1;
424 }
425
426 switch (msg->l4h[0]) {
427 case BSS_MAP_MSG_CLEAR_CMD:
428 ret = bssmap_handle_clear_command(conn, msg, length);
429 break;
Holger Hans Peter Freytherfae3c652010-11-10 09:44:34 +0100430 case BSS_MAP_MSG_CIPHER_MODE_CMD:
431 ret = bssmap_handle_cipher_mode(conn, msg, length);
432 break;
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +0100433 case BSS_MAP_MSG_ASSIGMENT_RQST:
434 ret = bssmap_handle_assignm_req(conn, msg, length);
435 break;
Holger Hans Peter Freytherf1f57a82010-11-10 09:34:47 +0100436 default:
437 LOGP(DMSC, LOGL_DEBUG, "Unimplemented msg type: %d\n", msg->l4h[0]);
438 break;
439 }
440
441 return ret;
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100442}
443
444static int dtap_rcvmsg(struct osmo_bsc_sccp_con *conn,
445 struct msgb *msg, unsigned int length)
446{
447 return -1;
448}
449
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +0100450int bsc_handle_udt(struct gsm_network *network,
451 struct bsc_msc_connection *conn,
452 struct msgb *msgb, unsigned int length)
453{
454 struct bssmap_header *bs;
455
456 LOGP(DMSC, LOGL_DEBUG, "Incoming SCCP message ftom MSC: %s\n",
457 hexdump(msgb->l3h, length));
458
459 if (length < sizeof(*bs)) {
460 LOGP(DMSC, LOGL_ERROR, "The header is too short.\n");
461 return -1;
462 }
463
464 bs = (struct bssmap_header *) msgb->l3h;
465 if (bs->length < length - sizeof(*bs))
466 return -1;
467
468 switch (bs->type) {
469 case BSSAP_MSG_BSS_MANAGEMENT:
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100470 msgb->l4h = &msgb->l3h[sizeof(*bs)];
471 bssmap_rcvmsg_udt(network, msgb, length - sizeof(*bs));
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +0100472 break;
473 default:
474 LOGP(DMSC, LOGL_ERROR, "Unimplemented msg type: %d\n", bs->type);
475 }
476
477 return 0;
478}
479
480int bsc_handle_dt1(struct osmo_bsc_sccp_con *conn,
481 struct msgb *msg, unsigned int len)
482{
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100483 if (len < sizeof(struct bssmap_header)) {
484 LOGP(DMSC, LOGL_ERROR, "The header is too short.\n");
485 }
486
487 switch (msg->l3h[0]) {
488 case BSSAP_MSG_BSS_MANAGEMENT:
489 msg->l4h = &msg->l3h[sizeof(struct bssmap_header)];
490 bssmap_rcvmsg_dt1(conn, msg, len - sizeof(struct bssmap_header));
491 break;
492 case BSSAP_MSG_DTAP:
493 dtap_rcvmsg(conn, msg, len);
494 break;
495 default:
496 LOGP(DMSC, LOGL_DEBUG, "Unimplemented msg type: %d\n", msg->l3h[0]);
497 }
498
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +0100499 return -1;
500}