Structural reform: Get rid of osmo_bsc_sccp_con

There was always a 1:1 correspondence between gsm_subscriber_connection
and osmo_bsc_sccp_con, so there's really no point in having two separate
dynamically allocated data structures with pointers back and forth and
another linked list around.

Let's merge osmo_bsc_sccp_con into gsm_subscriber_connection for
simplicity.

The resulting code might not be elegant in places, but I've tried to
do only the most simple changes in this patch, while further
simplifications can be done in later subsequent patches.

As a side-effect, this patch also fixes lchan clearing if the MSC
(or the local SCCP provider) hard-disconnects the SCCP connection.

Change-Id: Idd2b733477ee90d24dec369755a00f1c39c93f39
This commit is contained in:
Harald Welte 2018-01-28 02:45:46 +01:00
parent c1db52f132
commit 519c7e1d42
14 changed files with 222 additions and 266 deletions

View File

@ -25,6 +25,7 @@
#include <osmocom/gsm/protocol/gsm_12_21.h> #include <osmocom/gsm/protocol/gsm_12_21.h>
#include <osmocom/abis/e1_input.h> #include <osmocom/abis/e1_input.h>
#include <osmocom/bsc/meas_rep.h> #include <osmocom/bsc/meas_rep.h>
#include <osmocom/bsc/bsc_msg_filter.h>
struct mgcp_client_conf; struct mgcp_client_conf;
struct mgcp_client; struct mgcp_client;
@ -80,6 +81,12 @@ struct gsm_classmark {
uint8_t classmark3[14]; /* if cm3 gets extended by spec, it will be truncated */ uint8_t classmark3[14]; /* if cm3 gets extended by spec, it will be truncated */
}; };
enum subscr_sccp_state {
SUBSCR_SCCP_ST_NONE,
SUBSCR_SCCP_ST_WAIT_CONN_CONF,
SUBSCR_SCCP_ST_CONNECTED
};
/* active radio connection of a mobile subscriber */ /* active radio connection of a mobile subscriber */
struct gsm_subscriber_connection { struct gsm_subscriber_connection {
/* global linked list of subscriber_connections */ /* global linked list of subscriber_connections */
@ -88,9 +95,6 @@ struct gsm_subscriber_connection {
/* libbsc subscriber information (if available) */ /* libbsc subscriber information (if available) */
struct bsc_subscr *bsub; struct bsc_subscr *bsub;
/* SCCP connection associatd with this subscriber_connection */
struct osmo_bsc_sccp_con *sccp_con;
/* back pointers */ /* back pointers */
struct gsm_network *network; struct gsm_network *network;
@ -121,6 +125,47 @@ struct gsm_subscriber_connection {
* capabilities, which the MSC is required to translate into the codec list. */ * capabilities, which the MSC is required to translate into the codec list. */
struct gsm0808_speech_codec_list codec_list; struct gsm0808_speech_codec_list codec_list;
bool codec_list_present; bool codec_list_present;
/* flag to prevent multiple simultaneous ciphering commands */
int ciphering_handled;
/* state related to welcome USSD */
uint8_t new_subscriber;
/* state related to osmo_bsc_filter.c */
struct bsc_filter_state filter_state;
/* SCCP connection associatd with this subscriber_connection */
struct {
/* for advanced ping/pong */
int send_ping;
/* SCCP connection realted */
struct bsc_msc_data *msc;
/* Sigtran connection ID */
int conn_id;
enum subscr_sccp_state state;
} sccp;
/* for audio handling */
struct {
uint16_t cic;
uint32_t rtp_ip;
int rtp_port;
/* RTP address of the remote end (assigned by MSC through assignment request) */
struct sockaddr_storage aoip_rtp_addr_remote;
/* Local RTP address (reported back to the MSC by us with the
* assignment complete message) */
struct sockaddr_storage aoip_rtp_addr_local;
/* storage to keep states of the MGCP connection handler, the
* handler is created when an assignment request is received
* and is terminated when the assignment complete message is
* sent */
struct mgcp_ctx *mgcp_ctx;
} user_plane;
}; };

View File

@ -16,59 +16,14 @@ enum bsc_con {
}; };
struct bsc_msc_data; struct bsc_msc_data;
struct bsc_msc_connection;
struct osmo_bsc_sccp_con {
/* list_head anchoring us to gsm_network.subscr_conns */
struct llist_head entry;
/* flag to prevent multiple simultaneous ciphering commands */
int ciphering_handled;
/* for audio handling */
struct {
uint16_t cic;
uint32_t rtp_ip;
int rtp_port;
/* RTP address of the remote end (assigned by MSC through assignment request) */
struct sockaddr_storage aoip_rtp_addr_remote;
/* Local RTP address (reported back to the MSC by us with the
* assignment complete message) */
struct sockaddr_storage aoip_rtp_addr_local;
/* storage to keep states of the MGCP connection handler, the
* handler is created when an assignment request is received
* and is terminated when the assignment complete message is
* sent */
struct mgcp_ctx *mgcp_ctx;
} user_plane;
/* for advanced ping/pong */
int send_ping;
/* SCCP connection realted */
struct bsc_msc_data *msc;
/* back-pointer to subscriber connection */
struct gsm_subscriber_connection *conn;
/* state related to welcome USSD */
uint8_t new_subscriber;
/* state related to osmo_bsc_filter.c */
struct bsc_filter_state filter_state;
/* Sigtran connection ID */
int conn_id;
};
struct bsc_api *osmo_bsc_api(); struct bsc_api *osmo_bsc_api();
int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg); int bsc_queue_for_msc(struct gsm_subscriber_connection *conn, struct msgb *msg);
int bsc_open_connection(struct osmo_bsc_sccp_con *sccp, struct msgb *msg); int bsc_open_connection(struct gsm_subscriber_connection *sccp, struct msgb *msg);
enum bsc_con bsc_create_new_connection(struct gsm_subscriber_connection *conn, enum bsc_con bsc_create_new_connection(struct gsm_subscriber_connection *conn,
struct bsc_msc_data *msc, int send_ping); struct bsc_msc_data *msc, int send_ping);
int bsc_delete_connection(struct osmo_bsc_sccp_con *sccp); int bsc_delete_connection(struct gsm_subscriber_connection *sccp);
struct bsc_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn, struct msgb *); struct bsc_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn, struct msgb *);
int bsc_scan_bts_msg(struct gsm_subscriber_connection *conn, struct msgb *msg); int bsc_scan_bts_msg(struct gsm_subscriber_connection *conn, struct msgb *msg);
@ -76,7 +31,7 @@ int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg);
int bsc_send_welcome_ussd(struct gsm_subscriber_connection *conn); int bsc_send_welcome_ussd(struct gsm_subscriber_connection *conn);
int bsc_handle_udt(struct bsc_msc_data *msc, struct msgb *msg, unsigned int length); int bsc_handle_udt(struct bsc_msc_data *msc, struct msgb *msg, unsigned int length);
int bsc_handle_dt(struct osmo_bsc_sccp_con *conn, struct msgb *msg, unsigned int len); int bsc_handle_dt(struct gsm_subscriber_connection *conn, struct msgb *msg, unsigned int len);
int bsc_ctrl_cmds_install(); int bsc_ctrl_cmds_install();

View File

@ -43,7 +43,7 @@ struct mgcp_ctx {
/* Copy of the pointer and the data with context information /* Copy of the pointer and the data with context information
* needed to process the AoIP and MGCP requests (system data) */ * needed to process the AoIP and MGCP requests (system data) */
struct mgcp_client *mgcp; struct mgcp_client *mgcp;
struct osmo_bsc_sccp_con *conn; struct gsm_subscriber_connection *conn;
enum gsm48_chan_mode chan_mode; enum gsm48_chan_mode chan_mode;
bool full_rate; bool full_rate;
struct gsm_lchan *lchan; struct gsm_lchan *lchan;
@ -54,7 +54,8 @@ struct mgcp_ctx {
void mgcp_init(struct gsm_network *net); void mgcp_init(struct gsm_network *net);
struct mgcp_ctx *mgcp_assignm_req(void *ctx, struct mgcp_client *mgcp, struct osmo_bsc_sccp_con *conn, struct mgcp_ctx *mgcp_assignm_req(void *ctx, struct mgcp_client *mgcp,
struct gsm_subscriber_connection *conn,
enum gsm48_chan_mode chan_mode, bool full_rate); enum gsm48_chan_mode chan_mode, bool full_rate);
void mgcp_clear_complete(struct mgcp_ctx *mgcp_ctx, struct msgb *resp); void mgcp_clear_complete(struct mgcp_ctx *mgcp_ctx, struct msgb *resp);
void mgcp_ass_complete(struct mgcp_ctx *mgcp_ctx, struct gsm_lchan *lchan); void mgcp_ass_complete(struct mgcp_ctx *mgcp_ctx, struct gsm_lchan *lchan);

View File

@ -28,15 +28,15 @@
enum bsc_con osmo_bsc_sigtran_new_conn(struct gsm_subscriber_connection *conn, struct bsc_msc_data *msc); enum bsc_con osmo_bsc_sigtran_new_conn(struct gsm_subscriber_connection *conn, struct bsc_msc_data *msc);
/* Open a new connection oriented sigtran connection */ /* Open a new connection oriented sigtran connection */
int osmo_bsc_sigtran_open_conn(const struct osmo_bsc_sccp_con *conn, struct msgb *msg); int osmo_bsc_sigtran_open_conn(struct gsm_subscriber_connection *conn, struct msgb *msg);
/* Send data to MSC */ /* Send data to MSC */
int osmo_bsc_sigtran_send(const struct osmo_bsc_sccp_con *conn, struct msgb *msg); int osmo_bsc_sigtran_send(struct gsm_subscriber_connection *conn, struct msgb *msg);
/* Delete a connection from the list with open connections /* Delete a connection from the list with open connections
* (called by osmo_bsc_api.c on failing open connections and * (called by osmo_bsc_api.c on failing open connections and
* locally, when a connection is closed by the MSC */ * locally, when a connection is closed by the MSC */
int osmo_bsc_sigtran_del_conn(struct osmo_bsc_sccp_con *sccp); int osmo_bsc_sigtran_del_conn(struct gsm_subscriber_connection *sccp);
/* Initalize osmo sigtran backhaul */ /* Initalize osmo sigtran backhaul */
int osmo_bsc_sigtran_init(struct llist_head *mscs); int osmo_bsc_sigtran_init(struct llist_head *mscs);

View File

@ -32,6 +32,7 @@
#include <osmocom/bsc/gsm_04_08_utils.h> #include <osmocom/bsc/gsm_04_08_utils.h>
#include <osmocom/bsc/bsc_subscriber.h> #include <osmocom/bsc/bsc_subscriber.h>
#include <osmocom/bsc/penalty_timers.h> #include <osmocom/bsc/penalty_timers.h>
#include <osmocom/bsc/osmo_bsc_sigtran.h>
#include <osmocom/gsm/protocol/gsm_08_08.h> #include <osmocom/gsm/protocol/gsm_08_08.h>
#include <osmocom/gsm/gsm48.h> #include <osmocom/gsm/gsm48.h>
@ -278,6 +279,7 @@ struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_lchan *lcha
lchan->conn = conn; lchan->conn = conn;
INIT_LLIST_HEAD(&conn->ho_dtap_cache); INIT_LLIST_HEAD(&conn->ho_dtap_cache);
conn->ho_penalty_timers = penalty_timers_init(conn); conn->ho_penalty_timers = penalty_timers_init(conn);
conn->sccp.conn_id = -1;
llist_add_tail(&conn->entry, &net->subscr_conns); llist_add_tail(&conn->entry, &net->subscr_conns);
return conn; return conn;
} }

