blob: 0f6ca334f4699ff2c0e6d8b79e1234b172918342 [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/logging.h>
23#include <osmocom/sigtran/osmo_ss7.h>
24#include <osmocom/sigtran/sccp_sap.h>
25#include <osmocom/sccp/sccp_types.h>
26#include <osmocom/core/linuxlist.h>
27#include <osmocom/gsm/gsm0808.h>
28#include <osmocom/core/msgb.h>
29#include <openbsc/bsc_msc_data.h>
30#include <openbsc/debug.h>
31#include <openbsc/osmo_bsc.h>
32#include <openbsc/osmo_bsc_grace.h>
33#include <openbsc/osmo_bsc_sigtran.h>
34#include <openbsc/a_reset.h>
35#include <openbsc/gsm_04_80.h>
36
37/* A pointer to a list with all involved MSCs
38 * (a copy of the pointer location submitted with osmo_bsc_sigtran_init() */
39static struct llist_head *msc_list;
40
41#define RESET_INTERVAL 1 /* sek */
42#define SCCP_MSG_MAXSIZE 1024
43#define CS7_POINTCODE_DEFAULT_OFFSET 2
44
45/* Internal list with connections we currently maintain. This
46 * list is of type struct osmo_bsc_sccp_con */
47static LLIST_HEAD(active_connections);
48
49/* The SCCP stack will not assign connection IDs to us automatically, we
50 * will do this ourselves using a counter variable, that counts one up
51 * for every new connection */
52static uint32_t conn_id_counter;
53
54/* Helper function to Check if the given connection id is already assigned */
55static struct osmo_bsc_sccp_con *get_bsc_conn_by_conn_id(int conn_id)
56{
57 conn_id &= 0xFFFFFF;
58 struct osmo_bsc_sccp_con *bsc_con;
59
60 llist_for_each_entry(bsc_con, &active_connections, entry) {
61 if (bsc_con->conn_id == conn_id)
62 return bsc_con;
63 }
64
65 return NULL;
66}
67
68/* Pick a free connection id */
69static int pick_free_conn_id(const struct bsc_msc_data *msc)
70{
71 int conn_id = conn_id_counter;
72 int i;
73
74 for (i = 0; i < 0xFFFFFF; i++) {
75 conn_id++;
76 conn_id &= 0xFFFFFF;
77 if (get_bsc_conn_by_conn_id(conn_id) == false) {
78 conn_id_counter = conn_id;
79 return conn_id;
80 }
81 }
82
83 return -1;
84}
85
86/* Send reset to MSC */
87static void osmo_bsc_sigtran_tx_reset(const struct bsc_msc_data *msc)
88{
89 struct osmo_ss7_instance *ss7;
90 struct msgb *msg;
91
92 ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
93 OSMO_ASSERT(ss7);
94 LOGP(DMSC, LOGL_NOTICE, "Sending RESET to MSC: %s\n", osmo_sccp_addr_name(ss7, &msc->a.msc_addr));
95 msg = gsm0808_create_reset();
96 osmo_sccp_tx_unitdata_msg(msc->a.sccp_user, &msc->a.bsc_addr,
97 &msc->a.msc_addr, msg);
98}
99
100/* Send reset-ack to MSC */
101void osmo_bsc_sigtran_tx_reset_ack(const struct bsc_msc_data *msc)
102{
103 struct osmo_ss7_instance *ss7;
104 struct msgb *msg;
105 OSMO_ASSERT(msc);
106
107 ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
108 OSMO_ASSERT(ss7);
109 LOGP(DMSC, LOGL_NOTICE, "Sending RESET ACK to MSC: %s\n", osmo_sccp_addr_name(ss7, &msc->a.msc_addr));
110 msg = gsm0808_create_reset_ack();
111 osmo_sccp_tx_unitdata_msg(msc->a.sccp_user, &msc->a.bsc_addr,
112 &msc->a.msc_addr, msg);
113}
114
115/* Find an MSC by its sigtran point code */
116static struct bsc_msc_data *get_msc_by_addr(const struct osmo_sccp_addr *msc_addr)
117{
118 struct osmo_ss7_instance *ss7;
119 struct bsc_msc_data *msc;
120 llist_for_each_entry(msc, msc_list, entry) {
121 if (memcmp(msc_addr, &msc->a.msc_addr, sizeof(*msc_addr)) == 0)
122 return msc;
123 }
124
125 ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
126 OSMO_ASSERT(ss7);
127 LOGP(DMSC, LOGL_ERROR, "Unable to find MSC data under address: %s\n", osmo_sccp_addr_name(ss7, msc_addr));
128 return NULL;
129}
130
131/* Send data to MSC, use the connection id which MSC it is */
132static int handle_data_from_msc(int conn_id, struct msgb *msg)
133{
134 struct osmo_bsc_sccp_con *bsc_con = get_bsc_conn_by_conn_id(conn_id);
135 int rc = -EINVAL;
136
137 if (bsc_con) {
138 msg->l3h = msgb_l2(msg);
139 rc = bsc_handle_dt(bsc_con, msg, msgb_l2len(msg));
140 } else
141 LOGP(DMSC, LOGL_NOTICE, "incoming data from unknown connection id: %i\n", conn_id);
142
143 return rc;
144}
145
146/* Sent unitdata to MSC, use the point code to determine which MSC it is */
147static int handle_unitdata_from_msc(const struct osmo_sccp_addr *msc_addr, struct msgb *msg,
148 const struct osmo_sccp_user *scu)
149{
150 struct osmo_ss7_instance *ss7;
151 struct bsc_msc_data *msc = get_msc_by_addr(msc_addr);
152 int rc = -EINVAL;
153
154 if (msc) {
155 msg->l3h = msgb_l2(msg);
156 rc = bsc_handle_udt(msc, msg, msgb_l2len(msg));
157 } else {
158 ss7 = osmo_sccp_get_ss7(osmo_sccp_get_sccp(scu));
159 OSMO_ASSERT(ss7);
160 LOGP(DMSC, LOGL_NOTICE, "incoming unitdata data from unknown remote address: %s\n",
161 osmo_sccp_addr_name(ss7, msc_addr));
162 }
163 return rc;
164}
165
166/* Callback function, called by the SSCP stack when data arrives */
167static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
168{
169 struct osmo_scu_prim *scu_prim = (struct osmo_scu_prim *)oph;
170 struct osmo_sccp_user *scu = _scu;
171 struct osmo_bsc_sccp_con *bsc_con;
172 int rc = 0;
173
174 switch (OSMO_PRIM_HDR(&scu_prim->oph)) {
175 case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION):
176 /* Handle inbound UNITDATA */
177 DEBUGP(DMSC, "N-UNITDATA.ind(%s)\n", osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
178 rc = handle_unitdata_from_msc(&scu_prim->u.unitdata.calling_addr, oph->msg, scu);
179 break;
180
181 case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION):
182 /* Handle (Reject) inbound connections */
183 DEBUGP(DMSC, "N-CONNECT.ind(X->%u)\n", scu_prim->u.connect.conn_id);
184 LOGP(DMSC, LOGL_DEBUG, "Rejecting inbound SCCP connection...\n");
185 rc = osmo_sccp_tx_disconn(scu, scu_prim->u.connect.conn_id, &scu_prim->u.connect.called_addr, 0);
186 break;
187
188 case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM):
189 /* Handle outbound connection confirmation */
190 if (msgb_l2len(oph->msg) > 0) {
191 DEBUGP(DMSC, "N-CONNECT.cnf(%u, %s)\n", scu_prim->u.connect.conn_id,
192 osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
193 rc = handle_data_from_msc(scu_prim->u.connect.conn_id, oph->msg);
194 } else
195 DEBUGP(DRANAP, "N-CONNECT.cnf(%u)\n", scu_prim->u.connect.conn_id);
196 break;
197
198 case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION):
199 /* Handle incoming connection oriented data */
200 DEBUGP(DMSC, "N-DATA.ind(%u, %s)\n", scu_prim->u.data.conn_id,
201 osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
202
203 /* Incoming data is a sign of a vital connection */
204 bsc_con = get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id);
205 if (bsc_con)
206 a_reset_conn_success(bsc_con->msc->a.reset);
207
208 rc = handle_data_from_msc(scu_prim->u.data.conn_id, oph->msg);
209 break;
210
211 case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION):
212 /* indication of disconnect */
213 if (msgb_l2len(oph->msg) > 0) {
214 DEBUGP(DMSC, "N-DISCONNECT.ind(%u, %s, cause=%i)\n", scu_prim->u.disconnect.conn_id,
215 osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)), scu_prim->u.disconnect.cause);
216 handle_data_from_msc(scu_prim->u.disconnect.conn_id, oph->msg);
217 } else
218 DEBUGP(DRANAP, "N-DISCONNECT.ind(%u, cause=%i)\n", scu_prim->u.disconnect.conn_id,
219 scu_prim->u.disconnect.cause);
220
221 bsc_con = get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id);
222 if (bsc_con) {
223 /* We might have a connectivity problem. Maybe we need to go
224 * through the reset procedure again? */
225 if (scu_prim->u.disconnect.cause == 0)
226 a_reset_conn_fail(bsc_con->msc->a.reset);
227
228 rc = osmo_bsc_sigtran_del_conn(bsc_con);
229 }
230 break;
231
232 default:
233 LOGP(DMSC, LOGL_ERROR, "Unhandled SIGTRAN primitive: %u:%u\n", oph->primitive, oph->operation);
234 break;
235 }
236
237 msgb_free(oph->msg);
238 return rc;
239}
240
241/* Allocate resources to make a new connection oriented sigtran connection
242 * (not the connection ittself!) */
243enum bsc_con osmo_bsc_sigtran_new_conn(struct gsm_subscriber_connection *conn, struct bsc_msc_data *msc)
244{
245 struct osmo_ss7_instance *ss7;
246 struct osmo_bsc_sccp_con *bsc_con;
247 int conn_id;
248
249 OSMO_ASSERT(conn);
250 OSMO_ASSERT(msc);
251
252 ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
253 OSMO_ASSERT(ss7);
254 LOGP(DMSC, LOGL_NOTICE, "Initializing resources for new SIGTRAN connection to MSC: %s...\n",
255 osmo_sccp_addr_name(ss7, &msc->a.msc_addr));
256
257 if (a_reset_conn_ready(msc->a.reset) == false) {
258 LOGP(DMSC, LOGL_ERROR, "MSC is not connected. Dropping.\n");
259 return BSC_CON_REJECT_NO_LINK;
260 }
261
262 if (!bsc_grace_allow_new_connection(conn->bts->network, conn->bts)) {
263 LOGP(DMSC, LOGL_NOTICE, "BSC in grace period. No new connections.\n");
264 return BSC_CON_REJECT_RF_GRACE;
265 }
266
267 bsc_con = talloc_zero(conn->bts, struct osmo_bsc_sccp_con);
268 if (!bsc_con) {
269 LOGP(DMSC, LOGL_ERROR, "Failed to allocate new SIGTRAN connection.\n");
270 return BSC_CON_NO_MEM;
271 }
272
273 bsc_con->msc = msc;
274 bsc_con->conn = conn;
275 llist_add_tail(&bsc_con->entry, &active_connections);
276 conn->sccp_con = bsc_con;
277
278 /* Pick a free connection id */
279 conn_id = pick_free_conn_id(msc);
280 if (conn_id < 0)
281 return BSC_CON_REJECT_NO_LINK;
282 bsc_con->conn_id = conn_id;
283
284 LOGP(DMSC, LOGL_NOTICE, "Allocated new connection id: %i\n", conn_id);
285
286 return BSC_CON_SUCCESS;
287}
288
289/* Open a new connection oriented sigtran connection */
290int osmo_bsc_sigtran_open_conn(const struct osmo_bsc_sccp_con *conn, struct msgb *msg)
291{
292 struct osmo_ss7_instance *ss7;
293 struct bsc_msc_data *msc;
294 int conn_id;
295 int rc;
296
297 OSMO_ASSERT(conn);
298 OSMO_ASSERT(msg);
299 OSMO_ASSERT(conn->msc);
300
301 msc = conn->msc;
302
303 if (a_reset_conn_ready(msc->a.reset) == false) {
304 LOGP(DMSC, LOGL_ERROR, "MSC is not connected. Dropping.\n");
305 return -EINVAL;
306 }
307
308 conn_id = conn->conn_id;
309 ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
310 OSMO_ASSERT(ss7);
311 LOGP(DMSC, LOGL_NOTICE, "Opening new SIGTRAN connection (id=%i) to MSC: %s\n", conn_id,
312 osmo_sccp_addr_name(ss7, &msc->a.msc_addr));
313
314 rc = osmo_sccp_tx_conn_req_msg(msc->a.sccp_user, conn_id, &msc->a.bsc_addr,
315 &msc->a.msc_addr, msg);
316
317 return rc;
318}
319
320/* Send data to MSC */
321int osmo_bsc_sigtran_send(const struct osmo_bsc_sccp_con *conn, struct msgb *msg)
322{
323 struct osmo_ss7_instance *ss7;
324 int conn_id;
325 int rc;
326 struct bsc_msc_data *msc;
327
328 OSMO_ASSERT(conn);
329 OSMO_ASSERT(msg);
330 OSMO_ASSERT(conn->msc);
331
332 msc = conn->msc;
333
334 if (a_reset_conn_ready(msc->a.reset) == false) {
335 LOGP(DMSC, LOGL_ERROR, "MSC is not connected. Dropping.\n");
336 return -EINVAL;
337 }
338
339 conn_id = conn->conn_id;
340
341 ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
342 OSMO_ASSERT(ss7);
343 LOGP(DMSC, LOGL_DEBUG, "Sending connection (id=%i) oriented data to MSC: %si\n",
344 conn_id, osmo_sccp_addr_name(ss7, &msc->a.msc_addr));
345
346 rc = osmo_sccp_tx_data_msg(msc->a.sccp_user, conn_id, msg);
347
348 return rc;
349}
350
351/* Delete a connection from the list with open connections
352 * (called by osmo_bsc_api.c on failing open connections and
353 * locally, when a connection is closed by the MSC */
354int osmo_bsc_sigtran_del_conn(struct osmo_bsc_sccp_con *conn)
355{
356 if (!conn)
357 return 0;
358
359 if (conn->conn) {
360 LOGP(DMSC, LOGL_ERROR,
361 "sccp connection (id=%i) not cleared (gsm subscriber connection still active) -- forcefully clearing it now!\n",
362 conn->conn_id);
363 bsc_subscr_con_free(conn->conn);
364 conn->conn = NULL;
365
366 /* This bahaviour might be caused by a bad connection. Maybe we
367 * will have to go through the reset procedure again */
368 a_reset_conn_fail(conn->msc->a.reset);
369 }
370
371 llist_del(&conn->entry);
372 talloc_free(conn);
373
374 return 0;
375}
376
377/* Send an USSD notification in case we loose the connection to the MSC */
378static void bsc_notify_msc_lost(const struct osmo_bsc_sccp_con *conn)
379{
380 struct gsm_subscriber_connection *subscr_conn;
381
382 /* Check if sccp conn is still present */
383 if (!conn)
384 return;
385 subscr_conn = conn->conn;
386
387 /* send USSD notification if string configured and conn->data is set */
388 if (!subscr_conn)
389 return;
390
391 /* check for config string */
392 if (!conn->msc->ussd_msc_lost_txt)
393 return;
394 if (conn->msc->ussd_msc_lost_txt[0] == '\0')
395 return;
396
397 /* send USSD notification */
398 bsc_send_ussd_notify(subscr_conn, 1, subscr_conn->sccp_con->msc->ussd_msc_lost_txt);
399 bsc_send_ussd_release_complete(subscr_conn);
400}
401
402/* Close all open sigtran connections and channels */
403void osmo_bsc_sigtran_reset(const struct bsc_msc_data *msc)
404{
405 struct osmo_bsc_sccp_con *conn;
406 struct osmo_bsc_sccp_con *conn_temp;
407 OSMO_ASSERT(msc);
408
409 /* Close all open connections */
410 llist_for_each_entry_safe(conn, conn_temp, &active_connections, entry) {
411
412 /* We only may close connections which actually belong to this
413 * MSC. All other open connections are left untouched */
414 if (conn->msc == msc) {
415 /* Notify active connection users via USSD that the MSC is down */
416 bsc_notify_msc_lost(conn);
417
418 /* Take down all occopied RF channels */
419 if (conn->conn)
420 gsm0808_clear(conn->conn);
421
422 /* Disconnect all Sigtran connections */
423 osmo_sccp_tx_disconn(msc->a.sccp_user, conn->conn_id, &msc->a.bsc_addr, 0);
424
425 /* Delete subscriber connection */
426 osmo_bsc_sigtran_del_conn(conn);
427 }
428 }
429}
430
431/* Callback function: Close all open connections */
432static void osmo_bsc_sigtran_reset_cb(const void *priv)
433{
434 struct bsc_msc_data *msc = (struct bsc_msc_data*) priv;
435
436 /* Shut down all ongoing traffic */
437 osmo_bsc_sigtran_reset(msc);
438
439 /* Send reset to MSC */
440 osmo_bsc_sigtran_tx_reset(msc);
441}
442
443/* Default point-code to be used as local address (BSC) */
444#define BSC_DEFAULT_PC "0.23.3"
445
446/* Default point-code to be used as remote address (MSC) */
447#define MSC_DEFAULT_PC "0.23.1"
448
449/* Initalize osmo sigtran backhaul */
450int osmo_bsc_sigtran_init(struct llist_head *mscs)
451{
452 bool free_attempt_used = false;
453 bool fail_on_next_invalid_cfg = false;
454
455 struct bsc_msc_data *msc;
456 char msc_name[32];
457 uint32_t default_pc;
458
459 OSMO_ASSERT(mscs);
460 msc_list = mscs;
461
462 llist_for_each_entry(msc, msc_list, entry) {
463 snprintf(msc_name, sizeof(msc_name), "msc-%u", msc->nr);
464 LOGP(DMSC, LOGL_NOTICE, "Initializing SCCP connection to MSC %s\n", msc_name);
465
466 /* Check if the VTY could determine a valid CS7 instance,
467 * use safe default in case none is set */
468 if (msc->a.cs7_instance_valid == false) {
469 msc->a.cs7_instance = 0;
470 if (fail_on_next_invalid_cfg)
471 goto fail_auto_cofiguration;
472 free_attempt_used = true;
473 }
474 LOGP(DMSC, LOGL_NOTICE, "CS7 Instance identifier, A-Interface: %u\n", msc->a.cs7_instance);
475
476 /* Pre-Check if there is an ss7 instance present */
477 if (osmo_ss7_instance_find(msc->a.cs7_instance) == NULL) {
478 if (fail_on_next_invalid_cfg)
479 goto fail_auto_cofiguration;
480 free_attempt_used = true;
481 }
482
483 /* SS7 Protocol stack */
484 default_pc = osmo_ss7_pointcode_parse(NULL, BSC_DEFAULT_PC);
485 msc->a.sccp =
486 osmo_sccp_simple_client_on_ss7_id(msc, msc->a.cs7_instance, msc_name, default_pc,
487 OSMO_SS7_ASP_PROT_M3UA, 0, NULL, 0, NULL);
488 if (!msc->a.sccp)
489 return -EINVAL;
490
491 /* Check if the sccp-address fullfills minimum requirements (SSN+PC is present,
492 * automatically recover addresses if the addresses are not set up properly) */
493 if (!osmo_sccp_check_addr(&msc->a.bsc_addr, OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC)) {
494 if (fail_on_next_invalid_cfg)
495 goto fail_auto_cofiguration;
496 free_attempt_used = true;
497
498 LOGP(DMSC, LOGL_NOTICE,
499 "A-interface: invalid or missing local (BSC) SCCP address (a.bsc_addr=%s)\n",
500 osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.bsc_addr));
501 osmo_sccp_local_addr_by_instance(&msc->a.bsc_addr, msc->a.sccp, SCCP_SSN_BSSAP);
502 LOGP(DMSC, LOGL_NOTICE,
503 "A-interface: using automatically generated local (BSC) SCCP address (a.bsc_addr=%s)\n",
504 osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.bsc_addr));
505 } else {
506 LOGP(DMSC, LOGL_NOTICE,
507 "A-interface: using local (BSC) automatically SCCP address (a.msc_addr=%s)\n",
508 osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.bsc_addr));
509 }
510
511 if (!osmo_sccp_check_addr(&msc->a.msc_addr, OSMO_SCCP_ADDR_T_SSN | OSMO_SCCP_ADDR_T_PC)) {
512 if (fail_on_next_invalid_cfg)
513 goto fail_auto_cofiguration;
514 free_attempt_used = true;
515
516 LOGP(DMSC, LOGL_NOTICE,
517 "A-interface: invalid or missing remote (MSC) SCCP address for the MSC (a.msc_addr=%s)\n",
518 osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.msc_addr));
519 osmo_sccp_local_addr_by_instance(&msc->a.msc_addr, msc->a.sccp, SCCP_SSN_BSSAP);
520 msc->a.msc_addr.pc = osmo_ss7_pointcode_parse(NULL, MSC_DEFAULT_PC);
521 LOGP(DMSC, LOGL_NOTICE,
522 "A-interface: using automatically generated remote (MSC) SCCP address (a.msc_addr=%s)\n",
523 osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.msc_addr));
524 free_attempt_used = true;
525 } else {
526 LOGP(DMSC, LOGL_NOTICE,
527 "A-interface: using remote (MSC) automatically SCCP address (a.msc_addr=%s)\n",
528 osmo_sccp_addr_name(osmo_ss7_instance_find(msc->a.cs7_instance), &msc->a.msc_addr));
529 }
530
531 /* Bind SCCP user */
532 msc->a.sccp_user = osmo_sccp_user_bind(msc->a.sccp, msc_name, sccp_sap_up, msc->a.bsc_addr.ssn);
533 if (!msc->a.sccp_user)
534 return -EINVAL;
535
536 /* Start MSC-Reset procedure */
537 msc->a.reset = a_reset_alloc(msc, msc_name, osmo_bsc_sigtran_reset_cb, msc);
538 if (!msc->a.reset)
539 return -EINVAL;
540
541 /* If we have detected that the SS7 configuration of the MSC we have just initalized
542 * was incomplete or completely missing, we can not tolerate another incomplete
543 * configuration. The reson for this is that we do only specify exactly one default
544 * pointcode pair. We also specify localhost as default IP-Address. If we have wanted
545 * to support multiple MSCs with automatic configuration we would be forced to invent
546 * a complex ruleset how to allocate the pointcodes and respective IP-Addresses.
547 * Furthermore, the situation where a single BSC is connected to multiple MSCs
548 * is a very rare situation anyway. In this case we expect the user to experienced
549 * enough to create a valid SS7/CS7 VTY configuration that does not lack any
550 * components */
551 if (free_attempt_used)
552 fail_on_next_invalid_cfg = true;
553 }
554
555 return 0;
556
557fail_auto_cofiguration:
558 LOGP(DMSC, LOGL_ERROR,
559 "A-interface: More than one invalid/inclomplete configuration detected, unable to revover - check config file!\n");
560 return -EINVAL;
561}