blob: 77a77799a212362476c34fa10cd356b1a2ce5292 [file] [log] [blame]
Philipp Maierfbf66102017-04-09 12:32:51 +02001/* (C) 2017 by Sysmocom s.f.m.c. GmbH
2 * All Rights Reserved
3 *
4 * Author: Philipp Maier
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * 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
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 Affero General Public License for more details.
15 *
16 * 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/>.
18 *
19 */
20
21#include <osmocom/core/utils.h>
22#include <osmocom/core/msgb.h>
23#include <osmocom/core/logging.h>
24#include <osmocom/sigtran/sccp_helpers.h>
25#include <osmocom/sccp/sccp_types.h>
26#include <osmocom/gsm/gsm0808.h>
Max43b01b02017-09-15 11:22:30 +020027#include <osmocom/gsm/gsm48.h>
Philipp Maierfbf66102017-04-09 12:32:51 +020028#include <osmocom/gsm/gsm0808_utils.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020029#include <osmocom/msc/debug.h>
30#include <osmocom/msc/gsm_data.h>
31#include <osmocom/msc/a_iface_bssap.h>
32#include <osmocom/msc/a_iface.h>
33#include <osmocom/msc/osmo_msc.h>
Philipp Maierfbf66102017-04-09 12:32:51 +020034#include <osmocom/core/byteswap.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020035#include <osmocom/msc/a_reset.h>
Max43b01b02017-09-15 11:22:30 +020036#include <osmocom/msc/transaction.h>
Philipp Maier621ba032017-11-07 17:19:25 +010037#include <osmocom/msc/msc_mgcp.h>
Max43b01b02017-09-15 11:22:30 +020038
39#include <errno.h>
Philipp Maierfbf66102017-04-09 12:32:51 +020040
41#define IP_V4_ADDR_LEN 4
42
43/*
44 * Helper functions to lookup and allocate subscribers
45 */
46
47/* Allocate a new subscriber connection */
48static struct gsm_subscriber_connection *subscr_conn_allocate_a(const struct a_conn_info *a_conn_info,
49 struct gsm_network *network,
50 uint16_t lac, struct osmo_sccp_user *scu, int conn_id)
51{
52 struct gsm_subscriber_connection *conn;
53
Harald Weltef0dc1be2018-02-09 00:37:56 +010054 LOGP(DMSC, LOGL_DEBUG, "Allocating A-Interface subscriber conn: lac %i, conn_id %i\n", lac, conn_id);
Philipp Maierfbf66102017-04-09 12:32:51 +020055
56 conn = talloc_zero(network, struct gsm_subscriber_connection);
57 if (!conn)
58 return NULL;
59
60 conn->network = network;
61 conn->via_ran = RAN_GERAN_A;
62 conn->lac = lac;
63
64 conn->a.conn_id = conn_id;
65 conn->a.scu = scu;
66
67 /* Also backup the calling address of the BSC, this allows us to
68 * identify later which BSC is responsible for this subscriber connection */
Harald Welte54a10ef2018-02-09 00:09:16 +010069 memcpy(&conn->a.bsc_addr, &a_conn_info->bsc->bsc_addr, sizeof(conn->a.bsc_addr));
Philipp Maierfbf66102017-04-09 12:32:51 +020070
71 llist_add_tail(&conn->entry, &network->subscr_conns);
Harald Welte6de46592018-02-09 00:53:17 +010072 LOGPCONN(conn, LOGL_DEBUG, "A-Interface subscriber connection successfully allocated!\n");
Philipp Maierfbf66102017-04-09 12:32:51 +020073 return conn;
74}
75
76/* Return an existing A subscriber connection record for the given
77 * connection IDs, or return NULL if not found. */
78static struct gsm_subscriber_connection *subscr_conn_lookup_a(const struct gsm_network *network, int conn_id)
79{
80 struct gsm_subscriber_connection *conn;
81
82 OSMO_ASSERT(network);
83
84 DEBUGP(DMSC, "Looking for A subscriber: conn_id %i\n", conn_id);
85
86 /* FIXME: log_subscribers() is defined in iucs.c as static inline, if
87 * maybe this function should be public to reach it from here? */
88 /* log_subscribers(network); */
89
90 llist_for_each_entry(conn, &network->subscr_conns, entry) {
91 if (conn->via_ran == RAN_GERAN_A && conn->a.conn_id == conn_id) {
Harald Welte6de46592018-02-09 00:53:17 +010092 LOGPCONN(conn, LOGL_DEBUG, "Found A subscriber for conn_id %i\n", conn_id);
Philipp Maierfbf66102017-04-09 12:32:51 +020093 return conn;
94 }
95 }
96 DEBUGP(DMSC, "No A subscriber found for conn_id %i\n", conn_id);
97 return NULL;
98}
99
100/*
101 * BSSMAP handling for UNITDATA
102 */
103
104/* Endpoint to handle BSSMAP reset */
105static void bssmap_rx_reset(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
106{
107 struct gsm_network *network = a_conn_info->network;
108 struct osmo_ss7_instance *ss7;
109
110 ss7 = osmo_ss7_instance_find(network->a.cs7_instance);
111 OSMO_ASSERT(ss7);
112
Harald Weltefb7ba912018-02-09 01:05:27 +0100113 LOGP(DMSC, LOGL_NOTICE, "Rx BSSMAP RESET from BSC %s, sending RESET ACK\n",
Harald Welte54a10ef2018-02-09 00:09:16 +0100114 osmo_sccp_addr_name(ss7, &a_conn_info->bsc->bsc_addr));
115 osmo_sccp_tx_unitdata_msg(scu, &a_conn_info->bsc->msc_addr, &a_conn_info->bsc->bsc_addr,
116 gsm0808_create_reset_ack());
Philipp Maierfbf66102017-04-09 12:32:51 +0200117
118 /* Make sure all orphand subscriber connections will be cleard */
Harald Welte54a10ef2018-02-09 00:09:16 +0100119 a_clear_all(scu, &a_conn_info->bsc->bsc_addr);
120
121 if (!a_conn_info->bsc->reset)
122 a_start_reset(a_conn_info->bsc, true);
Philipp Maierfbf66102017-04-09 12:32:51 +0200123
124 msgb_free(msg);
125}
126
127/* Endpoint to handle BSSMAP reset acknowlegement */
128static void bssmap_rx_reset_ack(const struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info,
129 struct msgb *msg)
130{
131
132 struct gsm_network *network = a_conn_info->network;
133 struct osmo_ss7_instance *ss7;
134
135 ss7 = osmo_ss7_instance_find(network->a.cs7_instance);
136 OSMO_ASSERT(ss7);
137
Harald Welte54a10ef2018-02-09 00:09:16 +0100138 if (a_conn_info->bsc->reset == NULL) {
Philipp Maierfbf66102017-04-09 12:32:51 +0200139 LOGP(DMSC, LOGL_ERROR, "Received RESET ACK from an unknown BSC %s, ignoring...\n",
Harald Welte54a10ef2018-02-09 00:09:16 +0100140 osmo_sccp_addr_name(ss7, &a_conn_info->bsc->bsc_addr));
Philipp Maierfbf66102017-04-09 12:32:51 +0200141 goto fail;
142 }
143
Harald Welte54a10ef2018-02-09 00:09:16 +0100144 LOGP(DMSC, LOGL_NOTICE, "Received RESET ACK from BSC %s\n",
145 osmo_sccp_addr_name(ss7, &a_conn_info->bsc->bsc_addr));
Philipp Maierfbf66102017-04-09 12:32:51 +0200146
147 /* Confirm that we managed to get the reset ack message
148 * towards the connection reset logic */
Harald Welte54a10ef2018-02-09 00:09:16 +0100149 a_reset_ack_confirm(a_conn_info->bsc->reset);
Philipp Maierfbf66102017-04-09 12:32:51 +0200150
151fail:
152 msgb_free(msg);
153}
154
155/* Handle UNITDATA BSSMAP messages */
156static void bssmap_rcvmsg_udt(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
157{
158 /* Note: When in the MSC role, RESET ACK is the only valid message that
159 * can be received via UNITDATA */
160
161 if (msgb_l3len(msg) < 1) {
162 LOGP(DMSC, LOGL_NOTICE, "Error: No data received -- discarding message!\n");
Philipp Maier4502f5f2017-09-07 11:39:58 +0200163 msgb_free(msg);
Philipp Maierfbf66102017-04-09 12:32:51 +0200164 return;
165 }
166
Harald Weltefb7ba912018-02-09 01:05:27 +0100167 LOGP(DMSC, LOGL_DEBUG, "Rx BSSMAP UDT %s\n", gsm0808_bssmap_name(msg->l3h[0]));
Philipp Maierfbf66102017-04-09 12:32:51 +0200168
169 switch (msg->l3h[0]) {
170 case BSS_MAP_MSG_RESET:
171 bssmap_rx_reset(scu, a_conn_info, msg);
172 break;
173 case BSS_MAP_MSG_RESET_ACKNOWLEDGE:
174 bssmap_rx_reset_ack(scu, a_conn_info, msg);
175 break;
176 default:
177 LOGP(DMSC, LOGL_NOTICE, "Unimplemented message format: %s -- message discarded!\n",
178 gsm0808_bssmap_name(msg->l3h[0]));
179 msgb_free(msg);
180 }
181}
182
183/* Receive incoming connection less data messages via sccp */
Neels Hofmeyrc1d69252017-12-18 04:06:04 +0100184void a_sccp_rx_udt(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
Philipp Maierfbf66102017-04-09 12:32:51 +0200185{
186 /* Note: The only valid message type that can be received
187 * via UNITDATA are BSS Management messages */
188 struct bssmap_header *bs;
189
190 OSMO_ASSERT(scu);
191 OSMO_ASSERT(a_conn_info);
192 OSMO_ASSERT(msg);
193
Harald Weltef0dc1be2018-02-09 00:37:56 +0100194 LOGP(DMSC, LOGL_DEBUG, "Rx BSSMAP UDT: %s\n", msgb_hexdump_l2(msg));
Philipp Maierfbf66102017-04-09 12:32:51 +0200195
196 if (msgb_l2len(msg) < sizeof(*bs)) {
197 LOGP(DMSC, LOGL_ERROR, "Error: Header is too short -- discarding message!\n");
198 msgb_free(msg);
199 return;
200 }
201
202 bs = (struct bssmap_header *)msgb_l2(msg);
203 if (bs->length < msgb_l2len(msg) - sizeof(*bs)) {
204 LOGP(DMSC, LOGL_ERROR, "Error: Message is too short -- discarding message!\n");
205 msgb_free(msg);
206 return;
207 }
208
209 switch (bs->type) {
210 case BSSAP_MSG_BSS_MANAGEMENT:
211 msg->l3h = &msg->l2h[sizeof(struct bssmap_header)];
212 bssmap_rcvmsg_udt(scu, a_conn_info, msg);
213 break;
214 default:
215 LOGP(DMSC, LOGL_ERROR,
216 "Error: Unimplemented message type: %s -- message discarded!\n", gsm0808_bssmap_name(bs->type));
217 msgb_free(msg);
218 }
219}
220
221/*
222 * BSSMAP handling for connection oriented data
223 */
224
225/* Endpoint to handle BSSMAP clear request */
226static int bssmap_rx_clear_rqst(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
227{
228 struct gsm_network *network = a_conn_info->network;
229 struct tlv_parsed tp;
230 int rc;
231 struct msgb *msg_resp;
232 uint8_t cause;
233 struct gsm_subscriber_connection *conn;
234
Harald Weltef0dc1be2018-02-09 00:37:56 +0100235 LOGP(DMSC, LOGL_INFO, "BSC requested to clear connection (conn_id=%i)\n", a_conn_info->conn_id);
Philipp Maierfbf66102017-04-09 12:32:51 +0200236
237 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, msgb_l3len(msg) - 1, 0, 0);
238 if (!TLVP_PRESENT(&tp, GSM0808_IE_CAUSE)) {
239 LOGP(DMSC, LOGL_ERROR, "Cause code is missing -- discarding message!\n");
240 goto fail;
241 }
242 cause = TLVP_VAL(&tp, GSM0808_IE_CAUSE)[0];
243
244 /* Respond with clear command */
245 msg_resp = gsm0808_create_clear_command(GSM0808_CAUSE_CALL_CONTROL);
246 rc = osmo_sccp_tx_data_msg(scu, a_conn_info->conn_id, msg_resp);
247
248 /* If possible, inform the MSC about the clear request */
249 conn = subscr_conn_lookup_a(network, a_conn_info->conn_id);
250 if (!conn)
251 goto fail;
252 msc_clear_request(conn, cause);
253
254 msgb_free(msg);
255 return rc;
256
257fail:
258 msgb_free(msg);
259 return -EINVAL;
260}
261
262/* Endpoint to handle BSSMAP clear complete */
263static int bssmap_rx_clear_complete(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
264{
265 int rc;
266
Harald Weltef0dc1be2018-02-09 00:37:56 +0100267 LOGP(DMSC, LOGL_INFO, "Releasing connection (conn_id=%i)\n", a_conn_info->conn_id);
Philipp Maierfbf66102017-04-09 12:32:51 +0200268 rc = osmo_sccp_tx_disconn(scu, a_conn_info->conn_id,
Harald Welte54a10ef2018-02-09 00:09:16 +0100269 NULL, SCCP_RELEASE_CAUSE_END_USER_ORIGINATED);
Philipp Maierfbf66102017-04-09 12:32:51 +0200270
271 /* Remove the record from the list with active connections. */
272 a_delete_bsc_con(a_conn_info->conn_id);
273
274 msgb_free(msg);
275 return rc;
276}
277
278/* Endpoint to handle layer 3 complete messages */
279static int bssmap_rx_l3_compl(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
280{
281 struct tlv_parsed tp;
282 struct {
283 uint8_t ident;
284 struct gsm48_loc_area_id lai;
285 uint16_t ci;
286 } __attribute__ ((packed)) lai_ci;
287 uint16_t mcc;
288 uint16_t mnc;
289 uint16_t lac;
290 uint8_t data_length;
291 const uint8_t *data;
292 int rc;
293
294 struct gsm_network *network = a_conn_info->network;
295 struct gsm_subscriber_connection *conn;
296
Harald Weltef0dc1be2018-02-09 00:37:56 +0100297 LOGP(DMSC, LOGL_INFO, "BSC has completed layer 3 connection (conn_id=%i)\n", a_conn_info->conn_id);
Philipp Maierfbf66102017-04-09 12:32:51 +0200298
299 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, msgb_l3len(msg) - 1, 0, 0);
300 if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER)) {
301 LOGP(DMSC, LOGL_ERROR, "Mandatory CELL IDENTIFIER not present -- discarding message!\n");
302 goto fail;
303 }
304 if (!TLVP_PRESENT(&tp, GSM0808_IE_LAYER_3_INFORMATION)) {
305 LOGP(DMSC, LOGL_ERROR, "Mandatory LAYER 3 INFORMATION not present -- discarding message!\n");
306 goto fail;
307 }
308
309 /* Parse Cell ID element */
310 /* FIXME: Encapsulate this in a parser/generator function inside
311 * libosmocore, add support for all specified cell identification
312 * discriminators (see 3GPP ts 3.2.2.17 Cell Identifier) */
313 data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER);
314 data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER);
315 if (sizeof(lai_ci) != data_length) {
316 LOGP(DMSC, LOGL_ERROR,
317 "Unable to parse element CELL IDENTIFIER (wrong field length) -- discarding message!\n");
318 goto fail;
319 }
320 memcpy(&lai_ci, data, sizeof(lai_ci));
321 if (lai_ci.ident != CELL_IDENT_WHOLE_GLOBAL) {
322 LOGP(DMSC, LOGL_ERROR,
323 "Unable to parse element CELL IDENTIFIER (wrong cell identification discriminator) -- discarding message!\n");
324 goto fail;
325 }
326 if (gsm48_decode_lai(&lai_ci.lai, &mcc, &mnc, &lac) != 0) {
327 LOGP(DMSC, LOGL_ERROR,
328 "Unable to parse element CELL IDENTIFIER (lai decoding failed) -- discarding message!\n");
329 goto fail;
330 }
331
332 /* Parse Layer 3 Information element */
333 /* FIXME: This is probably to hackish, compiler also complains "assignment discards ‘const’ qualifier..." */
Neels Hofmeyr9baedaf2017-12-18 04:07:01 +0100334 msg->l3h = (uint8_t*)TLVP_VAL(&tp, GSM0808_IE_LAYER_3_INFORMATION);
Philipp Maierfbf66102017-04-09 12:32:51 +0200335 msg->tail = msg->l3h + TLVP_LEN(&tp, GSM0808_IE_LAYER_3_INFORMATION);
336
337 /* Create new subscriber context */
338 conn = subscr_conn_allocate_a(a_conn_info, network, lac, scu, a_conn_info->conn_id);
339
340 /* Handover location update to the MSC code */
Philipp Maierfbf66102017-04-09 12:32:51 +0200341 rc = msc_compl_l3(conn, msg, 0);
Philipp Maier4502f5f2017-09-07 11:39:58 +0200342 msgb_free(msg);
343
Philipp Maierfbf66102017-04-09 12:32:51 +0200344 if (rc == MSC_CONN_ACCEPT) {
Harald Weltef0dc1be2018-02-09 00:37:56 +0100345 LOGP(DMSC, LOGL_INFO, "User has been accepted by MSC.\n");
Philipp Maierfbf66102017-04-09 12:32:51 +0200346 return 0;
347 } else if (rc == MSC_CONN_REJECT)
Harald Weltef0dc1be2018-02-09 00:37:56 +0100348 LOGP(DMSC, LOGL_INFO, "User has been rejected by MSC.\n");
Philipp Maierfbf66102017-04-09 12:32:51 +0200349 else
Harald Weltef0dc1be2018-02-09 00:37:56 +0100350 LOGP(DMSC, LOGL_INFO, "User has been rejected by MSC (unknown error)\n");
Philipp Maierfbf66102017-04-09 12:32:51 +0200351
352 return -EINVAL;
353
354fail:
355 msgb_free(msg);
356 return -EINVAL;
357}
358
359/* Endpoint to handle BSSMAP classmark update */
360static int bssmap_rx_classmark_upd(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
361{
362 struct gsm_network *network = a_conn_info->network;
363 struct gsm_subscriber_connection *conn;
364 struct tlv_parsed tp;
365 const uint8_t *cm2 = NULL;
366 const uint8_t *cm3 = NULL;
367 uint8_t cm2_len = 0;
368 uint8_t cm3_len = 0;
369
370 conn = subscr_conn_lookup_a(network, a_conn_info->conn_id);
371 if (!conn)
372 goto fail;
373
Harald Weltefb7ba912018-02-09 01:05:27 +0100374 LOGPCONN(conn, LOGL_DEBUG, "Rx BSSMAP CLASSMARK UPDATE\n");
Philipp Maierfbf66102017-04-09 12:32:51 +0200375
376 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, msgb_l3len(msg) - 1, 0, 0);
377 if (!TLVP_PRESENT(&tp, GSM0808_IE_CLASSMARK_INFORMATION_T2)) {
Harald Welte6de46592018-02-09 00:53:17 +0100378 LOGPCONN(conn, LOGL_ERROR, "Mandatory Classmark Information Type 2 not present -- discarding message!\n");
Philipp Maierfbf66102017-04-09 12:32:51 +0200379 goto fail;
380 }
381
382 cm2 = TLVP_VAL(&tp, GSM0808_IE_CLASSMARK_INFORMATION_T2);
383 cm2_len = TLVP_LEN(&tp, GSM0808_IE_CLASSMARK_INFORMATION_T2);
384
385 if (TLVP_PRESENT(&tp, GSM0808_IE_CLASSMARK_INFORMATION_T3)) {
386 cm3 = TLVP_VAL(&tp, GSM0808_IE_CLASSMARK_INFORMATION_T3);
387 cm3_len = TLVP_LEN(&tp, GSM0808_IE_CLASSMARK_INFORMATION_T3);
388 }
389
390 /* Inform MSC about the classmark change */
391 msc_classmark_chg(conn, cm2, cm2_len, cm3, cm3_len);
392
393 msgb_free(msg);
394 return 0;
395
396fail:
397 msgb_free(msg);
398 return -EINVAL;
399}
400
401/* Endpoint to handle BSSMAP cipher mode complete */
402static int bssmap_rx_ciph_compl(const struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info,
403 struct msgb *msg)
404{
405 /* FIXME: The field GSM0808_IE_LAYER_3_MESSAGE_CONTENTS is optional by
406 * means of the specification. So there can be messages without L3 info.
407 * In this case, the code will crash becrause msc_cipher_mode_compl()
408 * is not able to deal with msg = NULL and apperently
409 * msc_cipher_mode_compl() was never meant to be used without L3 data.
410 * This needs to be discussed further! */
411
412 struct gsm_network *network = a_conn_info->network;
413 struct gsm_subscriber_connection *conn;
414 struct tlv_parsed tp;
415 uint8_t alg_id = 1;
416
417 conn = subscr_conn_lookup_a(network, a_conn_info->conn_id);
418 if (!conn)
419 goto fail;
420
Harald Weltefb7ba912018-02-09 01:05:27 +0100421 LOGPCONN(conn, LOGL_DEBUG, "Rx BSSMAP CIPHER MODE COMPLETE\n");
Philipp Maierfbf66102017-04-09 12:32:51 +0200422
423 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, msgb_l3len(msg) - 1, 0, 0);
424
425 if (TLVP_PRESENT(&tp, GSM0808_IE_CHOSEN_ENCR_ALG)) {
426 alg_id = TLVP_VAL(&tp, GSM0808_IE_CHOSEN_ENCR_ALG)[0] - 1;
427 }
428
429 if (TLVP_PRESENT(&tp, GSM0808_IE_LAYER_3_MESSAGE_CONTENTS)) {
Neels Hofmeyr9baedaf2017-12-18 04:07:01 +0100430 msg->l3h = (uint8_t*)TLVP_VAL(&tp, GSM0808_IE_LAYER_3_MESSAGE_CONTENTS);
Philipp Maierfbf66102017-04-09 12:32:51 +0200431 msg->tail = msg->l3h + TLVP_LEN(&tp, GSM0808_IE_LAYER_3_MESSAGE_CONTENTS);
432 } else {
433 msgb_free(msg);
434 msg = NULL;
435 }
436
Philipp Maier4502f5f2017-09-07 11:39:58 +0200437 /* Hand over cipher mode complete message to the MSC */
Philipp Maierfbf66102017-04-09 12:32:51 +0200438 msc_cipher_mode_compl(conn, msg, alg_id);
Philipp Maier4502f5f2017-09-07 11:39:58 +0200439 msgb_free(msg);
Philipp Maierfbf66102017-04-09 12:32:51 +0200440
441 return 0;
442fail:
443 msgb_free(msg);
444 return -EINVAL;
445}
446
447/* Endpoint to handle BSSMAP cipher mode reject */
448static int bssmap_rx_ciph_rej(const struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
449{
450 struct gsm_network *network = a_conn_info->network;
451 struct gsm_subscriber_connection *conn;
452 struct tlv_parsed tp;
453 uint8_t cause;
454
455 conn = subscr_conn_lookup_a(network, a_conn_info->conn_id);
456 if (!conn)
457 goto fail;
458
Harald Weltefb7ba912018-02-09 01:05:27 +0100459 LOGPCONN(conn, LOGL_NOTICE, "RX BSSMAP CIPHER MODE REJECT\n");
Philipp Maierfbf66102017-04-09 12:32:51 +0200460
461 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, msgb_l3len(msg) - 1, 0, 0);
462 if (!TLVP_PRESENT(&tp, BSS_MAP_MSG_CIPHER_MODE_REJECT)) {
Harald Welte6de46592018-02-09 00:53:17 +0100463 LOGPCONN(conn, LOGL_ERROR, "Cause code is missing -- discarding message!\n");
Philipp Maierfbf66102017-04-09 12:32:51 +0200464 goto fail;
465 }
466
467 cause = TLVP_VAL(&tp, BSS_MAP_MSG_CIPHER_MODE_REJECT)[0];
Harald Welte6de46592018-02-09 00:53:17 +0100468 LOGPCONN(conn, LOGL_NOTICE, "Cipher mode rejection cause: %i\n", cause);
Philipp Maierfbf66102017-04-09 12:32:51 +0200469
470 /* FIXME: Can we do something meaningful here? e.g. report to the
471 * msc code somehow that the cipher mode command has failed. */
472
473 msgb_free(msg);
474 return 0;
475fail:
476 msgb_free(msg);
477 return -EINVAL;
478}
479
480/* Endpoint to handle BSSMAP assignment failure */
481static int bssmap_rx_ass_fail(const struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
482{
483 struct gsm_network *network = a_conn_info->network;
484 struct gsm_subscriber_connection *conn;
485 struct tlv_parsed tp;
486 uint8_t cause;
487 uint8_t *rr_cause_ptr = NULL;
488 uint8_t rr_cause;
489
490 conn = subscr_conn_lookup_a(network, a_conn_info->conn_id);
491 if (!conn)
492 goto fail;
493
Harald Weltefb7ba912018-02-09 01:05:27 +0100494 LOGPCONN(conn, LOGL_NOTICE, "Rx BSSMAP ASSIGNMENT FAILURE message\n");
Philipp Maierfbf66102017-04-09 12:32:51 +0200495
496 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, msgb_l3len(msg) - 1, 0, 0);
497 if (!TLVP_PRESENT(&tp, GSM0808_IE_CAUSE)) {
Harald Welte6de46592018-02-09 00:53:17 +0100498 LOGPCONN(conn, LOGL_ERROR, "Cause code is missing -- discarding message!\n");
Philipp Maierfbf66102017-04-09 12:32:51 +0200499 goto fail;
500 }
501 cause = TLVP_VAL(&tp, GSM0808_IE_CAUSE)[0];
502
503 if (TLVP_PRESENT(&tp, GSM0808_IE_RR_CAUSE)) {
504 rr_cause = TLVP_VAL(&tp, GSM0808_IE_RR_CAUSE)[0];
505 rr_cause_ptr = &rr_cause;
506 }
507
508 /* FIXME: In AoIP, the Assignment failure will carry also an optional
509 * Codec List (BSS Supported) element. It has to be discussed if we
510 * can ignore this element. If not, The msc_assign_fail() function
511 * call has to change. However msc_assign_fail() does nothing in the
512 * end. So probably we can just leave it as it is. Even for AoIP */
513
514 /* Inform the MSC about the assignment failure event */
515 msc_assign_fail(conn, cause, rr_cause_ptr);
516
517 msgb_free(msg);
518 return 0;
519fail:
520 msgb_free(msg);
521 return -EINVAL;
522}
523
524/* Endpoint to handle sapi "n" reject */
525static int bssmap_rx_sapi_n_rej(const struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info,
526 struct msgb *msg)
527{
528 struct gsm_network *network = a_conn_info->network;
529 struct gsm_subscriber_connection *conn;
530 struct tlv_parsed tp;
531 uint8_t dlci;
532
533 conn = subscr_conn_lookup_a(network, a_conn_info->conn_id);
534 if (!conn)
535 goto fail;
536
Harald Welte6de46592018-02-09 00:53:17 +0100537 LOGPCONN(conn, LOGL_NOTICE, "BSC sends sapi \"n\" reject message\n");
Philipp Maierfbf66102017-04-09 12:32:51 +0200538
539 /* Note: The MSC code seems not to care about the cause code, but by
540 * the specification it is mandatory, so we check its presence. See
541 * also 3GPP TS 48.008 3.2.1.34 SAPI "n" REJECT */
542 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, msgb_l3len(msg) - 1, 0, 0);
543 if (!TLVP_PRESENT(&tp, GSM0808_IE_CAUSE)) {
Harald Welte6de46592018-02-09 00:53:17 +0100544 LOGPCONN(conn, LOGL_ERROR, "Cause code is missing -- discarding message!\n");
Philipp Maierfbf66102017-04-09 12:32:51 +0200545 goto fail;
546 }
547
548 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, msgb_l3len(msg) - 1, 0, 0);
549 if (!TLVP_PRESENT(&tp, GSM0808_IE_DLCI)) {
Harald Welte6de46592018-02-09 00:53:17 +0100550 LOGPCONN(conn, LOGL_ERROR, "DLCI is missing -- discarding message!\n");
Philipp Maierfbf66102017-04-09 12:32:51 +0200551 goto fail;
552 }
553 dlci = TLVP_VAL(&tp, GSM0808_IE_DLCI)[0];
554
555 /* Inform the MSC about the sapi "n" reject event */
556 msc_sapi_n_reject(conn, dlci);
557
558 msgb_free(msg);
559 return 0;
560fail:
561 msgb_free(msg);
562 return -EINVAL;
563}
564
565/* Endpoint to handle assignment complete */
566static int bssmap_rx_ass_compl(const struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info,
567 struct msgb *msg)
568{
569 struct gsm_network *network = a_conn_info->network;
570 struct gsm_subscriber_connection *conn;
Neels Hofmeyr6c8afe12017-09-04 01:03:58 +0200571 struct mgcp_client *mgcp;
Philipp Maierfbf66102017-04-09 12:32:51 +0200572 struct tlv_parsed tp;
573 struct sockaddr_storage rtp_addr;
574 struct sockaddr_in *rtp_addr_in;
575 int rc;
576
577 conn = subscr_conn_lookup_a(network, a_conn_info->conn_id);
578 if (!conn)
579 goto fail;
580
Neels Hofmeyr6c8afe12017-09-04 01:03:58 +0200581 mgcp = conn->network->mgw.client;
Philipp Maierfbf66102017-04-09 12:32:51 +0200582 OSMO_ASSERT(mgcp);
583
Harald Welte6de46592018-02-09 00:53:17 +0100584 LOGPCONN(conn, LOGL_INFO, "BSC sends assignment complete message\n");
Philipp Maierfbf66102017-04-09 12:32:51 +0200585
586 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 1, msgb_l3len(msg) - 1, 0, 0);
587
588 if (!TLVP_PRESENT(&tp, GSM0808_IE_AOIP_TRASP_ADDR)) {
Harald Welte6de46592018-02-09 00:53:17 +0100589 LOGPCONN(conn, LOGL_ERROR, "AoIP transport identifier missing -- discarding message!\n");
Philipp Maierfbf66102017-04-09 12:32:51 +0200590 goto fail;
591 }
592
593 /* Decode AoIP transport address element */
594 rc = gsm0808_dec_aoip_trasp_addr(&rtp_addr, TLVP_VAL(&tp, GSM0808_IE_AOIP_TRASP_ADDR),
595 TLVP_LEN(&tp, GSM0808_IE_AOIP_TRASP_ADDR));
596 if (rc < 0) {
Harald Welte6de46592018-02-09 00:53:17 +0100597 LOGPCONN(conn, LOGL_ERROR, "Unable to decode aoip transport address.\n");
Philipp Maierfbf66102017-04-09 12:32:51 +0200598 goto fail;
599 }
600
601 /* use address / port supplied with the AoIP
602 * transport address element */
603 if (rtp_addr.ss_family == AF_INET) {
604 rtp_addr_in = (struct sockaddr_in *)&rtp_addr;
Philipp Maier621ba032017-11-07 17:19:25 +0100605 msc_mgcp_ass_complete(conn, osmo_ntohs(rtp_addr_in->sin_port), inet_ntoa(rtp_addr_in->sin_addr));
Philipp Maierfbf66102017-04-09 12:32:51 +0200606 } else {
Harald Welte6de46592018-02-09 00:53:17 +0100607 LOGPCONN(conn, LOGL_ERROR, "Unsopported addressing scheme. (supports only IPV4)\n");
Philipp Maierfbf66102017-04-09 12:32:51 +0200608 goto fail;
609 }
610
611 /* FIXME: Seems to be related to authentication or,
612 encryption. Is this really in the right place? */
613 msc_rx_sec_mode_compl(conn);
614
615 msgb_free(msg);
616 return 0;
617fail:
618 msgb_free(msg);
619 return -EINVAL;
620}
621
622/* Handle incoming connection oriented BSSMAP messages */
623static int rx_bssmap(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
624{
625 if (msgb_l3len(msg) < 1) {
626 LOGP(DMSC, LOGL_NOTICE, "Error: No data received -- discarding message!\n");
627 msgb_free(msg);
628 return -1;
629 }
630
Harald Weltefb7ba912018-02-09 01:05:27 +0100631 LOGP(DMSC, LOGL_DEBUG, "Rx BSSMAP DT1 %s\n", gsm0808_bssmap_name(msg->l3h[0]));
Philipp Maierfbf66102017-04-09 12:32:51 +0200632
633 switch (msg->l3h[0]) {
634 case BSS_MAP_MSG_CLEAR_RQST:
635 return bssmap_rx_clear_rqst(scu, a_conn_info, msg);
636 break;
637 case BSS_MAP_MSG_CLEAR_COMPLETE:
638 return bssmap_rx_clear_complete(scu, a_conn_info, msg);
639 break;
640 case BSS_MAP_MSG_COMPLETE_LAYER_3:
641 return bssmap_rx_l3_compl(scu, a_conn_info, msg);
642 break;
643 case BSS_MAP_MSG_CLASSMARK_UPDATE:
644 return bssmap_rx_classmark_upd(scu, a_conn_info, msg);
645 break;
646 case BSS_MAP_MSG_CIPHER_MODE_COMPLETE:
647 return bssmap_rx_ciph_compl(scu, a_conn_info, msg);
648 break;
649 case BSS_MAP_MSG_CIPHER_MODE_REJECT:
650 return bssmap_rx_ciph_rej(scu, a_conn_info, msg);
651 break;
652 case BSS_MAP_MSG_ASSIGMENT_FAILURE:
653 return bssmap_rx_ass_fail(scu, a_conn_info, msg);
654 break;
655 case BSS_MAP_MSG_SAPI_N_REJECT:
656 return bssmap_rx_sapi_n_rej(scu, a_conn_info, msg);
657 break;
658 case BSS_MAP_MSG_ASSIGMENT_COMPLETE:
659 return bssmap_rx_ass_compl(scu, a_conn_info, msg);
660 break;
661 default:
662 LOGP(DMSC, LOGL_ERROR, "Unimplemented msg type: %s\n", gsm0808_bssmap_name(msg->l3h[0]));
663 msgb_free(msg);
664 return -EINVAL;
665 }
666
667 return -EINVAL;
668}
669
670/* Endpoint to handle regular BSSAP DTAP messages */
671static int rx_dtap(const struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
672{
673 struct gsm_network *network = a_conn_info->network;
674 struct gsm_subscriber_connection *conn;
675
676 conn = subscr_conn_lookup_a(network, a_conn_info->conn_id);
677 if (!conn) {
678 msgb_free(msg);
679 return -EINVAL;
680 }
681
Harald Weltefb7ba912018-02-09 01:05:27 +0100682 LOGPCONN(conn, LOGL_DEBUG, "Rx DTAP %s\n", msgb_hexdump_l2(msg));
Philipp Maierfbf66102017-04-09 12:32:51 +0200683
684 /* msc_dtap expects the dtap payload in l3h */
685 msg->l3h = msg->l2h + 3;
686
Philipp Maier4502f5f2017-09-07 11:39:58 +0200687 /* Forward dtap payload into the msc */
Philipp Maierfbf66102017-04-09 12:32:51 +0200688 msc_dtap(conn, conn->a.conn_id, msg);
Philipp Maier4502f5f2017-09-07 11:39:58 +0200689 msgb_free(msg);
Philipp Maierfbf66102017-04-09 12:32:51 +0200690
691 return 0;
692}
693
694/* Handle incoming connection oriented messages */
Neels Hofmeyrc1d69252017-12-18 04:06:04 +0100695int a_sccp_rx_dt(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg)
Philipp Maierfbf66102017-04-09 12:32:51 +0200696{
697 OSMO_ASSERT(scu);
698 OSMO_ASSERT(a_conn_info);
699 OSMO_ASSERT(msg);
700
Philipp Maierfbf66102017-04-09 12:32:51 +0200701 if (msgb_l2len(msg) < sizeof(struct bssmap_header)) {
702 LOGP(DMSC, LOGL_NOTICE, "The header is too short -- discarding message!\n");
703 msgb_free(msg);
Philipp Maier4502f5f2017-09-07 11:39:58 +0200704 return -EINVAL;
Philipp Maierfbf66102017-04-09 12:32:51 +0200705 }
706
707 switch (msg->l2h[0]) {
708 case BSSAP_MSG_BSS_MANAGEMENT:
709 msg->l3h = &msg->l2h[sizeof(struct bssmap_header)];
710 return rx_bssmap(scu, a_conn_info, msg);
711 break;
712 case BSSAP_MSG_DTAP:
713 return rx_dtap(scu, a_conn_info, msg);
714 break;
715 default:
716 LOGP(DMSC, LOGL_ERROR, "Unimplemented BSSAP msg type: %s\n", gsm0808_bssap_name(msg->l2h[0]));
717 msgb_free(msg);
718 return -EINVAL;
719 }
720
721 return -EINVAL;
722}