mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
synced 2025-11-01 20:43:47 +00:00
[bssap] First go at implementing ASSIGNMENT REQUEST
This commit is contained in:
@@ -157,9 +157,9 @@ enum GSM0808_IE_CODING {
|
||||
GSM0808_IE_RESERVED_1 = 15,
|
||||
GSM0808_IE_RESERVED_2 = 16,
|
||||
GSM0808_IE_RESERVED_3 = 17,
|
||||
GSM0808_IE_CLASSMARK_INFORMATION_TYPE_2 = 18,
|
||||
GSM0808_IE_CLASSMARK_INFORMATION_TYPE_3 = 19,
|
||||
GSM0808_IE_INTERFERENCE_BAND_TO_BE_USED = 20,
|
||||
GSM0808_IE_CLASSMARK_INFORMATION_T2 = 18,
|
||||
GSM0808_IE_CLASSMARK_INFORMATION_T3 = 19,
|
||||
GSM0808_IE_INTERFERENCE_BAND_TO_USE = 20,
|
||||
GSM0808_IE_RR_CAUSE = 21,
|
||||
GSM0808_IE_RESERVED_4 = 22,
|
||||
GSM0808_IE_LAYER_3_INFORMATION = 23,
|
||||
@@ -196,13 +196,13 @@ enum GSM0808_IE_CODING {
|
||||
GSM0808_IE_CONNECTION_RELEASE_RQSTED = 54,
|
||||
GSM0808_IE_GROUP_CALL_REFERENCE = 55,
|
||||
GSM0808_IE_EMLPP_PRIORITY = 56,
|
||||
GSM0808_IE_CONFIGURATION_EVOLUTION_INDICATION = 57,
|
||||
GSM0808_IE_CONFIG_EVO_INDI = 57,
|
||||
GSM0808_IE_OLD_BSS_TO_NEW_BSS_INFORMATION = 58,
|
||||
GSM0808_IE_LSA_IDENTIFIER = 59,
|
||||
GSM0808_IE_LSA_IDENTIFIER_LIST = 60,
|
||||
GSM0808_IE_LSA_INFORMATION = 61,
|
||||
GSM0808_IE_LCS_QOS = 62,
|
||||
GSM0808_IE_LSA_ACCESS_CONTROL_SUPPRESSION = 63,
|
||||
GSM0808_IE_LSA_ACCESS_CTRL_SUPPR = 63,
|
||||
GSM0808_IE_LCS_PRIORITY = 67,
|
||||
GSM0808_IE_LOCATION_TYPE = 68,
|
||||
GSM0808_IE_LOCATION_ESTIMATE = 69,
|
||||
@@ -274,6 +274,11 @@ struct msgb *bssmap_create_clear_complete(void);
|
||||
struct msgb *bssmap_create_cipher_complete(struct msgb *layer3, int bsc_enc_algo);
|
||||
struct msgb *bssmap_create_cipher_reject(u_int8_t cause);
|
||||
struct msgb *bssmap_create_sapi_reject(u_int8_t link_id);
|
||||
struct msgb *bssmap_create_assignment_completed(struct gsm_lchan *lchan, u_int8_t rr_cause);
|
||||
struct msgb *bssmap_create_assignment_failure(u_int8_t cause, u_int8_t *rr_cause);
|
||||
|
||||
void gsm0808_send_assignment_failure(struct gsm_lchan *l, u_int8_t cause, u_int8_t *rr_value);
|
||||
void gsm0808_send_assignment_compl(struct gsm_lchan *l, u_int8_t rr_value);
|
||||
|
||||
int dtap_rcvmsg(struct gsm_lchan *lchan, struct msgb *msg, unsigned int length);
|
||||
struct msgb *dtap_create_msg(struct msgb *msg_l3, u_int8_t link_id);
|
||||
|
||||
@@ -122,6 +122,15 @@ struct bss_sccp_connection_data {
|
||||
struct sccp_connection *sccp;
|
||||
int ciphering_handled : 1;
|
||||
|
||||
/* Timers... */
|
||||
|
||||
/* for assginment command */
|
||||
struct timer_list T10;
|
||||
|
||||
/* audio handling */
|
||||
int rtp_port;
|
||||
int rtp_payload2;
|
||||
|
||||
/* Queue SCCP and GSM0408 messages */
|
||||
struct llist_head gsm_queue;
|
||||
unsigned int gsm_queue_size;
|
||||
@@ -130,6 +139,7 @@ struct bss_sccp_connection_data {
|
||||
unsigned int sccp_queue_size;
|
||||
};
|
||||
|
||||
#define GSM0808_T10_VALUE 6, 0
|
||||
#define sccp_get_lchan(data_ctx) ((struct bss_sccp_connection_data *)data_ctx)->lchan
|
||||
#define lchan_get_sccp(lchan) lchan->msc_data->sccp
|
||||
struct bss_sccp_connection_data *bss_sccp_create_data();
|
||||
|
||||
@@ -52,6 +52,7 @@ struct gsm_network *bsc_gsmnet = 0;
|
||||
static const char *config_file = "openbsc.cfg";
|
||||
static char *msc_address = "127.0.0.1";
|
||||
static struct bsc_fd msc_connection;
|
||||
static struct in_addr local_addr;
|
||||
extern int ipacc_rtp_direct;
|
||||
|
||||
extern int bsc_bootstrap_network(int (*layer4)(struct gsm_network *, int, void *), const char *cfg_file);
|
||||
@@ -74,6 +75,7 @@ struct bss_sccp_connection_data *bss_sccp_create_data()
|
||||
|
||||
void bss_sccp_free_data(struct bss_sccp_connection_data *data)
|
||||
{
|
||||
bsc_del_timer(&data->T10);
|
||||
bsc_free_queued(data->sccp);
|
||||
bts_free_queued(data);
|
||||
talloc_free(data);
|
||||
@@ -267,6 +269,67 @@ static int handle_cipher_m_complete(struct msgb *msg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Receive a ASSIGNMENT COMPLETE */
|
||||
static int handle_ass_compl(struct msgb *msg)
|
||||
{
|
||||
struct gsm48_hdr *gh = msgb_l3(msg);
|
||||
|
||||
DEBUGP(DMSC, "ASSIGNMENT COMPLETE from MS, forwarding to MSC\n");
|
||||
|
||||
if (!msg->lchan->msc_data) {
|
||||
DEBUGP(DMSC, "No MSC data\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msgb_l3len(msg) - sizeof(*gh) != 1) {
|
||||
DEBUGP(DMSC, "assignment failure invalid: %d\n",
|
||||
msgb_l3len(msg) - sizeof(*gh));
|
||||
return -1;
|
||||
}
|
||||
gsm0808_send_assignment_compl(msg->lchan, gh->data[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive a ASSIGNMENT FAILURE. If the message is failed
|
||||
* to be parsed the T10 timer will send the failure.
|
||||
*/
|
||||
static int handle_ass_fail(struct msgb *msg)
|
||||
{
|
||||
struct gsm48_hdr *gh = msgb_l3(msg);
|
||||
|
||||
DEBUGP(DMSC, "ASSIGNMENT FAILURE from MS, forwarding to MSC\n");
|
||||
if (!msg->lchan->msc_data) {
|
||||
DEBUGP(DMSC, "No MSC data\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msgb_l3len(msg) - sizeof(*gh) != 1) {
|
||||
DEBUGP(DMSC, "assignment failure invalid: %d\n",
|
||||
msgb_l3len(msg) - sizeof(*gh));
|
||||
return -1;
|
||||
}
|
||||
|
||||
gsm0808_send_assignment_failure(msg->lchan,
|
||||
GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE, &gh->data[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive a GSM04.08 MODIFY ACK. Actually we have to check
|
||||
* the content to see if this was a success or not.
|
||||
*/
|
||||
static int handle_modify_ack(struct msgb *msg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* modify RSL */
|
||||
rc = gsm48_rx_rr_modif_ack(msg);
|
||||
|
||||
gsm0808_send_assignment_compl(msg->lchan, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Receive a GSM 04.08 Radio Resource (RR) message */
|
||||
static int gsm0408_rcv_rr(struct msgb *msg)
|
||||
{
|
||||
@@ -284,6 +347,15 @@ static int gsm0408_rcv_rr(struct msgb *msg)
|
||||
case GSM48_MT_RR_CIPH_M_COMPL:
|
||||
rc = handle_cipher_m_complete(msg);
|
||||
break;
|
||||
case GSM48_MT_RR_ASS_COMPL:
|
||||
rc = handle_ass_compl(msg);
|
||||
break;
|
||||
case GSM48_MT_RR_ASS_FAIL:
|
||||
rc = handle_ass_fail(msg);
|
||||
break;
|
||||
case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
|
||||
rc = handle_modify_ack(msg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -345,6 +417,43 @@ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* handle ipaccess signals */
|
||||
static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
|
||||
void *handler_data, void *signal_data)
|
||||
{
|
||||
struct gsm_lchan *lchan = signal_data;
|
||||
struct gsm_bts_trx_ts *ts;
|
||||
int rc;
|
||||
|
||||
if (subsys != SS_ABISIP)
|
||||
return 0;
|
||||
|
||||
ts = lchan->ts;
|
||||
|
||||
switch (signal) {
|
||||
case S_ABISIP_CRCX_ACK:
|
||||
/* we can ask it to connect now */
|
||||
if (lchan->msc_data) {
|
||||
DEBUGP(DMSC, "Connecting BTS to port: %d conn: %d\n",
|
||||
lchan->msc_data->rtp_port, ts->abis_ip.conn_id);
|
||||
|
||||
rc = rsl_ipacc_mdcx(lchan, ntohl(local_addr.s_addr),
|
||||
lchan->msc_data->rtp_port,
|
||||
ts->abis_ip.conn_id,
|
||||
lchan->msc_data->rtp_payload2);
|
||||
if (rc < 0) {
|
||||
DEBUGP(DMSC, "Failed to send connect: %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case S_ABISIP_DLCX_IND:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_usage()
|
||||
{
|
||||
printf("Usage: bsc_hack\n");
|
||||
@@ -522,6 +631,7 @@ static void print_help()
|
||||
printf(" -s --disable-color\n");
|
||||
printf(" -c --config-file filename The config file to use.\n");
|
||||
printf(" -m --msc=IP. The address of the MSC.\n");
|
||||
printf(" -l --local=IP. The local address of the MGCP.\n");
|
||||
}
|
||||
|
||||
static void handle_options(int argc, char** argv)
|
||||
@@ -536,10 +646,11 @@ static void handle_options(int argc, char** argv)
|
||||
{"timestamp", 0, 0, 'T'},
|
||||
{"rtp-proxy", 0, 0, 'P'},
|
||||
{"msc", 1, 0, 'm'},
|
||||
{"local", 1, 0, 'l'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_long(argc, argv, "hd:sTPc:m:",
|
||||
c = getopt_long(argc, argv, "hd:sTPc:m:l:",
|
||||
long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
@@ -567,6 +678,9 @@ static void handle_options(int argc, char** argv)
|
||||
case 'm':
|
||||
msc_address = strdup(optarg);
|
||||
break;
|
||||
case 'l':
|
||||
inet_aton(optarg, &local_addr);
|
||||
break;
|
||||
default:
|
||||
/* ignore */
|
||||
break;
|
||||
@@ -612,6 +726,9 @@ int main(int argc, char **argv)
|
||||
sccp_connection_set_incoming(&sccp_ssn_bssap, msc_sccp_accept, NULL);
|
||||
sccp_set_read(&sccp_ssn_bssap, msc_sccp_read, NULL);
|
||||
|
||||
/* initialize ipaccess handling */
|
||||
register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL);
|
||||
|
||||
rc = connect_to_msc(msc_address, 5000);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "Opening the MSC connection failed.\n");
|
||||
|
||||
@@ -44,6 +44,17 @@ static const struct tlv_definition bss_att_tlvdef = {
|
||||
[GSM0808_IE_CELL_IDENTIFIER_LIST] = { TLV_TYPE_TLV },
|
||||
[GSM0808_IE_CHANNEL_NEEDED] = { TLV_TYPE_TV },
|
||||
[GSM0808_IE_EMLPP_PRIORITY] = { TLV_TYPE_TV },
|
||||
[GSM0808_IE_CHANNEL_TYPE] = { TLV_TYPE_TLV },
|
||||
[GSM0808_IE_PRIORITY] = { TLV_TYPE_TLV },
|
||||
[GSM0808_IE_CIRCUIT_IDENTITY_CODE] = { TLV_TYPE_TV },
|
||||
[GSM0808_IE_DOWNLINK_DTX_FLAG] = { TLV_TYPE_TV },
|
||||
[GSM0808_IE_INTERFERENCE_BAND_TO_USE] = { TLV_TYPE_TV },
|
||||
[GSM0808_IE_CLASSMARK_INFORMATION_T2] = { TLV_TYPE_TLV },
|
||||
[GSM0808_IE_GROUP_CALL_REFERENCE] = { TLV_TYPE_TLV },
|
||||
[GSM0808_IE_TALKER_FLAG] = { TLV_TYPE_T },
|
||||
[GSM0808_IE_CONFIG_EVO_INDI] = { TLV_TYPE_TV },
|
||||
[GSM0808_IE_LSA_ACCESS_CTRL_SUPPR] = { TLV_TYPE_TV },
|
||||
[GSM0808_IE_SERVICE_HANDOVER] = { TLV_TYPE_TV},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -151,6 +162,7 @@ static int bssmap_handle_clear_command(struct sccp_connection *conn,
|
||||
|
||||
if (msg->lchan) {
|
||||
DEBUGP(DMSC, "Releasing all transactions on %p\n", conn);
|
||||
bsc_del_timer(&msg->lchan->msc_data->T10);
|
||||
msg->lchan->msc_data->lchan = NULL;
|
||||
msg->lchan->msc_data = NULL;
|
||||
put_lchan(msg->lchan);
|
||||
@@ -210,6 +222,75 @@ reject:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the network configurable T10 parameter
|
||||
*/
|
||||
static void bssmap_t10_fired(void *_conn)
|
||||
{
|
||||
struct sccp_connection *conn = (struct sccp_connection *) _conn;
|
||||
struct msgb *resp;
|
||||
|
||||
DEBUGP(DMSC, "T10 fired, assignment failed: %p\n", conn);
|
||||
resp = bssmap_create_assignment_failure(
|
||||
GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
|
||||
if (!resp) {
|
||||
DEBUGP(DMSC, "Allocation failure: %p\n", conn);
|
||||
return;
|
||||
}
|
||||
|
||||
bsc_queue_connection_write(conn, resp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the assignment request message.
|
||||
*
|
||||
* See §3.2.1.1 for the message type
|
||||
*/
|
||||
static int bssmap_handle_assignm_req(struct sccp_connection *conn,
|
||||
struct msgb *msg, unsigned int length)
|
||||
{
|
||||
struct tlv_parsed tp;
|
||||
struct bss_sccp_connection_data *msc_data;
|
||||
int ret = 0;
|
||||
|
||||
if (!msg->lchan || !msg->lchan->msc_data) {
|
||||
DEBUGP(DMSC, "No lchan/msc_data in cipher mode command.\n");
|
||||
goto reject;
|
||||
}
|
||||
|
||||
msc_data = msg->lchan->msc_data;
|
||||
tlv_parse(&tp, &bss_att_tlvdef, msg->l4h + 1, length - 1, 0, 0);
|
||||
|
||||
if (!TLVP_PRESENT(&tp, GSM0808_IE_CHANNEL_TYPE)) {
|
||||
DEBUGP(DMSC, "Mandantory channel type not present.\n");
|
||||
goto reject;
|
||||
}
|
||||
|
||||
if (!TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) {
|
||||
DEBUGP(DMSC, "Identity code missing. Audio routing will not work.\n");
|
||||
goto reject;
|
||||
}
|
||||
|
||||
/*
|
||||
* currently only activation of speach on the
|
||||
* existing channel is supported. This means we
|
||||
* will send a Channel Modify message and take it
|
||||
* from there.
|
||||
* Setup channel type, timer
|
||||
*/
|
||||
//gsm48_lchan_modify();
|
||||
|
||||
msc_data->T10.cb = bssmap_t10_fired;
|
||||
msc_data->T10.data = conn;
|
||||
bsc_schedule_timer(&msc_data->T10, GSM0808_T10_VALUE);
|
||||
return ret;
|
||||
|
||||
reject:
|
||||
gsm0808_send_assignment_failure(msg->lchan,
|
||||
GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bssmap_rcvmsg_udt(struct gsm_network *net, struct msgb *msg, unsigned int length)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -247,6 +328,9 @@ int bssmap_rcvmsg_dt1(struct sccp_connection *conn, struct msgb *msg, unsigned i
|
||||
case BSS_MAP_MSG_CIPHER_MODE_CMD:
|
||||
ret = bssmap_handle_cipher_mode(conn, msg, length);
|
||||
break;
|
||||
case BSS_MAP_MSG_ASSIGMENT_RQST:
|
||||
ret = bssmap_handle_assignm_req(conn, msg, length);
|
||||
break;
|
||||
default:
|
||||
DEBUGP(DMSC, "Unimplemented msg type: %d\n", msg->l4h[0]);
|
||||
break;
|
||||
@@ -442,6 +526,156 @@ struct msgb *bssmap_create_sapi_reject(u_int8_t link_id)
|
||||
return msg;
|
||||
}
|
||||
|
||||
static u_int8_t chan_mode_to_speech(enum gsm48_chan_mode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case GSM48_CMODE_SPEECH_V1:
|
||||
return 1;
|
||||
break;
|
||||
case GSM48_CMODE_SPEECH_EFR:
|
||||
return 0x11;
|
||||
break;
|
||||
case GSM48_CMODE_SPEECH_AMR:
|
||||
return 0x21;
|
||||
break;
|
||||
case GSM48_CMODE_SIGN:
|
||||
case GSM48_CMODE_DATA_14k5:
|
||||
case GSM48_CMODE_DATA_12k0:
|
||||
case GSM48_CMODE_DATA_6k0:
|
||||
case GSM48_CMODE_DATA_3k6:
|
||||
default:
|
||||
DEBUGP(DMSC, "Using non speech mode: %d\n", mode);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* 3.2.2.33 */
|
||||
static u_int8_t lchan_to_chosen_channel(struct gsm_lchan *lchan)
|
||||
{
|
||||
u_int8_t channel_mode = 0, channel = 0;
|
||||
|
||||
switch (lchan->tch_mode) {
|
||||
case GSM48_CMODE_SPEECH_V1:
|
||||
case GSM48_CMODE_SPEECH_EFR:
|
||||
case GSM48_CMODE_SPEECH_AMR:
|
||||
channel_mode = 0x9;
|
||||
break;
|
||||
case GSM48_CMODE_SIGN:
|
||||
channel_mode = 0x8;
|
||||
break;
|
||||
case GSM48_CMODE_DATA_14k5:
|
||||
channel_mode = 0xe;
|
||||
break;
|
||||
case GSM48_CMODE_DATA_12k0:
|
||||
channel_mode = 0xb;
|
||||
break;
|
||||
case GSM48_CMODE_DATA_6k0:
|
||||
channel_mode = 0xc;
|
||||
break;
|
||||
case GSM48_CMODE_DATA_3k6:
|
||||
channel_mode = 0xd;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (lchan->type) {
|
||||
case GSM_LCHAN_NONE:
|
||||
channel = 0x0;
|
||||
break;
|
||||
case GSM_LCHAN_SDCCH:
|
||||
channel = 0x1;
|
||||
break;
|
||||
case GSM_LCHAN_TCH_F:
|
||||
channel = 0x8;
|
||||
break;
|
||||
case GSM_LCHAN_TCH_H:
|
||||
channel = 0x9;
|
||||
break;
|
||||
case GSM_LCHAN_UNKNOWN:
|
||||
DEBUGP(DMSC, "Unknown lchan type: %p\n", lchan);
|
||||
break;
|
||||
}
|
||||
|
||||
return channel_mode << 4 | channel;
|
||||
}
|
||||
|
||||
struct msgb *bssmap_create_assignment_completed(struct gsm_lchan *lchan, u_int8_t rr_cause)
|
||||
{
|
||||
u_int8_t *data;
|
||||
u_int8_t speech_mode;
|
||||
|
||||
struct msgb *msg = msgb_alloc(35, "bssmap: ass compl");
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
msg->l3h = msgb_put(msg, 3);
|
||||
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
|
||||
msg->l3h[1] = 0xff;
|
||||
msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_COMPLETE;
|
||||
|
||||
/* write 3.2.2.22 */
|
||||
data = msgb_put(msg, 2);
|
||||
data[0] = GSM0808_IE_RR_CAUSE;
|
||||
data[1] = rr_cause;
|
||||
|
||||
/* write cirtcuit identity code 3.2.2.2 */
|
||||
/* write cell identifier 3.2.2.17 */
|
||||
/* write chosen channel 3.2.2.33 when BTS picked it */
|
||||
data = msgb_put(msg, 2);
|
||||
data[0] = GSM0808_IE_CHOSEN_CHANNEL;
|
||||
data[1] = lchan_to_chosen_channel(lchan);
|
||||
|
||||
/* write chosen encryption algorithm 3.2.2.44 */
|
||||
data = msgb_put(msg, 2);
|
||||
data[0] = GSM0808_IE_CHOSEN_ENCR_ALG;
|
||||
data[1] = RSL_ENC_ALG_A5(lchan->encr.alg_id);
|
||||
|
||||
/* write circuit pool 3.2.2.45 */
|
||||
/* write speech version chosen: 3.2.2.51 when BTS picked it */
|
||||
speech_mode = chan_mode_to_speech(lchan->tch_mode);
|
||||
if (speech_mode != 0) {
|
||||
data = msgb_put(msg, 2);
|
||||
data[0] = GSM0808_IE_SPEECH_VERSION;
|
||||
data[1] = speech_mode;
|
||||
}
|
||||
|
||||
/* write LSA identifier 3.2.2.15 */
|
||||
|
||||
|
||||
/* update the size */
|
||||
msg->l3h[1] = msgb_l3len(msg) - 2;
|
||||
return msg;
|
||||
}
|
||||
|
||||
struct msgb *bssmap_create_assignment_failure(u_int8_t cause, u_int8_t *rr_cause)
|
||||
{
|
||||
u_int8_t *data;
|
||||
struct msgb *msg = msgb_alloc(35, "bssmap: ass fail");
|
||||
if (!msg)
|
||||
return NULL;
|
||||
|
||||
msg->l3h = msgb_put(msg, 5);
|
||||
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
|
||||
msg->l3h[1] = 0xff;
|
||||
msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_FAILURE;
|
||||
msg->l3h[3] = GSM0808_IE_CAUSE;
|
||||
msg->l3h[4] = cause;
|
||||
|
||||
/* RR cause 3.2.2.22 */
|
||||
if (rr_cause) {
|
||||
data = msgb_put(msg, 2);
|
||||
data[0] = GSM0808_IE_RR_CAUSE;
|
||||
data[1] = *rr_cause;
|
||||
}
|
||||
|
||||
/* Circuit pool 3.22.45 */
|
||||
/* Circuit pool list 3.2.2.46 */
|
||||
|
||||
/* update the size */
|
||||
msg->l3h[1] = msgb_l3len(msg) - 2;
|
||||
return msg;
|
||||
}
|
||||
|
||||
struct msgb *dtap_create_msg(struct msgb *msg_l3, u_int8_t link_id)
|
||||
{
|
||||
struct dtap_header *header;
|
||||
@@ -484,6 +718,7 @@ static int bssap_handle_lchan_signal(unsigned int subsys, unsigned int signal,
|
||||
if (!lchan || !lchan->msc_data)
|
||||
return 0;
|
||||
|
||||
bsc_del_timer(&lchan->msc_data->T10);
|
||||
conn = lchan->msc_data->sccp;
|
||||
lchan->msc_data->lchan = NULL;
|
||||
lchan->msc_data = NULL;
|
||||
@@ -667,6 +902,34 @@ void bts_send_queued(struct bss_sccp_connection_data *data)
|
||||
data->gsm_queue_size = 0;
|
||||
}
|
||||
|
||||
void gsm0808_send_assignment_failure(struct gsm_lchan *lchan, u_int8_t cause, u_int8_t *rr_value)
|
||||
{
|
||||
struct msgb *resp;
|
||||
|
||||
bsc_del_timer(&lchan->msc_data->T10);
|
||||
resp = bssmap_create_assignment_failure(cause, rr_value);
|
||||
if (!resp) {
|
||||
DEBUGP(DMSC, "Allocation failure: %p\n", lchan_get_sccp(lchan));
|
||||
return;
|
||||
}
|
||||
|
||||
bsc_queue_connection_write(lchan_get_sccp(lchan), resp);
|
||||
}
|
||||
|
||||
void gsm0808_send_assignment_compl(struct gsm_lchan *lchan, u_int8_t rr_cause)
|
||||
{
|
||||
struct msgb *resp;
|
||||
|
||||
bsc_del_timer(&lchan->msc_data->T10);
|
||||
resp = bssmap_create_assignment_completed(lchan, rr_cause);
|
||||
if (!resp) {
|
||||
DEBUGP(DMSC, "Creating MSC response failed: %p\n", lchan_get_sccp(lchan));
|
||||
return;
|
||||
}
|
||||
|
||||
bsc_queue_connection_write(lchan_get_sccp(lchan), resp);
|
||||
}
|
||||
|
||||
static __attribute__((constructor)) void on_dso_load_bssap(void)
|
||||
{
|
||||
register_signal_handler(SS_LCHAN, bssap_handle_lchan_signal, NULL);
|
||||
|
||||
Reference in New Issue
Block a user