View File

@ -32,13 +32,13 @@
#include <osmocom/bsc/osmo_bsc_sigtran.h> #include <osmocom/bsc/osmo_bsc_sigtran.h>
#define return_when_not_connected(conn) \ #define return_when_not_connected(conn) \
if (!conn->sccp_con) {\ if (conn->sccp.state != SUBSCR_SCCP_ST_CONNECTED) {\
LOGP(DMSC, LOGL_ERROR, "MSC Connection not present.\n"); \ LOGP(DMSC, LOGL_ERROR, "MSC Connection not present.\n"); \
return; \ return; \
} }
#define return_when_not_connected_val(conn, ret) \ #define return_when_not_connected_val(conn, ret) \
if (!conn->sccp_con) {\ if (conn->sccp.state != SUBSCR_SCCP_ST_CONNECTED) {\
LOGP(DMSC, LOGL_ERROR, "MSC Connection not present.\n"); \ LOGP(DMSC, LOGL_ERROR, "MSC Connection not present.\n"); \
return ret; \ return ret; \
} }
@ -48,7 +48,7 @@
LOGP(DMSC, LOGL_ERROR, "Failed to allocate response.\n"); \ LOGP(DMSC, LOGL_ERROR, "Failed to allocate response.\n"); \
return; \ return; \
} \ } \
osmo_bsc_sigtran_send(conn->sccp_con, resp); osmo_bsc_sigtran_send(conn, resp);
static int bsc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause); static int bsc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause);
static int complete_layer3(struct gsm_subscriber_connection *conn, static int complete_layer3(struct gsm_subscriber_connection *conn,
@ -135,12 +135,12 @@ static int bsc_filter_data(struct gsm_subscriber_connection *conn,
req.ctx = conn; req.ctx = conn;
req.black_list = NULL; req.black_list = NULL;
req.access_lists = bsc_access_lists(); req.access_lists = bsc_access_lists();
req.local_lst_name = conn->sccp_con->msc->acc_lst_name; req.local_lst_name = conn->sccp.msc->acc_lst_name;
req.global_lst_name = conn_get_bts(conn)->network->bsc_data->acc_lst_name; req.global_lst_name = conn_get_bts(conn)->network->bsc_data->acc_lst_name;
req.bsc_nr = 0; req.bsc_nr = 0;
rc = bsc_msg_filter_data(gh, msgb_l3len(msg), &req, rc = bsc_msg_filter_data(gh, msgb_l3len(msg), &req,
&conn->sccp_con->filter_state, &conn->filter_state,
&cause); &cause);
*lu_cause = cause.lu_reject_cause; *lu_cause = cause.lu_reject_cause;
return rc; return rc;
@ -280,27 +280,27 @@ static int complete_layer3(struct gsm_subscriber_connection *conn,
} }
if (imsi) if (imsi)
conn->sccp_con->filter_state.imsi = talloc_steal(conn, imsi); conn->filter_state.imsi = talloc_steal(conn, imsi);
conn->sccp_con->filter_state.con_type = con_type; conn->filter_state.con_type = con_type;
/* check return value, if failed check msg for and send USSD */ /* check return value, if failed check msg for and send USSD */
network_code = get_network_code_for_msc(conn->sccp_con->msc); network_code = get_network_code_for_msc(conn->sccp.msc);
country_code = get_country_code_for_msc(conn->sccp_con->msc); country_code = get_country_code_for_msc(conn->sccp.msc);
lac = get_lac_for_msc(conn->sccp_con->msc, conn_get_bts(conn)); lac = get_lac_for_msc(conn->sccp.msc, conn_get_bts(conn));
ci = get_ci_for_msc(conn->sccp_con->msc, conn_get_bts(conn)); ci = get_ci_for_msc(conn->sccp.msc, conn_get_bts(conn));
bsc_scan_bts_msg(conn, msg); bsc_scan_bts_msg(conn, msg);
resp = gsm0808_create_layer3(msg, network_code, country_code, lac, ci); resp = gsm0808_create_layer3(msg, network_code, country_code, lac, ci);
if (!resp) { if (!resp) {
LOGP(DMSC, LOGL_DEBUG, "Failed to create layer3 message.\n"); LOGP(DMSC, LOGL_DEBUG, "Failed to create layer3 message.\n");
osmo_bsc_sigtran_del_conn(conn->sccp_con); osmo_bsc_sigtran_del_conn(conn);
return BSC_API_CONN_POL_REJECT; return BSC_API_CONN_POL_REJECT;
} }
if (osmo_bsc_sigtran_open_conn(conn->sccp_con, resp) != 0) { if (osmo_bsc_sigtran_open_conn(conn, resp) != 0) {
osmo_bsc_sigtran_del_conn(conn->sccp_con); osmo_bsc_sigtran_del_conn(conn);
msgb_free(resp); msgb_free(resp);
return BSC_API_CONN_POL_REJECT; return BSC_API_CONN_POL_REJECT;
} }
@ -314,14 +314,11 @@ static int complete_layer3(struct gsm_subscriber_connection *conn,
static int move_to_msc(struct gsm_subscriber_connection *_conn, static int move_to_msc(struct gsm_subscriber_connection *_conn,
struct msgb *msg, struct bsc_msc_data *msc) struct msgb *msg, struct bsc_msc_data *msc)
{ {
struct osmo_bsc_sccp_con *old_con = _conn->sccp_con;
/* /*
* 1. Give up the old connection. * 1. Give up the old connection.
* This happens by sending a clear request to the MSC, * This happens by sending a clear request to the MSC,
* it should end with the MSC releasing the connection. * it should end with the MSC releasing the connection.
*/ */
old_con->conn = NULL;
bsc_clear_request(_conn, 0); bsc_clear_request(_conn, 0);
/* /*
@ -329,7 +326,6 @@ static int move_to_msc(struct gsm_subscriber_connection *_conn,
* MSC. If it fails the caller will need to handle this * MSC. If it fails the caller will need to handle this
* properly. * properly.
*/ */
_conn->sccp_con = NULL;
if (complete_layer3(_conn, msg, msc) != BSC_API_CONN_POL_ACCEPT) { if (complete_layer3(_conn, msg, msc) != BSC_API_CONN_POL_ACCEPT) {
gsm0808_clear(_conn); gsm0808_clear(_conn);
bsc_subscr_con_free(_conn); bsc_subscr_con_free(_conn);
@ -416,7 +412,7 @@ static void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, st
/* Check the filter */ /* Check the filter */
if (bsc_filter_data(conn, msg, &lu_cause) < 0) { if (bsc_filter_data(conn, msg, &lu_cause) < 0) {
bsc_maybe_lu_reject(conn, bsc_maybe_lu_reject(conn,
conn->sccp_con->filter_state.con_type, conn->filter_state.con_type,
lu_cause); lu_cause);
bsc_clear_request(conn, 0); bsc_clear_request(conn, 0);
return; return;
@ -435,7 +431,7 @@ static void bsc_assign_compl(struct gsm_subscriber_connection *conn, uint8_t rr_
struct msgb *resp; struct msgb *resp;
return_when_not_connected(conn); return_when_not_connected(conn);
if (is_ipaccess_bts(conn_get_bts(conn)) && conn->sccp_con->user_plane.rtp_ip) { if (is_ipaccess_bts(conn_get_bts(conn)) && conn->user_plane.rtp_ip) {
/* NOTE: In a network that makes use of an IPA base station /* NOTE: In a network that makes use of an IPA base station
* and AoIP, we have to wait until the BTS reports its RTP * and AoIP, we have to wait until the BTS reports its RTP
* IP/Port combination back to BSC via RSL. Unfortunately, the * IP/Port combination back to BSC via RSL. Unfortunately, the
@ -473,27 +469,18 @@ static void bsc_assign_fail(struct gsm_subscriber_connection *conn,
static int bsc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause) static int bsc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause)
{ {
struct osmo_bsc_sccp_con *sccp;
struct msgb *resp; struct msgb *resp;
return_when_not_connected_val(conn, 1); return_when_not_connected_val(conn, 1);
LOGP(DMSC, LOGL_INFO, "Tx MSC CLEAR REQUEST\n"); LOGP(DMSC, LOGL_INFO, "Tx MSC CLEAR REQUEST\n");
/*
* Remove the connection from BSC<->SCCP part, the SCCP part
* will either be cleared by channel release or MSC disconnect
*/
sccp = conn->sccp_con;
sccp->conn = NULL;
conn->sccp_con = NULL;
resp = gsm0808_create_clear_rqst(GSM0808_CAUSE_RADIO_INTERFACE_FAILURE); resp = gsm0808_create_clear_rqst(GSM0808_CAUSE_RADIO_INTERFACE_FAILURE);
if (!resp) { if (!resp) {
LOGP(DMSC, LOGL_ERROR, "Failed to allocate response.\n"); LOGP(DMSC, LOGL_ERROR, "Failed to allocate response.\n");
return 1; return 1;
} }
osmo_bsc_sigtran_send(sccp, resp); osmo_bsc_sigtran_send(conn, resp);
return 1; return 1;
} }
@ -515,14 +502,14 @@ static void bsc_mr_config(struct gsm_subscriber_connection *conn,
struct bsc_msc_data *msc; struct bsc_msc_data *msc;
struct gsm48_multi_rate_conf *ms_conf, *bts_conf; struct gsm48_multi_rate_conf *ms_conf, *bts_conf;
if (!conn->sccp_con) { if (!conn) {
LOGP(DMSC, LOGL_ERROR, LOGP(DMSC, LOGL_ERROR,
"No msc data available on conn %p. Audio will be broken.\n", "No msc data available on conn %p. Audio will be broken.\n",
conn); conn);
return; return;
} }
msc = conn->sccp_con->msc; msc = conn->sccp.msc;
/* initialize the data structure */ /* initialize the data structure */
lchan->mr_ms_lv[0] = sizeof(*ms_conf); lchan->mr_ms_lv[0] = sizeof(*ms_conf);

View File

@ -45,24 +45,24 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
return 0; return 0;
con = lchan->conn; con = lchan->conn;
if (!con || !con->sccp_con) if (!con)
return 0; return 0;
switch (signal) { switch (signal) {
case S_ABISIP_CRCX_ACK: case S_ABISIP_CRCX_ACK:
/* we can ask it to connect now */ /* we can ask it to connect now */
LOGP(DMSC, LOGL_DEBUG, "Connecting BTS to port: %d conn: %d\n", LOGP(DMSC, LOGL_DEBUG, "Connecting BTS to port: %d conn: %d\n",
con->sccp_con->user_plane.rtp_port, lchan->abis_ip.conn_id); con->user_plane.rtp_port, lchan->abis_ip.conn_id);
/* If AoIP is in use, the rtp_ip, which has been communicated /* If AoIP is in use, the rtp_ip, which has been communicated
* via the A interface as connect_ip */ * via the A interface as connect_ip */
if(con->sccp_con->user_plane.rtp_ip) if(con->user_plane.rtp_ip)
rtp_ip = con->sccp_con->user_plane.rtp_ip; rtp_ip = con->user_plane.rtp_ip;
else else
rtp_ip = ntohl(INADDR_ANY); rtp_ip = ntohl(INADDR_ANY);
rc = rsl_ipacc_mdcx(lchan, rtp_ip, rc = rsl_ipacc_mdcx(lchan, rtp_ip,
con->sccp_con->user_plane.rtp_port, con->user_plane.rtp_port,
lchan->abis_ip.rtp_payload2); lchan->abis_ip.rtp_payload2);
if (rc < 0) { if (rc < 0) {
LOGP(DMSC, LOGL_ERROR, "Failed to send MDCX: %d\n", rc); LOGP(DMSC, LOGL_ERROR, "Failed to send MDCX: %d\n", rc);
@ -77,12 +77,22 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
/* No need to do anything for handover here. As soon as a HANDOVER DETECT /* No need to do anything for handover here. As soon as a HANDOVER DETECT
* happens, osmo_bsc_mgcp.c will trigger the MGCP MDCX towards MGW by * happens, osmo_bsc_mgcp.c will trigger the MGCP MDCX towards MGW by
* receiving an S_LCHAN_HANDOVER_DETECT signal. */ * receiving an S_LCHAN_HANDOVER_DETECT signal. */
} else if (is_ipaccess_bts(conn_get_bts(con)) && con->sccp_con->user_plane.rtp_ip) { #if 0
/* NOTE: When an ho_lchan exists, the MDCX is part of an
* handover operation (intra-bsc). This means we will not
* inform the MSC about the event, which means that no
* assignment complete message is transmitted, we just
* inform the logic that controls the MGW about the new
* connection info */
LOGP(DMSC, LOGL_INFO,"RTP connection handover initiated...\n");
mgcp_handover(con->user_plane.mgcp_ctx, con->ho_lchan);
#endif
} else if (is_ipaccess_bts(conn_get_bts(con)) && con->user_plane.rtp_ip) {
/* NOTE: This is only relevant on AoIP networks with /* NOTE: This is only relevant on AoIP networks with
* IPA based base stations. See also osmo_bsc_api.c, * IPA based base stations. See also osmo_bsc_api.c,
* function bsc_assign_compl() */ * function bsc_assign_compl() */
LOGP(DMSC, LOGL_INFO, "Tx MSC ASSIGN COMPL (POSTPONED)\n"); LOGP(DMSC, LOGL_INFO, "Tx MSC ASSIGN COMPL (POSTPONED)\n");
mgcp_ass_complete(con->sccp_con->user_plane.mgcp_ctx, lchan); mgcp_ass_complete(con->user_plane.mgcp_ctx, lchan);
} }
break; break;
} }

View File

@ -571,19 +571,15 @@ static int bssmap_handle_paging(struct bsc_msc_data *msc,
* GSM 08.08 § 3.1.9.1 and 3.2.1.21... * GSM 08.08 § 3.1.9.1 and 3.2.1.21...
* release our gsm_subscriber_connection and send message * release our gsm_subscriber_connection and send message
*/ */
static int bssmap_handle_clear_command(struct osmo_bsc_sccp_con *conn, static int bssmap_handle_clear_command(struct gsm_subscriber_connection *conn,
struct msgb *msg, unsigned int payload_length) struct msgb *msg, unsigned int payload_length)
{ {
struct msgb *resp; struct msgb *resp;
/* TODO: handle the cause of this package */ /* TODO: handle the cause of this package */
if (conn->conn) { LOGP(DMSC, LOGL_INFO, "Releasing all transactions on %p\n", conn);
LOGP(DMSC, LOGL_INFO, "Releasing all transactions on %p\n", conn); gsm0808_clear(conn);
gsm0808_clear(conn->conn);
bsc_subscr_con_free(conn->conn);
conn->conn = NULL;
}
/* generate the clear complete message */ /* generate the clear complete message */
resp = gsm0808_create_clear_complete(); resp = gsm0808_create_clear_complete();
@ -618,7 +614,7 @@ static int bssmap_handle_clear_command(struct osmo_bsc_sccp_con *conn,
* is supporting. Currently we are doing it in a rather static * is supporting. Currently we are doing it in a rather static
* way by picking one encryption or no encryption. * way by picking one encryption or no encryption.
*/ */
static int bssmap_handle_cipher_mode(struct osmo_bsc_sccp_con *conn, static int bssmap_handle_cipher_mode(struct gsm_subscriber_connection *conn,
struct msgb *msg, unsigned int payload_length) struct msgb *msg, unsigned int payload_length)
{ {
uint16_t len; uint16_t len;
@ -633,7 +629,7 @@ static int bssmap_handle_cipher_mode(struct osmo_bsc_sccp_con *conn,
uint8_t enc_bits_bsc; uint8_t enc_bits_bsc;
uint8_t enc_bits_msc; uint8_t enc_bits_msc;
if (!conn->conn) { if (!conn) {
LOGP(DMSC, LOGL_ERROR, "No lchan/msc_data in cipher mode command.\n"); LOGP(DMSC, LOGL_ERROR, "No lchan/msc_data in cipher mode command.\n");
goto reject; goto reject;
} }
@ -663,7 +659,7 @@ static int bssmap_handle_cipher_mode(struct osmo_bsc_sccp_con *conn,
goto reject; goto reject;
} }
network = conn_get_bts(conn->conn)->network; network = conn_get_bts(conn)->network;
data = TLVP_VAL(&tp, GSM0808_IE_ENCRYPTION_INFORMATION); data = TLVP_VAL(&tp, GSM0808_IE_ENCRYPTION_INFORMATION);
enc_bits_msc = data[0]; enc_bits_msc = data[0];
enc_key = &data[1]; enc_key = &data[1];
@ -692,7 +688,7 @@ static int bssmap_handle_cipher_mode(struct osmo_bsc_sccp_con *conn,
/* To complete the confusion, gsm0808_cipher_mode again expects the encryption as a number /* To complete the confusion, gsm0808_cipher_mode again expects the encryption as a number
* from 0 to 7. */ * from 0 to 7. */
if (gsm0808_cipher_mode(conn->conn, network->a5_encryption, enc_key, enc_key_len, if (gsm0808_cipher_mode(conn, network->a5_encryption, enc_key, enc_key_len,
include_imeisv)) { include_imeisv)) {
reject_cause = GSM0808_CAUSE_PROTOCOL_ERROR_BETWEEN_BSS_AND_MSC; reject_cause = GSM0808_CAUSE_PROTOCOL_ERROR_BETWEEN_BSS_AND_MSC;
goto reject; goto reject;
@ -728,7 +724,7 @@ static inline int mgcp_timeslot_to_port(int multiplex, int timeslot, int base)
* *
* See §3.2.1.1 for the message type * See §3.2.1.1 for the message type
*/ */
static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn, static int bssmap_handle_assignm_req(struct gsm_subscriber_connection *conn,
struct msgb *msg, unsigned int length) struct msgb *msg, unsigned int length)
{ {
struct msgb *resp; struct msgb *resp;
@ -744,13 +740,13 @@ static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn,
struct gsm0808_speech_codec_list *scl_ptr = NULL; struct gsm0808_speech_codec_list *scl_ptr = NULL;
int rc; int rc;
if (!conn->conn) { if (!conn) {
LOGP(DMSC, LOGL_ERROR, LOGP(DMSC, LOGL_ERROR,
"No lchan/msc_data in cipher mode command.\n"); "No lchan/msc_data in cipher mode command.\n");
return -1; return -1;
} }
msc = conn->msc; msc = conn->sccp.msc;
tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, length - 1, 0, 0); tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, length - 1, 0, 0);
@ -799,7 +795,7 @@ static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn,
} }
/* Decode speech codec list (AoIP) */ /* Decode speech codec list (AoIP) */
conn->conn->codec_list_present = false; conn->codec_list_present = false;
if (aoip) { if (aoip) {
/* Check for speech codec list element */ /* Check for speech codec list element */
if (!TLVP_PRESENT(&tp, GSM0808_IE_SPEECH_CODEC_LIST)) { if (!TLVP_PRESENT(&tp, GSM0808_IE_SPEECH_CODEC_LIST)) {
@ -809,7 +805,7 @@ static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn,
} }
/* Decode Speech Codec list */ /* Decode Speech Codec list */
rc = gsm0808_dec_speech_codec_list(&conn->conn->codec_list, rc = gsm0808_dec_speech_codec_list(&conn->codec_list,
TLVP_VAL(&tp, GSM0808_IE_SPEECH_CODEC_LIST), TLVP_VAL(&tp, GSM0808_IE_SPEECH_CODEC_LIST),
TLVP_LEN(&tp, GSM0808_IE_SPEECH_CODEC_LIST)); TLVP_LEN(&tp, GSM0808_IE_SPEECH_CODEC_LIST));
if (rc < 0) { if (rc < 0) {
@ -817,8 +813,8 @@ static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn,
"Unable to decode speech codec list\n"); "Unable to decode speech codec list\n");
goto reject; goto reject;
} }
conn->conn->codec_list_present = true; conn->codec_list_present = true;
scl_ptr = &conn->conn->codec_list; scl_ptr = &conn->codec_list;
} }
/* Match codec information from the assignment command against the /* Match codec information from the assignment command against the
@ -856,7 +852,8 @@ static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn,
conn->user_plane.mgcp_ctx = mgcp_assignm_req(msc->network, msc->network->mgw.client, conn->user_plane.mgcp_ctx = mgcp_assignm_req(msc->network, msc->network->mgw.client,
conn, chan_mode, full_rate); conn, chan_mode, full_rate);
if (!conn->user_plane.mgcp_ctx) { if (!conn->user_plane.mgcp_ctx) {
LOGP(DMSC, LOGL_ERROR, "MGCP GW failure, rejecting assignment... (id=%i)\n", conn->conn_id); LOGP(DMSC, LOGL_ERROR, "MGCP GW failure, rejecting assignment... (id=%i)\n",
conn->sccp.conn_id);
goto reject; goto reject;
} }
@ -869,7 +866,7 @@ static int bssmap_handle_assignm_req(struct osmo_bsc_sccp_con *conn,
* to sccp-lite. */ * to sccp-lite. */
conn->user_plane.rtp_port = mgcp_timeslot_to_port(multiplex, timeslot, msc->rtp_base); conn->user_plane.rtp_port = mgcp_timeslot_to_port(multiplex, timeslot, msc->rtp_base);
conn->user_plane.rtp_ip = 0; conn->user_plane.rtp_ip = 0;
return gsm0808_assign_req(conn->conn, chan_mode, full_rate); return gsm0808_assign_req(conn, chan_mode, full_rate);
} }
reject: reject:
@ -917,7 +914,7 @@ static int bssmap_rcvmsg_udt(struct bsc_msc_data *msc,
return ret; return ret;
} }
static int bssmap_rcvmsg_dt1(struct osmo_bsc_sccp_con *conn, static int bssmap_rcvmsg_dt1(struct gsm_subscriber_connection *conn,
struct msgb *msg, unsigned int length) struct msgb *msg, unsigned int length)
{ {
int ret = 0; int ret = 0;
@ -949,7 +946,7 @@ static int bssmap_rcvmsg_dt1(struct osmo_bsc_sccp_con *conn,
return ret; return ret;
} }
static int dtap_rcvmsg(struct osmo_bsc_sccp_con *conn, static int dtap_rcvmsg(struct gsm_subscriber_connection *conn,
struct msgb *msg, unsigned int length) struct msgb *msg, unsigned int length)
{ {
struct dtap_header *header; struct dtap_header *header;
@ -960,7 +957,7 @@ static int dtap_rcvmsg(struct osmo_bsc_sccp_con *conn,
LOGP(DMSC, LOGL_DEBUG, "Rx MSC DTAP: %s\n", LOGP(DMSC, LOGL_DEBUG, "Rx MSC DTAP: %s\n",
osmo_hexdump(msg->l3h, length)); osmo_hexdump(msg->l3h, length));
if (!conn->conn) { if (!conn) {
LOGP(DMSC, LOGL_ERROR, "No subscriber connection available\n"); LOGP(DMSC, LOGL_ERROR, "No subscriber connection available\n");
return -1; return -1;
} }
@ -992,10 +989,10 @@ static int dtap_rcvmsg(struct osmo_bsc_sccp_con *conn,
memcpy(data, msg->l3h + sizeof(*header), length - sizeof(*header)); memcpy(data, msg->l3h + sizeof(*header), length - sizeof(*header));
/* pass it to the filter for extra actions */ /* pass it to the filter for extra actions */
rc = bsc_scan_msc_msg(conn->conn, gsm48); rc = bsc_scan_msc_msg(conn, gsm48);
dtap_rc = gsm0808_submit_dtap(conn->conn, gsm48, header->link_id, 1); dtap_rc = gsm0808_submit_dtap(conn, gsm48, header->link_id, 1);
if (rc == BSS_SEND_USSD) if (rc == BSS_SEND_USSD)
bsc_send_welcome_ussd(conn->conn); bsc_send_welcome_ussd(conn);
return dtap_rc; return dtap_rc;
} }
@ -1029,7 +1026,7 @@ int bsc_handle_udt(struct bsc_msc_data *msc,
return 0; return 0;
} }
int bsc_handle_dt(struct osmo_bsc_sccp_con *conn, int bsc_handle_dt(struct gsm_subscriber_connection *conn,
struct msgb *msg, unsigned int len) struct msgb *msg, unsigned int len)
{ {
if (len < sizeof(struct bssmap_header)) { if (len < sizeof(struct bssmap_header)) {
@ -1063,9 +1060,8 @@ int bssmap_send_aoip_ass_compl(struct gsm_lchan *lchan)
OSMO_ASSERT(lchan->abis_ip.ass_compl.valid); OSMO_ASSERT(lchan->abis_ip.ass_compl.valid);
OSMO_ASSERT(conn); OSMO_ASSERT(conn);
OSMO_ASSERT(conn->sccp_con);
LOGP(DMSC, LOGL_DEBUG, "Sending assignment complete message... (id=%i)\n", conn->sccp_con->conn_id); LOGP(DMSC, LOGL_DEBUG, "Sending assignment complete message... (id=%i)\n", conn->sccp.conn_id);
/* Extrapolate speech codec from speech mode */ /* Extrapolate speech codec from speech mode */
gsm0808_speech_codec_from_chan_type(&sc, lchan->abis_ip.ass_compl.speech_mode); gsm0808_speech_codec_from_chan_type(&sc, lchan->abis_ip.ass_compl.speech_mode);
@ -1075,15 +1071,15 @@ int bssmap_send_aoip_ass_compl(struct gsm_lchan *lchan)
lchan->abis_ip.ass_compl.chosen_channel, lchan->abis_ip.ass_compl.chosen_channel,
lchan->abis_ip.ass_compl.encr_alg_id, lchan->abis_ip.ass_compl.encr_alg_id,
lchan->abis_ip.ass_compl.speech_mode, lchan->abis_ip.ass_compl.speech_mode,
&conn->sccp_con->user_plane.aoip_rtp_addr_local, &conn->user_plane.aoip_rtp_addr_local,
&sc, &sc,
NULL); NULL);
if (!resp) { if (!resp) {
LOGP(DMSC, LOGL_ERROR, "Failed to generate assignment completed message! (id=%i)\n", LOGP(DMSC, LOGL_ERROR, "Failed to generate assignment completed message! (id=%i)\n",
conn->sccp_con->conn_id); conn->sccp.conn_id);
return -EINVAL; return -EINVAL;
} }
return osmo_bsc_sigtran_send(conn->sccp_con, resp); return osmo_bsc_sigtran_send(conn, resp);
} }

View File

@ -570,10 +570,7 @@ static int set_net_ussd_notify(struct ctrl_cmd *cmd, void *data)
net = cmd->node; net = cmd->node;
llist_for_each_entry(conn, &net->subscr_conns, entry) { llist_for_each_entry(conn, &net->subscr_conns, entry) {
if (!conn->sccp_con) if (conn->user_plane.cic != cic)
continue;
if (conn->sccp_con->user_plane.cic != cic)
continue; continue;
/* /*

View File

@ -54,7 +54,7 @@ static void handle_lu_request(struct gsm_subscriber_connection *conn,
if (memcmp(&lai, &lu->lai, sizeof(lai)) != 0) { if (memcmp(&lai, &lu->lai, sizeof(lai)) != 0) {
LOGP(DMSC, LOGL_DEBUG, "Marking con for welcome USSD.\n"); LOGP(DMSC, LOGL_DEBUG, "Marking con for welcome USSD.\n");
conn->sccp_con->new_subscriber = 1; conn->new_subscriber = 1;
} }
} }
@ -234,15 +234,7 @@ int bsc_scan_bts_msg(struct gsm_subscriber_connection *conn, struct msgb *msg)
static int send_welcome_ussd(struct gsm_subscriber_connection *conn) static int send_welcome_ussd(struct gsm_subscriber_connection *conn)
{ {
struct osmo_bsc_sccp_con *bsc_con; if (!conn->sccp.msc->ussd_welcome_txt) {
bsc_con = conn->sccp_con;
if (!bsc_con) {
LOGP(DMSC, LOGL_DEBUG, "No SCCP connection associated.\n");
return 0;
}
if (!bsc_con->msc->ussd_welcome_txt) {
LOGP(DMSC, LOGL_DEBUG, "No USSD Welcome text defined.\n"); LOGP(DMSC, LOGL_DEBUG, "No USSD Welcome text defined.\n");
return 0; return 0;
} }
@ -252,7 +244,7 @@ static int send_welcome_ussd(struct gsm_subscriber_connection *conn)
int bsc_send_welcome_ussd(struct gsm_subscriber_connection *conn) int bsc_send_welcome_ussd(struct gsm_subscriber_connection *conn)
{ {
bsc_send_ussd_notify(conn, 1, conn->sccp_con->msc->ussd_welcome_txt); bsc_send_ussd_notify(conn, 1, conn->sccp.msc->ussd_welcome_txt);
bsc_send_ussd_release_complete(conn); bsc_send_ussd_release_complete(conn);
return 0; return 0;
@ -362,7 +354,7 @@ int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg)
mtype = gsm48_hdr_msg_type(gh); mtype = gsm48_hdr_msg_type(gh);
net = bts->network; net = bts->network;
msc = conn->sccp_con->msc; msc = conn->sccp.msc;
if (mtype == GSM48_MT_MM_LOC_UPD_ACCEPT) { if (mtype == GSM48_MT_MM_LOC_UPD_ACCEPT) {
if (has_core_identity(msc)) { if (has_core_identity(msc)) {
@ -375,7 +367,7 @@ int bsc_scan_msc_msg(struct gsm_subscriber_connection *conn, struct msgb *msg)
} }
} }
if (conn->sccp_con->new_subscriber) if (conn->new_subscriber)
return send_welcome_ussd(conn); return send_welcome_ussd(conn);
return 0; return 0;
} else if (mtype == GSM48_MT_MM_INFO) { } else if (mtype == GSM48_MT_MM_INFO) {

View File

@ -151,7 +151,7 @@ static void crcx_for_bts_resp_cb(struct mgcp_response *r, void *priv);
static void fsm_crcx_bts_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data) static void fsm_crcx_bts_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{ {
struct mgcp_ctx *mgcp_ctx = data; struct mgcp_ctx *mgcp_ctx = data;
struct osmo_bsc_sccp_con *conn; struct gsm_subscriber_connection *conn;
struct msgb *msg; struct msgb *msg;
struct mgcp_msg mgcp_msg; struct mgcp_msg mgcp_msg;
struct mgcp_client *mgcp; struct mgcp_client *mgcp;
@ -174,7 +174,7 @@ static void fsm_crcx_bts_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data
mgcp_msg = (struct mgcp_msg) { mgcp_msg = (struct mgcp_msg) {
.verb = MGCP_VERB_CRCX, .verb = MGCP_VERB_CRCX,
.presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID | MGCP_MSG_PRESENCE_CONN_MODE), .presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID | MGCP_MSG_PRESENCE_CONN_MODE),
.call_id = conn->conn_id, .call_id = conn->sccp.conn_id,
.conn_mode = MGCP_CONN_LOOPBACK .conn_mode = MGCP_CONN_LOOPBACK
}; };
if (snprintf(mgcp_msg.endpoint, MGCP_ENDPOINT_MAXLEN, MGCP_ENDPOINT_FORMAT, rtp_endpoint) >= if (snprintf(mgcp_msg.endpoint, MGCP_ENDPOINT_MAXLEN, MGCP_ENDPOINT_FORMAT, rtp_endpoint) >=
@ -201,7 +201,7 @@ static void crcx_for_bts_resp_cb(struct mgcp_response *r, void *priv)
{ {
struct mgcp_ctx *mgcp_ctx = priv; struct mgcp_ctx *mgcp_ctx = priv;
int rc; int rc;
struct osmo_bsc_sccp_con *conn; struct gsm_subscriber_connection *conn;
uint32_t addr; uint32_t addr;
OSMO_ASSERT(mgcp_ctx); OSMO_ASSERT(mgcp_ctx);
@ -256,7 +256,7 @@ static void crcx_for_bts_resp_cb(struct mgcp_response *r, void *priv)
static void fsm_proc_assignmnent_req_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data) static void fsm_proc_assignmnent_req_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{ {
struct mgcp_ctx *mgcp_ctx = data; struct mgcp_ctx *mgcp_ctx = data;
struct osmo_bsc_sccp_con *conn; struct gsm_subscriber_connection *conn;
enum gsm48_chan_mode chan_mode; enum gsm48_chan_mode chan_mode;
bool full_rate; bool full_rate;
int rc; int rc;
@ -273,12 +273,12 @@ static void fsm_proc_assignmnent_req_cb(struct osmo_fsm_inst *fi, uint32_t event
return; return;
} }
OSMO_ASSERT(conn->conn); OSMO_ASSERT(conn);
chan_mode = mgcp_ctx->chan_mode; chan_mode = mgcp_ctx->chan_mode;
full_rate = mgcp_ctx->full_rate; full_rate = mgcp_ctx->full_rate;
LOGPFSML(fi, LOGL_DEBUG, "MGW proceeding assignment request...\n"); LOGPFSML(fi, LOGL_DEBUG, "MGW proceeding assignment request...\n");
rc = gsm0808_assign_req(conn->conn, chan_mode, full_rate); rc = gsm0808_assign_req(conn, chan_mode, full_rate);
if (rc < 0) { if (rc < 0) {
handle_error(mgcp_ctx, MGCP_ERR_ASSGMNT_FAIL); handle_error(mgcp_ctx, MGCP_ERR_ASSGMNT_FAIL);
@ -295,7 +295,7 @@ static void mdcx_for_bts_resp_cb(struct mgcp_response *r, void *priv);
static void fsm_mdcx_bts_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data) static void fsm_mdcx_bts_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{ {
struct mgcp_ctx *mgcp_ctx = data; struct mgcp_ctx *mgcp_ctx = data;
struct osmo_bsc_sccp_con *conn; struct gsm_subscriber_connection *conn;
struct gsm_lchan *lchan; struct gsm_lchan *lchan;
struct msgb *msg; struct msgb *msg;
struct mgcp_msg mgcp_msg; struct mgcp_msg mgcp_msg;
@ -333,7 +333,7 @@ static void fsm_mdcx_bts_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data
.verb = MGCP_VERB_MDCX, .verb = MGCP_VERB_MDCX,
.presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID | MGCP_MSG_PRESENCE_CONN_ID | .presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID | MGCP_MSG_PRESENCE_CONN_ID |
MGCP_MSG_PRESENCE_CONN_MODE | MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT), MGCP_MSG_PRESENCE_CONN_MODE | MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT),
.call_id = conn->conn_id, .call_id = conn->sccp.conn_id,
.conn_id = mgcp_ctx->conn_id_bts, .conn_id = mgcp_ctx->conn_id_bts,
.conn_mode = MGCP_CONN_RECV_SEND, .conn_mode = MGCP_CONN_RECV_SEND,
.audio_ip = inet_ntoa(addr), .audio_ip = inet_ntoa(addr),
@ -407,7 +407,7 @@ static void crcx_for_net_resp_cb(struct mgcp_response *r, void *priv);
static void fsm_crcx_net_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data) static void fsm_crcx_net_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{ {
struct mgcp_ctx *mgcp_ctx = data; struct mgcp_ctx *mgcp_ctx = data;
struct osmo_bsc_sccp_con *conn; struct gsm_subscriber_connection *conn;
struct msgb *msg; struct msgb *msg;
struct mgcp_msg mgcp_msg; struct mgcp_msg mgcp_msg;
struct mgcp_client *mgcp; struct mgcp_client *mgcp;
@ -460,7 +460,7 @@ static void fsm_crcx_net_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data
.verb = MGCP_VERB_CRCX, .verb = MGCP_VERB_CRCX,
.presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID | MGCP_MSG_PRESENCE_CONN_MODE | .presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID | MGCP_MSG_PRESENCE_CONN_MODE |
MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT), MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_AUDIO_PORT),
.call_id = conn->conn_id, .call_id = conn->sccp.conn_id,
.conn_mode = MGCP_CONN_RECV_SEND, .conn_mode = MGCP_CONN_RECV_SEND,
.audio_ip = addr, .audio_ip = addr,
.audio_port = port .audio_port = port
@ -489,7 +489,7 @@ static void crcx_for_net_resp_cb(struct mgcp_response *r, void *priv)
{ {
struct mgcp_ctx *mgcp_ctx = priv; struct mgcp_ctx *mgcp_ctx = priv;
int rc; int rc;
struct osmo_bsc_sccp_con *conn; struct gsm_subscriber_connection *conn;
struct gsm_lchan *lchan; struct gsm_lchan *lchan;
struct sockaddr_in *sin; struct sockaddr_in *sin;
uint32_t addr; uint32_t addr;
@ -581,7 +581,7 @@ static void mdcx_for_bts_ho_resp_cb(struct mgcp_response *r, void *priv);
* change to ST_HALT when teardown is done. */ * change to ST_HALT when teardown is done. */
static void handle_teardown(struct mgcp_ctx *mgcp_ctx) static void handle_teardown(struct mgcp_ctx *mgcp_ctx)
{ {
struct osmo_bsc_sccp_con *conn; struct gsm_subscriber_connection *conn;
struct msgb *msg; struct msgb *msg;
struct mgcp_msg mgcp_msg; struct mgcp_msg mgcp_msg;
struct mgcp_client *mgcp; struct mgcp_client *mgcp;
@ -607,7 +607,7 @@ static void handle_teardown(struct mgcp_ctx *mgcp_ctx)
mgcp_msg = (struct mgcp_msg) { mgcp_msg = (struct mgcp_msg) {
.verb = MGCP_VERB_DLCX, .verb = MGCP_VERB_DLCX,
.presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID), .presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID),
.call_id = conn->conn_id .call_id = conn->sccp.conn_id
}; };
if (snprintf(mgcp_msg.endpoint, sizeof(mgcp_msg.endpoint), MGCP_ENDPOINT_FORMAT, rtp_endpoint) >= if (snprintf(mgcp_msg.endpoint, sizeof(mgcp_msg.endpoint), MGCP_ENDPOINT_FORMAT, rtp_endpoint) >=
sizeof(mgcp_msg.endpoint)) { sizeof(mgcp_msg.endpoint)) {
@ -633,7 +633,7 @@ static void handle_teardown(struct mgcp_ctx *mgcp_ctx)
* change to ST_CALL when teardown is done. */ * change to ST_CALL when teardown is done. */
static void handle_handover(struct mgcp_ctx *mgcp_ctx) static void handle_handover(struct mgcp_ctx *mgcp_ctx)
{ {
struct osmo_bsc_sccp_con *conn; struct gsm_subscriber_connection *conn;
struct msgb *msg; struct msgb *msg;
struct mgcp_msg mgcp_msg; struct mgcp_msg mgcp_msg;
struct mgcp_client *mgcp; struct mgcp_client *mgcp;
@ -663,7 +663,7 @@ static void handle_handover(struct mgcp_ctx *mgcp_ctx)
.presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID | MGCP_MSG_PRESENCE_CONN_ID | .presence = (MGCP_MSG_PRESENCE_ENDPOINT | MGCP_MSG_PRESENCE_CALL_ID | MGCP_MSG_PRESENCE_CONN_ID |
MGCP_MSG_PRESENCE_CONN_MODE | MGCP_MSG_PRESENCE_AUDIO_IP | MGCP_MSG_PRESENCE_CONN_MODE | MGCP_MSG_PRESENCE_AUDIO_IP |
MGCP_MSG_PRESENCE_AUDIO_PORT), MGCP_MSG_PRESENCE_AUDIO_PORT),
.call_id = conn->conn_id, .call_id = conn->sccp.conn_id,
.conn_id = mgcp_ctx->conn_id_bts, .conn_id = mgcp_ctx->conn_id_bts,
.conn_mode = MGCP_CONN_RECV_SEND, .conn_mode = MGCP_CONN_RECV_SEND,
.audio_ip = inet_ntoa(addr), .audio_ip = inet_ntoa(addr),
@ -766,7 +766,7 @@ static void fsm_complete_handover(struct osmo_fsm_inst *fi, uint32_t event, void
static void dlcx_for_all_resp_cb(struct mgcp_response *r, void *priv) static void dlcx_for_all_resp_cb(struct mgcp_response *r, void *priv)
{ {
struct mgcp_ctx *mgcp_ctx = priv; struct mgcp_ctx *mgcp_ctx = priv;
struct osmo_bsc_sccp_con *conn; struct gsm_subscriber_connection *conn;
struct mgcp_client *mgcp; struct mgcp_client *mgcp;
OSMO_ASSERT(mgcp_ctx); OSMO_ASSERT(mgcp_ctx);
@ -799,7 +799,7 @@ static void dlcx_for_all_resp_cb(struct mgcp_response *r, void *priv)
static void fsm_halt_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data) static void fsm_halt_cb(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{ {
struct mgcp_ctx *mgcp_ctx = (struct mgcp_ctx *)data; struct mgcp_ctx *mgcp_ctx = (struct mgcp_ctx *)data;
struct osmo_bsc_sccp_con *conn; struct gsm_subscriber_connection *conn;
OSMO_ASSERT(mgcp_ctx); OSMO_ASSERT(mgcp_ctx);
conn = mgcp_ctx->conn; conn = mgcp_ctx->conn;
@ -960,7 +960,8 @@ static struct osmo_fsm fsm_bsc_mgcp = {
* chan_mode: channel mode (system data, passed through) * chan_mode: channel mode (system data, passed through)
* full_rate: full rate flag (system data, passed through) * full_rate: full rate flag (system data, passed through)
* Returns an mgcp_context that contains system data and the OSMO-FSM */ * Returns an mgcp_context that contains system data and the OSMO-FSM */
struct mgcp_ctx *mgcp_assignm_req(void *ctx, struct mgcp_client *mgcp, struct osmo_bsc_sccp_con *conn, struct mgcp_ctx *mgcp_assignm_req(void *ctx, struct mgcp_client *mgcp,
struct gsm_subscriber_connection *conn,
enum gsm48_chan_mode chan_mode, bool full_rate) enum gsm48_chan_mode chan_mode, bool full_rate)
{ {
struct mgcp_ctx *mgcp_ctx; struct mgcp_ctx *mgcp_ctx;
@ -969,7 +970,7 @@ struct mgcp_ctx *mgcp_assignm_req(void *ctx, struct mgcp_client *mgcp, struct os
OSMO_ASSERT(mgcp); OSMO_ASSERT(mgcp);
OSMO_ASSERT(conn); OSMO_ASSERT(conn);
OSMO_ASSERT(snprintf(name, sizeof(name), "MGW_%i", conn->conn_id) < sizeof(name)); OSMO_ASSERT(snprintf(name, sizeof(name), "MGW_%i", conn->sccp.conn_id) < sizeof(name));
/* Allocate and configure a new fsm instance */ /* Allocate and configure a new fsm instance */
mgcp_ctx = talloc_zero(ctx, struct mgcp_ctx); mgcp_ctx = talloc_zero(ctx, struct mgcp_ctx);
@ -997,7 +998,7 @@ struct mgcp_ctx *mgcp_assignm_req(void *ctx, struct mgcp_client *mgcp, struct os
* respmgcp_ctx: pending clear complete message to send via A-Interface */ * respmgcp_ctx: pending clear complete message to send via A-Interface */
void mgcp_clear_complete(struct mgcp_ctx *mgcp_ctx, struct msgb *resp) void mgcp_clear_complete(struct mgcp_ctx *mgcp_ctx, struct msgb *resp)
{ {
struct osmo_bsc_sccp_con *conn; struct gsm_subscriber_connection *conn;
OSMO_ASSERT(mgcp_ctx); OSMO_ASSERT(mgcp_ctx);
OSMO_ASSERT(resp); OSMO_ASSERT(resp);
@ -1086,19 +1087,19 @@ static int mgcp_sig_ho_detect(struct gsm_lchan *new_lchan)
return -EINVAL; return -EINVAL;
} }
if (!conn->sccp_con) { if (!conn->sccp.conn_id) {
LOGP(DHO, LOGL_ERROR, "%s HO Detect for conn without sccp_con\n", LOGP(DHO, LOGL_ERROR, "%s HO Detect for conn without sccp_conn_id\n",
gsm_lchan_name(new_lchan)); gsm_lchan_name(new_lchan));
return -EINVAL; return -EINVAL;
} }
if (!conn->sccp_con->user_plane.mgcp_ctx) { if (!conn->user_plane.mgcp_ctx) {
LOGP(DHO, LOGL_ERROR, "%s HO Detect for conn without MGCP ctx\n", LOGP(DHO, LOGL_ERROR, "%s HO Detect for conn without MGCP ctx\n",
gsm_lchan_name(new_lchan)); gsm_lchan_name(new_lchan));
return -EINVAL; return -EINVAL;
} }
mgcp_handover(conn->sccp_con->user_plane.mgcp_ctx, new_lchan); mgcp_handover(conn->user_plane.mgcp_ctx, new_lchan);
return 0; return 0;
} }

View File

@ -38,28 +38,26 @@
* (a copy of the pointer location submitted with osmo_bsc_sigtran_init() */ * (a copy of the pointer location submitted with osmo_bsc_sigtran_init() */
static struct llist_head *msc_list; static struct llist_head *msc_list;
extern struct gsm_network *bsc_gsmnet;
#define RESET_INTERVAL 1 /* sek */ #define RESET_INTERVAL 1 /* sek */
#define SCCP_MSG_MAXSIZE 1024 #define SCCP_MSG_MAXSIZE 1024
#define CS7_POINTCODE_DEFAULT_OFFSET 2 #define CS7_POINTCODE_DEFAULT_OFFSET 2
/* Internal list with connections we currently maintain. This
* list is of type struct osmo_bsc_sccp_con */
static LLIST_HEAD(active_connections);
/* The SCCP stack will not assign connection IDs to us automatically, we /* The SCCP stack will not assign connection IDs to us automatically, we
* will do this ourselves using a counter variable, that counts one up * will do this ourselves using a counter variable, that counts one up
* for every new connection */ * for every new connection */
static uint32_t conn_id_counter; static uint32_t conn_id_counter;
/* Helper function to Check if the given connection id is already assigned */ /* Helper function to Check if the given connection id is already assigned */
static struct osmo_bsc_sccp_con *get_bsc_conn_by_conn_id(int conn_id) static struct gsm_subscriber_connection *get_bsc_conn_by_conn_id(int conn_id)
{ {
conn_id &= 0xFFFFFF; conn_id &= 0xFFFFFF;
struct osmo_bsc_sccp_con *bsc_con; struct gsm_subscriber_connection *conn;
llist_for_each_entry(bsc_con, &active_connections, entry) { llist_for_each_entry(conn, &bsc_gsmnet->subscr_conns, entry) {
if (bsc_con->conn_id == conn_id) if (conn->sccp.conn_id == conn_id)
return bsc_con; return conn;
} }
return NULL; return NULL;
@ -131,12 +129,12 @@ static struct bsc_msc_data *get_msc_by_addr(const struct osmo_sccp_addr *msc_add
/* Send data to MSC, use the connection id which MSC it is */ /* Send data to MSC, use the connection id which MSC it is */
static int handle_data_from_msc(int conn_id, struct msgb *msg) static int handle_data_from_msc(int conn_id, struct msgb *msg)
{ {
struct osmo_bsc_sccp_con *bsc_con = get_bsc_conn_by_conn_id(conn_id); struct gsm_subscriber_connection *conn = get_bsc_conn_by_conn_id(conn_id);
int rc = -EINVAL; int rc = -EINVAL;
if (bsc_con) { if (conn) {
msg->l3h = msgb_l2(msg); msg->l3h = msgb_l2(msg);
rc = bsc_handle_dt(bsc_con, msg, msgb_l2len(msg)); rc = bsc_handle_dt(conn, msg, msgb_l2len(msg));
} else } else
LOGP(DMSC, LOGL_NOTICE, "incoming data from unknown connection id: %i\n", conn_id); LOGP(DMSC, LOGL_NOTICE, "incoming data from unknown connection id: %i\n", conn_id);
@ -168,7 +166,7 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
{ {
struct osmo_scu_prim *scu_prim = (struct osmo_scu_prim *)oph; struct osmo_scu_prim *scu_prim = (struct osmo_scu_prim *)oph;
struct osmo_sccp_user *scu = _scu; struct osmo_sccp_user *scu = _scu;
struct osmo_bsc_sccp_con *bsc_con; struct gsm_subscriber_connection *conn;
int rc = 0; int rc = 0;
switch (OSMO_PRIM_HDR(&scu_prim->oph)) { switch (OSMO_PRIM_HDR(&scu_prim->oph)) {
@ -187,6 +185,9 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM): case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM):
/* Handle outbound connection confirmation */ /* Handle outbound connection confirmation */
conn = get_bsc_conn_by_conn_id(scu_prim->u.connect.conn_id);
if (conn)
conn->sccp.state = SUBSCR_SCCP_ST_CONNECTED;
if (msgb_l2len(oph->msg) > 0) { if (msgb_l2len(oph->msg) > 0) {
DEBUGP(DMSC, "N-CONNECT.cnf(%u, %s)\n", scu_prim->u.connect.conn_id, DEBUGP(DMSC, "N-CONNECT.cnf(%u, %s)\n", scu_prim->u.connect.conn_id,
osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
@ -201,32 +202,28 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg))); osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
/* Incoming data is a sign of a vital connection */ /* Incoming data is a sign of a vital connection */
bsc_con = get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id); conn = get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id);
if (bsc_con) if (conn)
a_reset_conn_success(bsc_con->msc->a.reset); a_reset_conn_success(conn->sccp.msc->a.reset);
rc = handle_data_from_msc(scu_prim->u.data.conn_id, oph->msg); rc = handle_data_from_msc(scu_prim->u.data.conn_id, oph->msg);
break; break;
case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION): case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION):
/* indication of disconnect */ /* indication of disconnect */
conn = get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id);
if (conn)
conn->sccp.state = SUBSCR_SCCP_ST_NONE;
if (msgb_l2len(oph->msg) > 0) { if (msgb_l2len(oph->msg) > 0) {
DEBUGP(DMSC, "N-DISCONNECT.ind(%u, %s, cause=%i)\n", scu_prim->u.disconnect.conn_id, DEBUGP(DMSC, "N-DISCONNECT.ind(%u, %s, cause=%i)\n", scu_prim->u.disconnect.conn_id,
osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)), scu_prim->u.disconnect.cause); osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)), scu_prim->u.disconnect.cause);
handle_data_from_msc(scu_prim->u.disconnect.conn_id, oph->msg); handle_data_from_msc(scu_prim->u.disconnect.conn_id, oph->msg);
} else } else {
DEBUGP(DRANAP, "N-DISCONNECT.ind(%u, cause=%i)\n", scu_prim->u.disconnect.conn_id, DEBUGP(DRANAP, "N-DISCONNECT.ind(%u, cause=%i)\n", scu_prim->u.disconnect.conn_id,
scu_prim->u.disconnect.cause); scu_prim->u.disconnect.cause);
bsc_con = get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id);
if (bsc_con) {
/* We might have a connectivity problem. Maybe we need to go
* through the reset procedure again? */
if (scu_prim->u.disconnect.cause == 0)
a_reset_conn_fail(bsc_con->msc->a.reset);
rc = osmo_bsc_sigtran_del_conn(bsc_con);
} }
if (conn)
rc = osmo_bsc_sigtran_del_conn(conn);
break; break;
default: default:
@ -244,9 +241,7 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
enum bsc_con osmo_bsc_sigtran_new_conn(struct gsm_subscriber_connection *conn, struct bsc_msc_data *msc) enum bsc_con osmo_bsc_sigtran_new_conn(struct gsm_subscriber_connection *conn, struct bsc_msc_data *msc)
{ {
struct osmo_ss7_instance *ss7; struct osmo_ss7_instance *ss7;
struct osmo_bsc_sccp_con *bsc_con;
struct gsm_bts *bts = conn_get_bts(conn); struct gsm_bts *bts = conn_get_bts(conn);
int conn_id;
OSMO_ASSERT(conn); OSMO_ASSERT(conn);
OSMO_ASSERT(msc); OSMO_ASSERT(msc);
@ -266,30 +261,13 @@ enum bsc_con osmo_bsc_sigtran_new_conn(struct gsm_subscriber_connection *conn, s
return BSC_CON_REJECT_RF_GRACE; return BSC_CON_REJECT_RF_GRACE;
} }
bsc_con = talloc_zero(bts, struct osmo_bsc_sccp_con); conn->sccp.msc = msc;
if (!bsc_con) {
LOGP(DMSC, LOGL_ERROR, "Failed to allocate new SIGTRAN connection.\n");
return BSC_CON_NO_MEM;
}
bsc_con->msc = msc;
bsc_con->conn = conn;
llist_add_tail(&bsc_con->entry, &active_connections);
conn->sccp_con = bsc_con;
/* Pick a free connection id */
conn_id = pick_free_conn_id(msc);
if (conn_id < 0)
return BSC_CON_REJECT_NO_LINK;
bsc_con->conn_id = conn_id;
LOGP(DMSC, LOGL_NOTICE, "Allocated new connection id: %i\n", conn_id);
return BSC_CON_SUCCESS; return BSC_CON_SUCCESS;
} }
/* Open a new connection oriented sigtran connection */ /* Open a new connection oriented sigtran connection */
int osmo_bsc_sigtran_open_conn(const struct osmo_bsc_sccp_con *conn, struct msgb *msg) int osmo_bsc_sigtran_open_conn(struct gsm_subscriber_connection *conn, struct msgb *msg)
{ {
struct osmo_ss7_instance *ss7; struct osmo_ss7_instance *ss7;
struct bsc_msc_data *msc; struct bsc_msc_data *msc;
@ -298,16 +276,22 @@ int osmo_bsc_sigtran_open_conn(const struct osmo_bsc_sccp_con *conn, struct msgb
OSMO_ASSERT(conn); OSMO_ASSERT(conn);
OSMO_ASSERT(msg); OSMO_ASSERT(msg);
OSMO_ASSERT(conn->msc); OSMO_ASSERT(conn->sccp.msc);
OSMO_ASSERT(conn->sccp.conn_id == -1);
msc = conn->msc; msc = conn->sccp.msc;
if (a_reset_conn_ready(msc->a.reset) == false) { if (a_reset_conn_ready(msc->a.reset) == false) {
LOGP(DMSC, LOGL_ERROR, "MSC is not connected. Dropping.\n"); LOGP(DMSC, LOGL_ERROR, "MSC is not connected. Dropping.\n");
return -EINVAL; return -EINVAL;
} }
conn_id = conn->conn_id; conn->sccp.conn_id = conn_id = pick_free_conn_id(msc);
if (conn->sccp.conn_id < 0) {
LOGP(DMSC, LOGL_ERROR, "Unable to allocate SCCP Connection ID\n");
return -1;
}
LOGP(DMSC, LOGL_DEBUG, "Allocated new connection id: %d\n", conn->sccp.conn_id);
ss7 = osmo_ss7_instance_find(msc->a.cs7_instance); ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
OSMO_ASSERT(ss7); OSMO_ASSERT(ss7);
LOGP(DMSC, LOGL_NOTICE, "Opening new SIGTRAN connection (id=%i) to MSC: %s\n", conn_id, LOGP(DMSC, LOGL_NOTICE, "Opening new SIGTRAN connection (id=%i) to MSC: %s\n", conn_id,
@ -315,12 +299,14 @@ int osmo_bsc_sigtran_open_conn(const struct osmo_bsc_sccp_con *conn, struct msgb
rc = osmo_sccp_tx_conn_req_msg(msc->a.sccp_user, conn_id, &msc->a.bsc_addr, rc = osmo_sccp_tx_conn_req_msg(msc->a.sccp_user, conn_id, &msc->a.bsc_addr,
&msc->a.msc_addr, msg); &msc->a.msc_addr, msg);
if (rc >= 0)
conn->sccp.state = SUBSCR_SCCP_ST_WAIT_CONN_CONF;
return rc; return rc;
} }
/* Send data to MSC */ /* Send data to MSC */
int osmo_bsc_sigtran_send(const struct osmo_bsc_sccp_con *conn, struct msgb *msg) int osmo_bsc_sigtran_send(struct gsm_subscriber_connection *conn, struct msgb *msg)
{ {
struct osmo_ss7_instance *ss7; struct osmo_ss7_instance *ss7;
int conn_id; int conn_id;
@ -329,9 +315,9 @@ int osmo_bsc_sigtran_send(const struct osmo_bsc_sccp_con *conn, struct msgb *msg
OSMO_ASSERT(conn); OSMO_ASSERT(conn);
OSMO_ASSERT(msg); OSMO_ASSERT(msg);
OSMO_ASSERT(conn->msc); OSMO_ASSERT(conn->sccp.msc);
msc = conn->msc; msc = conn->sccp.msc;
/* Log the type of the message we are sending. This is just /* Log the type of the message we are sending. This is just
* informative, do not stop if detecting the type fails */ * informative, do not stop if detecting the type fails */
@ -354,7 +340,7 @@ int osmo_bsc_sigtran_send(const struct osmo_bsc_sccp_con *conn, struct msgb *msg
return -EINVAL; return -EINVAL;
} }
conn_id = conn->conn_id; conn_id = conn->sccp.conn_id;
ss7 = osmo_ss7_instance_find(msc->a.cs7_instance); ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
OSMO_ASSERT(ss7); OSMO_ASSERT(ss7);
@ -369,80 +355,66 @@ int osmo_bsc_sigtran_send(const struct osmo_bsc_sccp_con *conn, struct msgb *msg
/* Delete a connection from the list with open connections /* Delete a connection from the list with open connections
* (called by osmo_bsc_api.c on failing open connections and * (called by osmo_bsc_api.c on failing open connections and
* locally, when a connection is closed by the MSC */ * locally, when a connection is closed by the MSC */
int osmo_bsc_sigtran_del_conn(struct osmo_bsc_sccp_con *conn) int osmo_bsc_sigtran_del_conn(struct gsm_subscriber_connection *conn)
{ {
if (!conn) if (!conn)
return 0; return 0;
if (conn->conn) { LOGP(DMSC, LOGL_ERROR,
LOGP(DMSC, LOGL_ERROR, "sccp connection (id=%i) not cleared (gsm subscriber connection still active) -- forcefully clearing it now!\n", conn->sccp.conn_id);
"sccp connection (id=%i) not cleared (gsm subscriber connection still active) -- forcefully clearing it now!\n",
conn->conn_id);
bsc_subscr_con_free(conn->conn);
conn->conn = NULL;
/* This bahaviour might be caused by a bad connection. Maybe we /* This bahaviour might be caused by a bad connection. Maybe we
* will have to go through the reset procedure again */ * will have to go through the reset procedure again */
a_reset_conn_fail(conn->msc->a.reset); a_reset_conn_fail(conn->sccp.msc->a.reset);
}
/* Remove mgcp context if existant */ /* Remove mgcp context if existant */
if (conn->user_plane.mgcp_ctx) if (conn->user_plane.mgcp_ctx)
mgcp_free_ctx(conn->user_plane.mgcp_ctx); mgcp_free_ctx(conn->user_plane.mgcp_ctx);
llist_del(&conn->entry); /* free the "conn" and make sure any pending lchans are also free'd */
talloc_free(conn); bsc_subscr_con_free(conn);
return 0; return 0;
} }
/* Send an USSD notification in case we loose the connection to the MSC */ /* Send an USSD notification in case we loose the connection to the MSC */
static void bsc_notify_msc_lost(const struct osmo_bsc_sccp_con *conn) static void bsc_notify_msc_lost(struct gsm_subscriber_connection *conn)
{ {
struct gsm_subscriber_connection *subscr_conn;
/* Check if sccp conn is still present */ /* Check if sccp conn is still present */
if (!conn) if (!conn)
return; return;
subscr_conn = conn->conn;
/* send USSD notification if string configured and conn->data is set */
if (!subscr_conn)
return;
/* check for config string */ /* check for config string */
if (!conn->msc->ussd_msc_lost_txt) if (!conn->sccp.msc->ussd_msc_lost_txt)
return; return;
if (conn->msc->ussd_msc_lost_txt[0] == '\0') if (conn->sccp.msc->ussd_msc_lost_txt[0] == '\0')
return; return;
/* send USSD notification */ /* send USSD notification */
bsc_send_ussd_notify(subscr_conn, 1, subscr_conn->sccp_con->msc->ussd_msc_lost_txt); bsc_send_ussd_notify(conn, 1, conn->sccp.msc->ussd_msc_lost_txt);
bsc_send_ussd_release_complete(subscr_conn); bsc_send_ussd_release_complete(conn);
} }
/* Close all open sigtran connections and channels */ /* Close all open sigtran connections and channels */
void osmo_bsc_sigtran_reset(const struct bsc_msc_data *msc) void osmo_bsc_sigtran_reset(const struct bsc_msc_data *msc)
{ {
struct osmo_bsc_sccp_con *conn; struct gsm_subscriber_connection *conn, *conn_temp;
struct osmo_bsc_sccp_con *conn_temp;
OSMO_ASSERT(msc); OSMO_ASSERT(msc);
/* Close all open connections */ /* Close all open connections */
llist_for_each_entry_safe(conn, conn_temp, &active_connections, entry) { llist_for_each_entry_safe(conn, conn_temp, &bsc_gsmnet->subscr_conns, entry) {
/* We only may close connections which actually belong to this /* We only may close connections which actually belong to this
* MSC. All other open connections are left untouched */ * MSC. All other open connections are left untouched */
if (conn->msc == msc) { if (conn->sccp.msc == msc) {
/* Notify active connection users via USSD that the MSC is down */ /* Notify active connection users via USSD that the MSC is down */
bsc_notify_msc_lost(conn); bsc_notify_msc_lost(conn);
/* Take down all occopied RF channels */ /* Take down all occopied RF channels */
if (conn->conn) gsm0808_clear(conn);
gsm0808_clear(conn->conn);
/* Disconnect all Sigtran connections */ /* Disconnect all Sigtran connections */
osmo_sccp_tx_disconn(msc->a.sccp_user, conn->conn_id, &msc->a.bsc_addr, 0); osmo_sccp_tx_disconn(msc->a.sccp_user, conn->sccp.conn_id, &msc->a.bsc_addr, 0);
/* Delete subscriber connection */ /* Delete subscriber connection */
osmo_bsc_sigtran_del_conn(conn); osmo_bsc_sigtran_del_conn(conn);

View File

@ -124,17 +124,14 @@ static void test_scan(void)
struct gsm_network *net = bsc_network_init(NULL, 1, 1); struct gsm_network *net = bsc_network_init(NULL, 1, 1);
struct gsm_bts *bts = gsm_bts_alloc(net, 0); struct gsm_bts *bts = gsm_bts_alloc(net, 0);
struct osmo_bsc_sccp_con *sccp_con;
struct bsc_msc_data *msc; struct bsc_msc_data *msc;
struct gsm_subscriber_connection *conn; struct gsm_subscriber_connection *conn;
sccp_con = talloc_zero(net, struct osmo_bsc_sccp_con);
msc = talloc_zero(net, struct bsc_msc_data); msc = talloc_zero(net, struct bsc_msc_data);
conn = talloc_zero(net, struct gsm_subscriber_connection); conn = talloc_zero(net, struct gsm_subscriber_connection);
bts->network = net; bts->network = net;
sccp_con->msc = msc; conn->sccp.msc = msc;
conn->sccp_con = sccp_con;
conn->lchan = &bts->c0->ts[1].lchan[0]; conn->lchan = &bts->c0->ts[1].lchan[0];
/* start testing with proper messages */ /* start testing with proper messages */

View File

@ -80,22 +80,23 @@ struct {
}, },
}; };
struct gsm_network *bsc_gsmnet;
void test_cell_identifier() void test_cell_identifier()
{ {
int i; int i;
int rc; int rc;
struct gsm_network *net;
struct bsc_msc_data *msc; struct bsc_msc_data *msc;
struct gsm_bts *bts; struct gsm_bts *bts;
net = bsc_network_init(NULL, 1, 1); bsc_gsmnet = bsc_network_init(NULL, 1, 1);
net->bsc_data->rf_ctrl = talloc_zero(NULL, struct osmo_bsc_rf); bsc_gsmnet->bsc_data->rf_ctrl = talloc_zero(NULL, struct osmo_bsc_rf);
net->bsc_data->rf_ctrl->policy = S_RF_ON; bsc_gsmnet->bsc_data->rf_ctrl->policy = S_RF_ON;
msc = talloc_zero(net, struct bsc_msc_data); msc = talloc_zero(bsc_gsmnet, struct bsc_msc_data);
msc->network = net; msc->network = bsc_gsmnet;
bts = gsm_bts_alloc_register(net, GSM_BTS_TYPE_UNKNOWN, 0); bts = gsm_bts_alloc_register(bsc_gsmnet, GSM_BTS_TYPE_UNKNOWN, 0);
if (bts == NULL) { if (bts == NULL) {
fprintf(stderr, "gsm_bts_alloc_register() returned NULL\n"); fprintf(stderr, "gsm_bts_alloc_register() returned NULL\n");
return; return;