blob: a801e0e69e0cd93c33ea5d35515ddb2146e68d0f [file] [log] [blame]
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +01001/* GSM 08.08 BSSMAP handling */
Holger Hans Peter Freytherd2361d92012-12-03 15:32:54 +01002/* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
3 * (C) 2009-2012 by On-Waves
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +01004 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01007 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +01009 * (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
Harald Welte9af6ddf2011-01-01 15:25:50 +010014 * GNU Affero General Public License for more details.
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +010015 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010016 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +010018 *
19 */
20
21#include <openbsc/osmo_bsc.h>
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +010022#include <openbsc/osmo_bsc_grace.h>
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +010023#include <openbsc/osmo_msc_data.h>
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +010024#include <openbsc/debug.h>
Holger Hans Peter Freyther9c838ae2010-11-15 09:16:09 +010025#include <openbsc/gsm_subscriber.h>
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +010026#include <openbsc/mgcp.h>
Holger Hans Peter Freyther9c838ae2010-11-15 09:16:09 +010027#include <openbsc/paging.h>
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +010028
Harald Welted36ff762011-03-23 18:26:56 +010029#include <osmocom/gsm/protocol/gsm_08_08.h>
30#include <osmocom/gsm/gsm0808.h>
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +010031
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +010032#include <arpa/inet.h>
33
34static uint16_t read_data16(const uint8_t *data)
35{
36 uint16_t res;
37
38 memcpy(&res, data, sizeof(res));
39 return res;
40}
41
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +010042/*
43 * helpers for the assignment command
44 */
45enum gsm0808_permitted_speech audio_support_to_gsm88(struct gsm_audio_support *audio)
46{
47 if (audio->hr) {
48 switch (audio->ver) {
49 case 1:
50 return GSM0808_PERM_HR1;
51 break;
52 case 2:
53 return GSM0808_PERM_HR2;
54 break;
55 case 3:
56 return GSM0808_PERM_HR3;
57 break;
58 default:
59 LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: %d\n", audio->ver);
60 return GSM0808_PERM_FR1;
61 }
62 } else {
63 switch (audio->ver) {
64 case 1:
65 return GSM0808_PERM_FR1;
66 break;
67 case 2:
68 return GSM0808_PERM_FR2;
69 break;
70 case 3:
71 return GSM0808_PERM_FR3;
72 break;
73 default:
74 LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: %d\n", audio->ver);
75 return GSM0808_PERM_HR1;
76 }
77 }
78}
79
80enum gsm48_chan_mode gsm88_to_chan_mode(enum gsm0808_permitted_speech speech)
81{
82 switch (speech) {
83 case GSM0808_PERM_HR1:
84 case GSM0808_PERM_FR1:
85 return GSM48_CMODE_SPEECH_V1;
86 break;
87 case GSM0808_PERM_HR2:
88 case GSM0808_PERM_FR2:
89 return GSM48_CMODE_SPEECH_EFR;
90 break;
91 case GSM0808_PERM_HR3:
92 case GSM0808_PERM_FR3:
93 return GSM48_CMODE_SPEECH_AMR;
94 break;
95 }
96
97 LOGP(DMSC, LOGL_FATAL, "Should not be reached.\n");
98 return GSM48_CMODE_SPEECH_AMR;
99}
100
Holger Hans Peter Freyther644b0bf2011-06-08 15:52:07 +0200101static int bssmap_handle_reset_ack(struct osmo_msc_data *msc,
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100102 struct msgb *msg, unsigned int length)
103{
104 LOGP(DMSC, LOGL_NOTICE, "Reset ACK from MSC\n");
105 return 0;
106}
107
108/* GSM 08.08 ยง 3.2.1.19 */
Holger Hans Peter Freyther644b0bf2011-06-08 15:52:07 +0200109static int bssmap_handle_paging(struct osmo_msc_data *msc,
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100110 struct msgb *msg, unsigned int payload_length)
111{
Holger Hans Peter Freyther9c838ae2010-11-15 09:16:09 +0100112 struct gsm_subscriber *subscr;
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100113 struct tlv_parsed tp;
114 char mi_string[GSM48_MI_SIZE];
115 uint32_t tmsi = GSM_RESERVED_TMSI;
116 unsigned int lac = GSM_LAC_RESERVED_ALL_BTS;
117 uint8_t data_length;
118 const uint8_t *data;
119 uint8_t chan_needed = RSL_CHANNEED_ANY;
120
121 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, payload_length - 1, 0, 0);
122
123 if (!TLVP_PRESENT(&tp, GSM0808_IE_IMSI)) {
Holger Hans Peter Freyther59043d82012-08-03 11:05:29 +0200124 LOGP(DMSC, LOGL_ERROR, "Mandatory IMSI not present.\n");
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100125 return -1;
126 } else if ((TLVP_VAL(&tp, GSM0808_IE_IMSI)[0] & GSM_MI_TYPE_MASK) != GSM_MI_TYPE_IMSI) {
127 LOGP(DMSC, LOGL_ERROR, "Wrong content in the IMSI\n");
128 return -1;
129 }
130
131 if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST)) {
Holger Hans Peter Freyther59043d82012-08-03 11:05:29 +0200132 LOGP(DMSC, LOGL_ERROR, "Mandatory CELL IDENTIFIER LIST not present.\n");
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100133 return -1;
134 }
135
Harald Welted55cef92012-01-20 17:20:51 +0100136 if (TLVP_PRESENT(&tp, GSM0808_IE_TMSI) &&
137 TLVP_LEN(&tp, GSM0808_IE_TMSI) == 4) {
Daniel Willmann8a485f02014-06-27 17:05:47 +0200138 tmsi = ntohl(tlvp_val32_unal(&tp, GSM0808_IE_TMSI));
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100139 }
140
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100141 /*
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) {
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200159 LOGP(DMSC, LOGL_ERROR, "Unsupported Cell Identifier List: %s\n", osmo_hexdump(data, data_length));
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100160 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
Jacob Erlbeck1e30a282014-12-03 09:28:24 +0100170 subscr = subscr_get_or_create(msc->network->subscr_group, mi_string);
Holger Hans Peter Freyther9c838ae2010-11-15 09:16:09 +0100171 if (!subscr) {
172 LOGP(DMSC, LOGL_ERROR, "Failed to allocate a subscriber for %s\n", mi_string);
173 return -1;
174 }
175
176 subscr->lac = lac;
177 subscr->tmsi = tmsi;
178
Harald Weltecccd3012011-07-11 18:18:35 +0200179 LOGP(DMSC, LOGL_INFO, "Paging request from MSC IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x\n", mi_string, tmsi, tmsi, lac);
Holger Hans Peter Freytherdc030962013-01-07 17:30:13 +0100180 bsc_grace_paging_request(subscr, chan_needed, msc);
Holger Hans Peter Freyther9c838ae2010-11-15 09:16:09 +0100181 return 0;
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100182}
183
Holger Hans Peter Freytherf1f57a82010-11-10 09:34:47 +0100184/*
185 * GSM 08.08 ยง 3.1.9.1 and 3.2.1.21...
186 * release our gsm_subscriber_connection and send message
187 */
188static int bssmap_handle_clear_command(struct osmo_bsc_sccp_con *conn,
189 struct msgb *msg, unsigned int payload_length)
190{
191 struct msgb *resp;
192
193 /* TODO: handle the cause of this package */
194
195 if (conn->conn) {
Harald Weltecccd3012011-07-11 18:18:35 +0200196 LOGP(DMSC, LOGL_INFO, "Releasing all transactions on %p\n", conn);
Holger Hans Peter Freytherf1f57a82010-11-10 09:34:47 +0100197 gsm0808_clear(conn->conn);
198 subscr_con_free(conn->conn);
199 conn->conn = NULL;
200 }
201
202 /* send the clear complete message */
203 resp = gsm0808_create_clear_complete();
204 if (!resp) {
205 LOGP(DMSC, LOGL_ERROR, "Sending clear complete failed.\n");
206 return -1;
207 }
208
209 bsc_queue_for_msc(conn, resp);
210 return 0;
211}
212
Holger Hans Peter Freytherfae3c652010-11-10 09:44:34 +0100213/*
214 * GSM 08.08 ยง 3.4.7 cipher mode handling. We will have to pick
215 * the cipher to be used for this. In case we are already using
216 * a cipher we will have to send cipher mode reject to the MSC,
217 * otherwise we will have to pick something that we and the MS
218 * is supporting. Currently we are doing it in a rather static
219 * way by picking one ecnryption or no encrytpion.
220 */
221static int bssmap_handle_cipher_mode(struct osmo_bsc_sccp_con *conn,
222 struct msgb *msg, unsigned int payload_length)
223{
224 uint16_t len;
225 struct gsm_network *network = NULL;
226 const uint8_t *data;
227 struct tlv_parsed tp;
228 struct msgb *resp;
229 int reject_cause = -1;
230 int include_imeisv = 1;
231
232 if (!conn->conn) {
233 LOGP(DMSC, LOGL_ERROR, "No lchan/msc_data in cipher mode command.\n");
234 goto reject;
235 }
236
237 if (conn->ciphering_handled) {
238 LOGP(DMSC, LOGL_ERROR, "Already seen ciphering command. Protocol Error.\n");
239 goto reject;
240 }
241
242 conn->ciphering_handled = 1;
243
244 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, payload_length - 1, 0, 0);
245 if (!TLVP_PRESENT(&tp, GSM0808_IE_ENCRYPTION_INFORMATION)) {
246 LOGP(DMSC, LOGL_ERROR, "IE Encryption Information missing.\n");
247 goto reject;
248 }
249
250 /*
251 * check if our global setting is allowed
252 * - Currently we check for A5/0 and A5/1
253 * - Copy the key if that is necessary
254 * - Otherwise reject
255 */
256 len = TLVP_LEN(&tp, GSM0808_IE_ENCRYPTION_INFORMATION);
257 if (len < 1) {
258 LOGP(DMSC, LOGL_ERROR, "IE Encryption Information is too short.\n");
259 goto reject;
260 }
261
262 network = conn->conn->bts->network;
263 data = TLVP_VAL(&tp, GSM0808_IE_ENCRYPTION_INFORMATION);
264
265 if (TLVP_PRESENT(&tp, GSM0808_IE_CIPHER_RESPONSE_MODE))
266 include_imeisv = TLVP_VAL(&tp, GSM0808_IE_CIPHER_RESPONSE_MODE)[0] & 0x1;
267
268 if (network->a5_encryption == 0 && (data[0] & 0x1) == 0x1) {
269 gsm0808_cipher_mode(conn->conn, 0, NULL, 0, include_imeisv);
270 } else if (network->a5_encryption != 0 && (data[0] & 0x2) == 0x2) {
271 gsm0808_cipher_mode(conn->conn, 1, &data[1], len - 1, include_imeisv);
272 } else {
273 LOGP(DMSC, LOGL_ERROR, "Can not select encryption...\n");
274 goto reject;
275 }
276
Harald Welte75413c42011-07-12 00:03:43 +0200277 return 0;
278
Holger Hans Peter Freytherfae3c652010-11-10 09:44:34 +0100279reject:
280 resp = gsm0808_create_cipher_reject(reject_cause);
281 if (!resp) {
282 LOGP(DMSC, LOGL_ERROR, "Sending the cipher reject failed.\n");
283 return -1;
284 }
285
286 bsc_queue_for_msc(conn, resp);
287 return -1;
288}
289
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +0100290/*
291 * Handle the assignment request message.
292 *
293 * See ยง3.2.1.1 for the message type
294 */
295static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn,
296 struct msgb *msg, unsigned int length)
297{
298 struct msgb *resp;
Holger Hans Peter Freyther8ec49522011-08-15 15:53:00 +0200299 struct osmo_msc_data *msc;
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +0100300 struct tlv_parsed tp;
301 uint8_t *data;
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +0100302 uint8_t timeslot;
303 uint8_t multiplex;
304 enum gsm48_chan_mode chan_mode = GSM48_CMODE_SIGN;
305 int i, supported, port, full_rate = -1;
306
307 if (!conn->conn) {
308 LOGP(DMSC, LOGL_ERROR, "No lchan/msc_data in cipher mode command.\n");
309 return -1;
310 }
311
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +0100312 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, length - 1, 0, 0);
313
314 if (!TLVP_PRESENT(&tp, GSM0808_IE_CHANNEL_TYPE)) {
Holger Hans Peter Freyther59043d82012-08-03 11:05:29 +0200315 LOGP(DMSC, LOGL_ERROR, "Mandatory channel type not present.\n");
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +0100316 goto reject;
317 }
318
319 if (!TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) {
320 LOGP(DMSC, LOGL_ERROR, "Identity code missing. Audio routing will not work.\n");
321 goto reject;
322 }
323
Holger Hans Peter Freyther93dfa242014-08-08 21:06:30 +0200324 conn->cic = ntohs(read_data16(TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)));
325 timeslot = conn->cic & 0x1f;
326 multiplex = (conn->cic & ~0x1f) >> 5;
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +0100327
328 /*
329 * Currently we only support a limited subset of all
330 * possible channel types. The limitation ends by not using
331 * multi-slot, limiting the channel coding, speech...
332 */
333 if (TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE) < 3) {
334 LOGP(DMSC, LOGL_ERROR, "ChannelType len !=3 not supported: %d\n",
335 TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE));
336 goto reject;
337 }
338
339 /*
340 * Try to figure out if we support the proposed speech codecs. For
341 * now we will always pick the full rate codecs.
342 */
343
344 data = (uint8_t *) TLVP_VAL(&tp, GSM0808_IE_CHANNEL_TYPE);
345 if ((data[0] & 0xf) != 0x1) {
346 LOGP(DMSC, LOGL_ERROR, "ChannelType != speech: %d\n", data[0]);
347 goto reject;
348 }
349
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +0100350 /*
351 * go through the list of preferred codecs of our gsm network
352 * and try to find it among the permitted codecs. If we found
353 * it we will send chan_mode to the right mode and break the
354 * inner loop. The outer loop will exit due chan_mode having
355 * the correct value.
356 */
357 full_rate = 0;
Holger Hans Peter Freytherf936fb42011-06-04 15:12:57 +0200358 msc = conn->msc;
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +0100359 for (supported = 0;
Holger Hans Peter Freyther8ec49522011-08-15 15:53:00 +0200360 chan_mode == GSM48_CMODE_SIGN && supported < msc->audio_length;
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +0100361 ++supported) {
362
Holger Hans Peter Freyther8ec49522011-08-15 15:53:00 +0200363 int perm_val = audio_support_to_gsm88(msc->audio_support[supported]);
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +0100364 for (i = 2; i < TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE); ++i) {
365 if ((data[i] & 0x7f) == perm_val) {
366 chan_mode = gsm88_to_chan_mode(perm_val);
367 full_rate = (data[i] & 0x4) == 0;
368 break;
369 } else if ((data[i] & 0x80) == 0x00) {
370 break;
371 }
372 }
373 }
374
375 if (chan_mode == GSM48_CMODE_SIGN) {
376 LOGP(DMSC, LOGL_ERROR, "No supported audio type found.\n");
377 goto reject;
378 }
379
380 /* map it to a MGCP Endpoint and a RTP port */
381 port = mgcp_timeslot_to_endpoint(multiplex, timeslot);
Holger Hans Peter Freyther8ec49522011-08-15 15:53:00 +0200382 conn->rtp_port = rtp_calculate_port(port, msc->rtp_base);
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +0100383
384 return gsm0808_assign_req(conn->conn, chan_mode, full_rate);
385
386reject:
387 resp = gsm0808_create_assignment_failure(GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
388 if (!resp) {
389 LOGP(DMSC, LOGL_ERROR, "Channel allocation failure.\n");
390 return -1;
391 }
392
393 bsc_queue_for_msc(conn, resp);
394 return -1;
395}
396
Holger Hans Peter Freyther644b0bf2011-06-08 15:52:07 +0200397static int bssmap_rcvmsg_udt(struct osmo_msc_data *msc,
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100398 struct msgb *msg, unsigned int length)
399{
400 int ret = 0;
401
402 if (length < 1) {
403 LOGP(DMSC, LOGL_ERROR, "Not enough room: %d\n", length);
404 return -1;
405 }
406
Harald Weltecccd3012011-07-11 18:18:35 +0200407 LOGP(DMSC, LOGL_INFO, "Rx MSC UDT BSSMAP %s\n",
408 gsm0808_bssmap_name(msg->l4h[0]));
409
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100410 switch (msg->l4h[0]) {
411 case BSS_MAP_MSG_RESET_ACKNOWLEDGE:
Holger Hans Peter Freyther644b0bf2011-06-08 15:52:07 +0200412 ret = bssmap_handle_reset_ack(msc, msg, length);
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100413 break;
414 case BSS_MAP_MSG_PAGING:
Holger Hans Peter Freytherdc030962013-01-07 17:30:13 +0100415 ret = bssmap_handle_paging(msc, msg, length);
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100416 break;
417 }
418
419 return ret;
420}
421
422static int bssmap_rcvmsg_dt1(struct osmo_bsc_sccp_con *conn,
423 struct msgb *msg, unsigned int length)
424{
Holger Hans Peter Freytherf1f57a82010-11-10 09:34:47 +0100425 int ret = 0;
426
427 if (length < 1) {
428 LOGP(DMSC, LOGL_ERROR, "Not enough room: %d\n", length);
429 return -1;
430 }
431
Harald Weltecccd3012011-07-11 18:18:35 +0200432 LOGP(DMSC, LOGL_INFO, "Rx MSC DT1 BSSMAP %s\n",
433 gsm0808_bssmap_name(msg->l4h[0]));
434
Holger Hans Peter Freytherf1f57a82010-11-10 09:34:47 +0100435 switch (msg->l4h[0]) {
436 case BSS_MAP_MSG_CLEAR_CMD:
437 ret = bssmap_handle_clear_command(conn, msg, length);
438 break;
Holger Hans Peter Freytherfae3c652010-11-10 09:44:34 +0100439 case BSS_MAP_MSG_CIPHER_MODE_CMD:
440 ret = bssmap_handle_cipher_mode(conn, msg, length);
441 break;
Holger Hans Peter Freyther50c579b2010-11-10 10:07:30 +0100442 case BSS_MAP_MSG_ASSIGMENT_RQST:
443 ret = bssmap_handle_assignm_req(conn, msg, length);
444 break;
Holger Hans Peter Freytherf1f57a82010-11-10 09:34:47 +0100445 default:
Harald Welte9f32a8a2011-07-11 17:56:34 +0200446 LOGP(DMSC, LOGL_NOTICE, "Unimplemented msg type: %s\n",
447 gsm0808_bssmap_name(msg->l4h[0]));
Holger Hans Peter Freytherf1f57a82010-11-10 09:34:47 +0100448 break;
449 }
450
451 return ret;
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100452}
453
454static int dtap_rcvmsg(struct osmo_bsc_sccp_con *conn,
455 struct msgb *msg, unsigned int length)
456{
Holger Hans Peter Freytherdbc698a2010-11-10 10:17:05 +0100457 struct dtap_header *header;
458 struct msgb *gsm48;
459 uint8_t *data;
Holger Hans Peter Freyther3d4d79d2012-12-03 15:32:54 +0100460 int rc, dtap_rc;
Holger Hans Peter Freytherdbc698a2010-11-10 10:17:05 +0100461
Harald Weltecccd3012011-07-11 18:18:35 +0200462 LOGP(DMSC, LOGL_DEBUG, "Rx MSC DTAP: %s\n",
463 osmo_hexdump(msg->l3h, length));
464
Holger Hans Peter Freytherdbc698a2010-11-10 10:17:05 +0100465 if (!conn->conn) {
466 LOGP(DMSC, LOGL_ERROR, "No subscriber connection available\n");
467 return -1;
468 }
469
470 header = (struct dtap_header *) msg->l3h;
471 if (sizeof(*header) >= length) {
Holger Hans Peter Freyther2f2be572012-03-16 12:18:39 +0100472 LOGP(DMSC, LOGL_ERROR, "The DTAP header does not fit. Wanted: %zu got: %u\n", sizeof(*header), length);
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200473 LOGP(DMSC, LOGL_ERROR, "hex: %s\n", osmo_hexdump(msg->l3h, length));
Holger Hans Peter Freytherdbc698a2010-11-10 10:17:05 +0100474 return -1;
475 }
476
477 if (header->length > length - sizeof(*header)) {
478 LOGP(DMSC, LOGL_ERROR, "The DTAP l4 information does not fit: header: %u length: %u\n", header->length, length);
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200479 LOGP(DMSC, LOGL_ERROR, "hex: %s\n", osmo_hexdump(msg->l3h, length));
Holger Hans Peter Freytherdbc698a2010-11-10 10:17:05 +0100480 return -1;
481 }
482
Harald Weltecccd3012011-07-11 18:18:35 +0200483 LOGP(DMSC, LOGL_INFO, "Rx MSC DTAP, SAPI: %u CHAN: %u\n", header->link_id & 0x07, header->link_id & 0xC0);
Holger Hans Peter Freytherdbc698a2010-11-10 10:17:05 +0100484
485 /* forward the data */
486 gsm48 = gsm48_msgb_alloc();
487 if (!gsm48) {
488 LOGP(DMSC, LOGL_ERROR, "Allocation of the message failed.\n");
489 return -1;
490 }
491
492 gsm48->l3h = gsm48->data;
493 data = msgb_put(gsm48, length - sizeof(*header));
494 memcpy(data, msg->l3h + sizeof(*header), length - sizeof(*header));
495
496 /* pass it to the filter for extra actions */
Holger Hans Peter Freytherd2361d92012-12-03 15:32:54 +0100497 rc = bsc_scan_msc_msg(conn->conn, gsm48);
Holger Hans Peter Freyther3d4d79d2012-12-03 15:32:54 +0100498 dtap_rc = gsm0808_submit_dtap(conn->conn, gsm48, header->link_id, 1);
Holger Hans Peter Freytherd2361d92012-12-03 15:32:54 +0100499 if (rc == BSS_SEND_USSD)
500 bsc_send_welcome_ussd(conn->conn);
Holger Hans Peter Freyther3d4d79d2012-12-03 15:32:54 +0100501 return dtap_rc;
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100502}
503
Holger Hans Peter Freyther644b0bf2011-06-08 15:52:07 +0200504int bsc_handle_udt(struct osmo_msc_data *msc,
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +0100505 struct msgb *msgb, unsigned int length)
506{
507 struct bssmap_header *bs;
508
Harald Weltecccd3012011-07-11 18:18:35 +0200509 LOGP(DMSC, LOGL_DEBUG, "Rx MSC UDT: %s\n",
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200510 osmo_hexdump(msgb->l3h, length));
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +0100511
512 if (length < sizeof(*bs)) {
513 LOGP(DMSC, LOGL_ERROR, "The header is too short.\n");
514 return -1;
515 }
516
517 bs = (struct bssmap_header *) msgb->l3h;
518 if (bs->length < length - sizeof(*bs))
519 return -1;
520
521 switch (bs->type) {
522 case BSSAP_MSG_BSS_MANAGEMENT:
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100523 msgb->l4h = &msgb->l3h[sizeof(*bs)];
Holger Hans Peter Freyther644b0bf2011-06-08 15:52:07 +0200524 bssmap_rcvmsg_udt(msc, msgb, length - sizeof(*bs));
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +0100525 break;
526 default:
Harald Welte9f32a8a2011-07-11 17:56:34 +0200527 LOGP(DMSC, LOGL_NOTICE, "Unimplemented msg type: %s\n",
528 gsm0808_bssmap_name(bs->type));
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +0100529 }
530
531 return 0;
532}
533
534int bsc_handle_dt1(struct osmo_bsc_sccp_con *conn,
535 struct msgb *msg, unsigned int len)
536{
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100537 if (len < sizeof(struct bssmap_header)) {
538 LOGP(DMSC, LOGL_ERROR, "The header is too short.\n");
539 }
540
541 switch (msg->l3h[0]) {
542 case BSSAP_MSG_BSS_MANAGEMENT:
543 msg->l4h = &msg->l3h[sizeof(struct bssmap_header)];
544 bssmap_rcvmsg_dt1(conn, msg, len - sizeof(struct bssmap_header));
545 break;
546 case BSSAP_MSG_DTAP:
547 dtap_rcvmsg(conn, msg, len);
548 break;
549 default:
Harald Weltecccd3012011-07-11 18:18:35 +0200550 LOGP(DMSC, LOGL_NOTICE, "Unimplemented BSSAP msg type: %s\n",
551 gsm0808_bssap_name(msg->l3h[0]));
Holger Hans Peter Freyther890dfc52010-11-10 09:24:37 +0100552 }
553
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +0100554 return -1;
555}