mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
synced 2025-11-02 04:53:24 +00:00
Compare commits
42 Commits
on-waves/0
...
on-waves/0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b4e366083 | ||
|
|
bf1eb64b02 | ||
|
|
f0fbae94ea | ||
|
|
8fe4df503c | ||
|
|
8da7103070 | ||
|
|
f73f6fad8c | ||
|
|
25cb84be12 | ||
|
|
d9ae25c1bf | ||
|
|
5c011366c9 | ||
|
|
79e2d4230d | ||
|
|
8ecd029b12 | ||
|
|
3c0508e94a | ||
|
|
f535aad612 | ||
|
|
d0ac8866f1 | ||
|
|
73f9a65f12 | ||
|
|
b2c55c49a8 | ||
|
|
8dc241959c | ||
|
|
f99709430a | ||
|
|
b9bc45b1b0 | ||
|
|
65d10c1320 | ||
|
|
414ba77f75 | ||
|
|
59f2470650 | ||
|
|
339dfdb624 | ||
|
|
9e2e2e04d1 | ||
|
|
2ab6db0153 | ||
|
|
6cb97bdebe | ||
|
|
8c3694a282 | ||
|
|
191d23a889 | ||
|
|
a5963097ac | ||
|
|
221fb37518 | ||
|
|
4ec8a390cc | ||
|
|
cf3f1c8b3d | ||
|
|
984f3b8047 | ||
|
|
ec1f15d513 | ||
|
|
b76cd5ed7e | ||
|
|
1592550d98 | ||
|
|
5cdf42b1a4 | ||
|
|
3a6b1a41fb | ||
|
|
1b5b3bbfdb | ||
|
|
3a67035411 | ||
|
|
cb1937a4c5 | ||
|
|
3cfd5d6a02 |
@@ -1,7 +1,7 @@
|
||||
dnl Process this file with autoconf to produce a configure script
|
||||
AC_INIT
|
||||
|
||||
AM_INIT_AUTOMAKE(openbsc, 0.3.92onwaves)
|
||||
AM_INIT_AUTOMAKE(openbsc, 0.3.94onwaves)
|
||||
|
||||
dnl kernel style compile messages
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
|
||||
@@ -70,10 +70,12 @@ u_int64_t str_to_imsi(const char *imsi_str);
|
||||
u_int8_t lchan2chan_nr(const struct gsm_lchan *lchan);
|
||||
int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id, u_int8_t release_reason);
|
||||
|
||||
int rsl_lchan_set_state(struct gsm_lchan *lchan, int);
|
||||
|
||||
/* to be provided by external code */
|
||||
int abis_rsl_sendmsg(struct msgb *msg);
|
||||
int rsl_deact_sacch(struct gsm_lchan *lchan);
|
||||
int rsl_chan_release(struct gsm_lchan *lchan);
|
||||
int rsl_lchan_rll_release(struct gsm_lchan *lchan, u_int8_t link_id);
|
||||
|
||||
/* BCCH related code */
|
||||
int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf);
|
||||
|
||||
@@ -158,6 +158,9 @@ struct bsc_nat {
|
||||
u_int8_t mgcp_msg[4096];
|
||||
int mgcp_length;
|
||||
|
||||
/* msc things */
|
||||
int first_contact;
|
||||
|
||||
struct bsc_endpoint *bsc_endpoints;
|
||||
};
|
||||
|
||||
@@ -193,7 +196,6 @@ struct sccp_connections *patch_sccp_src_ref_to_msc(struct msgb *, struct bsc_nat
|
||||
/**
|
||||
* MGCP/Audio handling
|
||||
*/
|
||||
int bsc_write_mgcp_msg(struct bsc_connection *bsc, struct msgb *msg);
|
||||
int bsc_write_mgcp(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length);
|
||||
int bsc_mgcp_assign(struct sccp_connections *, struct msgb *msg);
|
||||
void bsc_mgcp_clear(struct sccp_connections *);
|
||||
@@ -209,4 +211,7 @@ void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc);
|
||||
int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60]);
|
||||
int bsc_mgcp_extract_ci(const char *resp);
|
||||
|
||||
|
||||
int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int id);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -326,7 +326,6 @@ void bsc_queue_connection_write(struct sccp_connection *conn, struct msgb *msg);
|
||||
void bsc_free_queued(struct sccp_connection *conn);
|
||||
void bsc_send_queued(struct sccp_connection *conn);
|
||||
|
||||
void bts_queue_send(struct msgb *msg, int link_id);
|
||||
void bts_send_queued(struct bss_sccp_connection_data*);
|
||||
void bts_free_queued(struct bss_sccp_connection_data*);
|
||||
void bts_unblock_queue(struct bss_sccp_connection_data*);
|
||||
|
||||
@@ -198,6 +198,7 @@ enum gsm_lchan_state {
|
||||
LCHAN_S_ACT_REQ, /* channel activatin requested */
|
||||
LCHAN_S_ACTIVE, /* channel is active and operational */
|
||||
LCHAN_S_REL_REQ, /* channel release has been requested */
|
||||
LCHAN_S_REL_ERR, /* channel is in an error state */
|
||||
LCHAN_S_INACTIVE, /* channel is set inactive */
|
||||
};
|
||||
|
||||
@@ -246,6 +247,8 @@ struct gsm_lchan {
|
||||
} encr;
|
||||
|
||||
struct timer_list T3101;
|
||||
struct timer_list T3111;
|
||||
struct timer_list error_timer;
|
||||
|
||||
/* AMR bits */
|
||||
struct gsm48_multi_rate_conf mr_conf;
|
||||
@@ -278,6 +281,9 @@ struct gsm_lchan {
|
||||
} abis_ip;
|
||||
|
||||
struct gsm_subscriber_connection conn;
|
||||
|
||||
/* release reason */
|
||||
u_int8_t release_reason;
|
||||
};
|
||||
|
||||
struct gsm_e1_subslot {
|
||||
|
||||
@@ -104,6 +104,9 @@ struct mgcp_config {
|
||||
unsigned int number_endpoints;
|
||||
struct mgcp_endpoint *endpoints;
|
||||
|
||||
/* spec handling */
|
||||
int force_realloc;
|
||||
|
||||
/* callback functionality */
|
||||
mgcp_change change_cb;
|
||||
mgcp_policy policy_cb;
|
||||
|
||||
@@ -57,6 +57,10 @@ struct mgcp_endpoint {
|
||||
|
||||
/* backpointer */
|
||||
struct mgcp_config *cfg;
|
||||
|
||||
/* statistics */
|
||||
unsigned int in_bts;
|
||||
unsigned int in_remote;
|
||||
};
|
||||
|
||||
#define ENDPOINT_NUMBER(endp) abs(endp - endp->cfg->endpoints)
|
||||
|
||||
@@ -568,12 +568,33 @@ int rsl_deact_sacch(struct gsm_lchan *lchan)
|
||||
return abis_rsl_sendmsg(msg);
|
||||
}
|
||||
|
||||
static void error_timeout_cb(void *data)
|
||||
{
|
||||
struct gsm_lchan *lchan = data;
|
||||
if (lchan->state != LCHAN_S_REL_ERR) {
|
||||
LOGP(DRSL, LOGL_ERROR, "%s error timeout but not in error state: %d\n",
|
||||
gsm_lchan_name(lchan), lchan->state);
|
||||
return;
|
||||
}
|
||||
|
||||
/* go back to the none state */
|
||||
LOGP(DRSL, LOGL_NOTICE, "%s is back in operation.\n", gsm_lchan_name(lchan));
|
||||
rsl_lchan_set_state(lchan, LCHAN_S_NONE);
|
||||
}
|
||||
|
||||
/* Chapter 8.4.14 / 4.7: Tell BTS to release the radio channel */
|
||||
int rsl_rf_chan_release(struct gsm_lchan *lchan)
|
||||
static int rsl_rf_chan_release(struct gsm_lchan *lchan, int error)
|
||||
{
|
||||
struct abis_rsl_dchan_hdr *dh;
|
||||
struct msgb *msg = rsl_msgb_alloc();
|
||||
struct msgb *msg;
|
||||
|
||||
if (lchan->state == LCHAN_S_REL_ERR) {
|
||||
LOGP(DRSL, LOGL_NOTICE, "%s is in error state not sending release.\n",
|
||||
gsm_lchan_name(lchan));
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg = rsl_msgb_alloc();
|
||||
dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
|
||||
init_dchan_hdr(dh, RSL_MT_RF_CHAN_REL);
|
||||
dh->chan_nr = lchan2chan_nr(lchan);
|
||||
@@ -581,7 +602,20 @@ int rsl_rf_chan_release(struct gsm_lchan *lchan)
|
||||
msg->lchan = lchan;
|
||||
msg->trx = lchan->ts->trx;
|
||||
|
||||
DEBUGP(DRSL, "%s RF Channel Release CMD\n", gsm_lchan_name(lchan));
|
||||
DEBUGP(DRSL, "%s RF Channel Release CMD due error %d\n", gsm_lchan_name(lchan), error);
|
||||
|
||||
if (error) {
|
||||
/*
|
||||
* the nanoBTS sends RLL release indications after the channel release. This can
|
||||
* be a problem when we have reassigned the channel to someone else and then can
|
||||
* not figure out who used this channel.
|
||||
*/
|
||||
rsl_lchan_set_state(lchan, LCHAN_S_REL_ERR);
|
||||
lchan->error_timer.data = lchan;
|
||||
lchan->error_timer.cb = error_timeout_cb;
|
||||
bsc_schedule_timer(&lchan->error_timer,
|
||||
msg->trx->bts->network->T3111 + 2, 0);
|
||||
}
|
||||
|
||||
/* BTS will respond by RF CHAN REL ACK */
|
||||
return abis_rsl_sendmsg(msg);
|
||||
@@ -728,7 +762,6 @@ int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id, u_int8_t reas
|
||||
/* 0 is normal release, 1 is local end */
|
||||
msgb_tv_put(msg, RSL_IE_RELEASE_MODE, reason);
|
||||
|
||||
lchan->state = LCHAN_S_REL_REQ;
|
||||
/* FIXME: start some timer in case we don't receive a REL ACK ? */
|
||||
|
||||
msg->trx = lchan->ts->trx;
|
||||
@@ -736,6 +769,12 @@ int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id, u_int8_t reas
|
||||
return abis_rsl_sendmsg(msg);
|
||||
}
|
||||
|
||||
int rsl_lchan_set_state(struct gsm_lchan *lchan, int state)
|
||||
{
|
||||
lchan->state = state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Chapter 8.4.2: Channel Activate Acknowledge */
|
||||
static int rsl_rx_chan_act_ack(struct msgb *msg)
|
||||
{
|
||||
@@ -750,7 +789,7 @@ static int rsl_rx_chan_act_ack(struct msgb *msg)
|
||||
LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK, but state %s\n",
|
||||
gsm_lchan_name(msg->lchan),
|
||||
gsm_lchans_name(msg->lchan->state));
|
||||
msg->lchan->state = LCHAN_S_ACTIVE;
|
||||
rsl_lchan_set_state(msg->lchan, LCHAN_S_ACTIVE);
|
||||
|
||||
dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_ACK, msg->lchan);
|
||||
|
||||
@@ -776,9 +815,9 @@ static int rsl_rx_chan_act_nack(struct msgb *msg)
|
||||
print_rsl_cause(LOGL_ERROR, cause,
|
||||
TLVP_LEN(&tp, RSL_IE_CAUSE));
|
||||
if (*cause != RSL_ERR_RCH_ALR_ACTV_ALLOC)
|
||||
msg->lchan->state = LCHAN_S_NONE;
|
||||
rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
|
||||
} else
|
||||
msg->lchan->state = LCHAN_S_NONE;
|
||||
rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
|
||||
|
||||
LOGPC(DRSL, LOGL_ERROR, "\n");
|
||||
|
||||
@@ -806,7 +845,7 @@ static int rsl_rx_conn_fail(struct msgb *msg)
|
||||
|
||||
LOGPC(DRSL, LOGL_NOTICE, "\n");
|
||||
/* FIXME: only free it after channel release ACK */
|
||||
return rsl_rf_chan_release(msg->lchan);
|
||||
return rsl_rf_chan_release(msg->lchan, 1);
|
||||
}
|
||||
|
||||
static void print_meas_rep_uni(struct gsm_meas_rep_unidir *mru,
|
||||
@@ -978,11 +1017,14 @@ static int abis_rsl_rx_dchan(struct msgb *msg)
|
||||
break;
|
||||
case RSL_MT_RF_CHAN_REL_ACK:
|
||||
DEBUGP(DRSL, "%s RF CHANNEL RELEASE ACK\n", ts_name);
|
||||
if (msg->lchan->state != LCHAN_S_REL_REQ)
|
||||
if (msg->lchan->state != LCHAN_S_REL_REQ && msg->lchan->state != LCHAN_S_REL_ERR)
|
||||
LOGP(DRSL, LOGL_NOTICE, "%s CHAN REL ACK but state %s\n",
|
||||
gsm_lchan_name(msg->lchan),
|
||||
gsm_lchans_name(msg->lchan->state));
|
||||
msg->lchan->state = LCHAN_S_NONE;
|
||||
bsc_del_timer(&msg->lchan->T3111);
|
||||
/* we have an error timer pending to release that */
|
||||
if (msg->lchan->state != LCHAN_S_REL_ERR)
|
||||
rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
|
||||
lchan_free(msg->lchan);
|
||||
break;
|
||||
case RSL_MT_MODE_MODIFY_ACK:
|
||||
@@ -1074,7 +1116,15 @@ static void t3101_expired(void *data)
|
||||
{
|
||||
struct gsm_lchan *lchan = data;
|
||||
|
||||
rsl_rf_chan_release(lchan);
|
||||
rsl_rf_chan_release(lchan, 1);
|
||||
}
|
||||
|
||||
/* If T3111 expires, we will send the RF Channel Request */
|
||||
static void t3111_expired(void *data)
|
||||
{
|
||||
struct gsm_lchan *lchan = data;
|
||||
|
||||
rsl_rf_chan_release(lchan, 0);
|
||||
}
|
||||
|
||||
/* MS has requested a channel on the RACH */
|
||||
@@ -1125,7 +1175,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
|
||||
LOGP(DRSL, LOGL_NOTICE, "%s lchan_alloc() returned channel "
|
||||
"in state %s\n", gsm_lchan_name(lchan),
|
||||
gsm_lchans_name(lchan->state));
|
||||
lchan->state = LCHAN_S_ACT_REQ;
|
||||
rsl_lchan_set_state(lchan, LCHAN_S_ACT_REQ);
|
||||
|
||||
ts_number = lchan->ts->nr;
|
||||
arfcn = lchan->ts->trx->arfcn;
|
||||
@@ -1242,11 +1292,37 @@ static int rsl_rx_rll_err_ind(struct msgb *msg)
|
||||
rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND);
|
||||
|
||||
if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED)
|
||||
return rsl_rf_chan_release(msg->lchan);
|
||||
return rsl_rf_chan_release(msg->lchan, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rsl_handle_release(struct gsm_lchan *lchan)
|
||||
{
|
||||
int sapi;
|
||||
struct gsm_bts *bts;
|
||||
|
||||
/* maybe we have only brought down one RLL */
|
||||
if (lchan->state != LCHAN_S_REL_REQ)
|
||||
return;
|
||||
|
||||
for (sapi = 0; sapi < ARRAY_SIZE(lchan->sapis); ++sapi) {
|
||||
if (lchan->sapis[sapi] == LCHAN_SAPI_UNUSED)
|
||||
continue;
|
||||
LOGP(DRSL, LOGL_NOTICE, "%s waiting for SAPI=%d to be released.\n",
|
||||
gsm_lchan_name(lchan), sapi);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* wait a bit to send the RF Channel Release */
|
||||
lchan->T3111.cb = t3111_expired;
|
||||
lchan->T3111.data = lchan;
|
||||
bts = lchan->ts->trx->bts;
|
||||
bsc_schedule_timer(&lchan->T3111, bts->network->T3111, 0);
|
||||
}
|
||||
|
||||
/* ESTABLISH INDICATION, LOCATION AREA UPDATE REQUEST
|
||||
0x02, 0x06,
|
||||
0x01, 0x20,
|
||||
@@ -1298,20 +1374,16 @@ static int abis_rsl_rx_rll(struct msgb *msg)
|
||||
msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_UNUSED;
|
||||
rll_indication(msg->lchan, rllh->link_id,
|
||||
BSC_RLLR_IND_REL_IND);
|
||||
/* we can now releae the channel on the BTS/Abis side */
|
||||
/* FIXME: officially we need to start T3111 and wait for
|
||||
* some grace period */
|
||||
rsl_rf_chan_release(msg->lchan);
|
||||
rsl_handle_release(msg->lchan);
|
||||
rsl_lchan_rll_release(msg->lchan, rllh->link_id);
|
||||
break;
|
||||
case RSL_MT_REL_CONF:
|
||||
/* BTS informs us of having received UA from MS,
|
||||
* in response to DISC that we've sent earlier */
|
||||
DEBUGPC(DRLL, "RELEASE CONFIRMATION\n");
|
||||
msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_UNUSED;
|
||||
/* we can now releae the channel on the BTS/Abis side */
|
||||
/* FIXME: officially we need to start T3111 and wait for
|
||||
* some grace period */
|
||||
rsl_rf_chan_release(msg->lchan);
|
||||
rsl_handle_release(msg->lchan);
|
||||
rsl_lchan_rll_release(msg->lchan, rllh->link_id);
|
||||
break;
|
||||
case RSL_MT_ERROR_IND:
|
||||
rc = rsl_rx_rll_err_ind(msg);
|
||||
|
||||
@@ -49,6 +49,20 @@ static void connection_loss(struct bsc_msc_connection *con)
|
||||
con->connection_loss(con);
|
||||
}
|
||||
|
||||
static int bsc_msc_except(struct bsc_fd *bfd)
|
||||
{
|
||||
struct write_queue *wrt;
|
||||
struct bsc_msc_connection *con;
|
||||
|
||||
LOGP(DMSC, LOGL_ERROR, "Exception on the BFD. Closing down.\n");
|
||||
|
||||
wrt = container_of(bfd, struct write_queue, bfd);
|
||||
con = container_of(wrt, struct bsc_msc_connection, write_queue);
|
||||
|
||||
connection_loss(con);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called in the case of a non blocking connect */
|
||||
static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
|
||||
{
|
||||
@@ -81,7 +95,7 @@ static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
|
||||
|
||||
/* go to full operation */
|
||||
fd->cb = write_queue_bfd_cb;
|
||||
fd->when = BSC_FD_READ;
|
||||
fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
|
||||
|
||||
con->is_connected = 1;
|
||||
LOGP(DMSC, LOGL_NOTICE, "(Re)Connected to the MSC.\n");
|
||||
@@ -156,7 +170,7 @@ int bsc_msc_connect(struct bsc_msc_connection *con)
|
||||
connection_loss(con);
|
||||
return ret;
|
||||
} else {
|
||||
fd->when = BSC_FD_READ;
|
||||
fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
|
||||
fd->cb = write_queue_bfd_cb;
|
||||
con->is_connected = 1;
|
||||
if (con->connected)
|
||||
@@ -187,6 +201,7 @@ struct bsc_msc_connection *bsc_msc_create(const char *ip, int port)
|
||||
con->ip = ip;
|
||||
con->port = port;
|
||||
write_queue_init(&con->write_queue, 100);
|
||||
con->write_queue.except_cb = bsc_msc_except;
|
||||
return con;
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ struct gsm_subscriber *find_subscriber(u_int8_t type, const char *mi_string)
|
||||
if (type == GSM_MI_TYPE_TMSI) {
|
||||
tmsi = tmsi_from_string(mi_string);
|
||||
if (tmsi == GSM_RESERVED_TMSI) {
|
||||
DEBUGP(DMSC, "The TMSI is the reserved one.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "The TMSI is the reserved one.\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -127,7 +127,7 @@ struct gsm_subscriber *find_subscriber(u_int8_t type, const char *mi_string)
|
||||
}
|
||||
}
|
||||
|
||||
DEBUGP(DMSC, "No subscriber has been found.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "No subscriber has been found.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -136,35 +136,49 @@ struct gsm_subscriber *find_subscriber(u_int8_t type, const char *mi_string)
|
||||
/* SCCP handling */
|
||||
void msc_outgoing_sccp_data(struct sccp_connection *conn, struct msgb *msg, unsigned int len)
|
||||
{
|
||||
struct gsm_lchan *lchan;
|
||||
struct bssmap_header *bs;
|
||||
|
||||
if (len < 1) {
|
||||
DEBUGP(DMSC, "The header is too short.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "The header is too short.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
lchan = sccp_get_lchan(conn->data_ctx);
|
||||
if (!lchan) {
|
||||
LOGP(DMSC, LOGL_ERROR, "SCCP data without lchan for type: 0x%x\n", msg->l3h[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
/* that is bad */
|
||||
if (!lchan->msc_data) {
|
||||
LOGP(DMSC, LOGL_ERROR, "SCCP data for lchan without msc data type: 0x%x\n",
|
||||
msg->l3h[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (msg->l3h[0]) {
|
||||
case BSSAP_MSG_BSS_MANAGEMENT:
|
||||
msg->l4h = &msg->l3h[sizeof(*bs)];
|
||||
msg->lchan = sccp_get_lchan(conn->data_ctx);
|
||||
msg->lchan = lchan;
|
||||
bssmap_rcvmsg_dt1(conn, msg, len - sizeof(*bs));
|
||||
break;
|
||||
case BSSAP_MSG_DTAP:
|
||||
dtap_rcvmsg(sccp_get_lchan(conn->data_ctx), msg, len);
|
||||
dtap_rcvmsg(lchan, msg, len);
|
||||
break;
|
||||
default:
|
||||
DEBUGPC(DMSC, "Unimplemented msg type: %d\n", msg->l3h[0]);
|
||||
LOGP(DMSC, LOGL_DEBUG, "Unimplemented msg type: %d\n", msg->l3h[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void msc_outgoing_sccp_state(struct sccp_connection *conn, int old_state)
|
||||
{
|
||||
if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) {
|
||||
DEBUGP(DMSC, "Freeing sccp conn: %p state: %d\n", conn, conn->connection_state);
|
||||
LOGP(DMSC, LOGL_DEBUG, "Freeing sccp conn: %p state: %d\n", conn, conn->connection_state);
|
||||
if (sccp_get_lchan(conn->data_ctx) != NULL) {
|
||||
struct gsm_lchan *lchan = sccp_get_lchan(conn->data_ctx);
|
||||
|
||||
DEBUGP(DMSC, "ERROR: The lchan is still associated\n.");
|
||||
LOGP(DMSC, LOGL_ERROR, "ERROR: The lchan is still associated\n.");
|
||||
|
||||
lchan->msc_data = NULL;
|
||||
put_subscr_con(&lchan->conn, 0);
|
||||
@@ -176,7 +190,7 @@ void msc_outgoing_sccp_state(struct sccp_connection *conn, int old_state)
|
||||
} else if (conn->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED) {
|
||||
struct bss_sccp_connection_data *con_data;
|
||||
|
||||
DEBUGP(DMSC, "Connection established: %p\n", conn);
|
||||
LOGP(DMSC, LOGL_DEBUG, "Connection established: %p\n", conn);
|
||||
|
||||
/* start the inactivity test timer */
|
||||
con_data = (struct bss_sccp_connection_data *) conn->data_ctx;
|
||||
@@ -210,23 +224,23 @@ static int open_sccp_connection(struct msgb *layer3)
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGP(DMSC, "Opening new layer3 connection\n");
|
||||
LOGP(DMSC, LOGL_DEBUG, "Opening new layer3 connection\n");
|
||||
sccp_connection = sccp_connection_socket();
|
||||
if (!sccp_connection) {
|
||||
DEBUGP(DMSC, "Failed to allocate memory.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Failed to allocate memory.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
data = bssmap_create_layer3(layer3);
|
||||
if (!data) {
|
||||
DEBUGP(DMSC, "Failed to allocate complete layer3.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Failed to allocate complete layer3.\n");
|
||||
sccp_connection_free(sccp_connection);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
con_data = bss_sccp_create_data();
|
||||
if (!con_data) {
|
||||
DEBUGP(DMSC, "Failed to allocate bss<->msc data.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Failed to allocate bss<->msc data.\n");
|
||||
sccp_connection_free(sccp_connection);
|
||||
msgb_free(data);
|
||||
return -ENOMEM;
|
||||
@@ -255,7 +269,7 @@ static int send_dtap_or_open_connection(struct msgb *msg)
|
||||
if (msg->lchan->msc_data) {
|
||||
struct msgb *dtap = dtap_create_msg(msg, 0);
|
||||
if (!dtap) {
|
||||
DEBUGP(DMSC, "Creating a DTAP message failed.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Creating a DTAP message failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -274,7 +288,7 @@ static int handle_paging_response(struct msgb *msg)
|
||||
u_int8_t mi_type;
|
||||
|
||||
gsm48_paging_extract_mi(msg, mi_string, &mi_type);
|
||||
DEBUGP(DMSC, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
|
||||
LOGP(DMSC, LOGL_DEBUG, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
|
||||
mi_type, mi_string);
|
||||
|
||||
subscr = find_subscriber(mi_type, mi_string);
|
||||
@@ -284,7 +298,7 @@ static int handle_paging_response(struct msgb *msg)
|
||||
/* force the paging to stop at every bts */
|
||||
subscr->lac = GSM_LAC_RESERVED_ALL_BTS;
|
||||
if (gsm48_handle_paging_resp(msg, subscr) != 0) {
|
||||
DEBUGP(DMSC, "Paging failed.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Paging failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -302,10 +316,10 @@ static int handle_cipher_m_complete(struct msgb *msg)
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGP(DMSC, "CIPHER MODE COMPLETE from MS, forwarding to MSC\n");
|
||||
LOGP(DMSC, LOGL_DEBUG, "CIPHER MODE COMPLETE from MS, forwarding to MSC\n");
|
||||
resp = bssmap_create_cipher_complete(msg);
|
||||
if (!resp) {
|
||||
DEBUGP(DMSC, "Creating MSC response failed.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Creating MSC response failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -322,7 +336,7 @@ static int handle_ass_compl(struct msgb *msg)
|
||||
struct gsm_lchan *old_chan;
|
||||
struct gsm48_hdr *gh = msgb_l3(msg);
|
||||
|
||||
DEBUGP(DMSC, "ASSIGNMENT COMPLETE from MS, forwarding to MSC\n");
|
||||
LOGP(DMSC, LOGL_DEBUG, "ASSIGNMENT COMPLETE from MS, forwarding to MSC\n");
|
||||
|
||||
if (!msg->lchan->msc_data) {
|
||||
LOGP(DMSC, LOGL_ERROR, "No MSC data\n");
|
||||
@@ -331,13 +345,13 @@ static int handle_ass_compl(struct msgb *msg)
|
||||
}
|
||||
|
||||
if (msg->lchan->msc_data->secondary_lchan != msg->lchan) {
|
||||
LOGP(DMSC, LOGL_NOTICE, "Wrong assignment complete.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Wrong assignment complete.\n");
|
||||
put_subscr_con(&msg->lchan->conn, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msgb_l3len(msg) - sizeof(*gh) != 1) {
|
||||
DEBUGP(DMSC, "assignment failure invalid: %d\n",
|
||||
LOGP(DMSC, LOGL_ERROR, "assignment compl invalid: %d\n",
|
||||
msgb_l3len(msg) - sizeof(*gh));
|
||||
put_subscr_con(&msg->lchan->conn, 0);
|
||||
return -1;
|
||||
@@ -368,30 +382,36 @@ static int handle_ass_compl(struct msgb *msg)
|
||||
*/
|
||||
static int handle_ass_fail(struct msgb *msg)
|
||||
{
|
||||
u_int8_t *rr_cause;
|
||||
struct gsm48_hdr *gh = msgb_l3(msg);
|
||||
|
||||
DEBUGP(DMSC, "ASSIGNMENT FAILURE from MS, forwarding to MSC\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "ASSIGNMENT FAILURE from MS, forwarding to MSC\n");
|
||||
if (!msg->lchan->msc_data) {
|
||||
LOGP(DMSC, LOGL_ERROR, "No MSC data\n");
|
||||
put_subscr_con(&msg->lchan->conn, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg->lchan->msc_data->secondary_lchan != msg->lchan) {
|
||||
LOGP(DMSC, LOGL_NOTICE, "Wrong assignment complete.\n");
|
||||
/* assignment failure comes on the old link */
|
||||
if (msg->lchan->msc_data->lchan != msg->lchan) {
|
||||
LOGP(DMSC, LOGL_NOTICE, "Failure should come on the old link.\n");
|
||||
msg->lchan->msc_data = NULL;
|
||||
put_subscr_con(&msg->lchan->conn, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Giving up the secondary will happen in bssap */
|
||||
if (msgb_l3len(msg) - sizeof(*gh) != 1) {
|
||||
DEBUGP(DMSC, "assignment failure invalid: %d\n",
|
||||
LOGP(DMSC, LOGL_ERROR, "assignment failure invalid: %d\n",
|
||||
msgb_l3len(msg) - sizeof(*gh));
|
||||
put_subscr_con(&msg->lchan->conn, 0);
|
||||
return -1;
|
||||
rr_cause = NULL;
|
||||
} else {
|
||||
rr_cause = &gh->data[0];
|
||||
}
|
||||
|
||||
/* this will also free the secondary channel */
|
||||
gsm0808_send_assignment_failure(msg->lchan,
|
||||
GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE, &gh->data[0]);
|
||||
GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE, rr_cause);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -496,7 +516,7 @@ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
|
||||
if (rc == 0 && msg->lchan->msc_data && lchan_get_sccp(msg->lchan)) {
|
||||
struct msgb *dtap = dtap_create_msg(msg, link_id);
|
||||
if (!dtap) {
|
||||
DEBUGP(DMSC, "Creating a DTAP message failed.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Creating a DTAP message failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -523,7 +543,7 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int 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",
|
||||
LOGP(DMSC, LOGL_DEBUG, "Connecting BTS to port: %d conn: %d\n",
|
||||
lchan->msc_data->rtp_port, lchan->abis_ip.conn_id);
|
||||
|
||||
int rtp_payload = ts->trx->bts->network->rtp_payload;
|
||||
@@ -534,7 +554,7 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
|
||||
lchan->msc_data->rtp_port,
|
||||
rtp_payload);
|
||||
if (rc < 0) {
|
||||
DEBUGP(DMSC, "Failed to send connect: %d\n", rc);
|
||||
LOGP(DMSC, LOGL_ERROR, "Failed to send connect: %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
@@ -570,8 +590,8 @@ static int msc_sccp_do_write(struct bsc_fd *fd, struct msgb *msg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DEBUGP(DMSC, "Sending SCCP to MSC: %u\n", msgb_l2len(msg));
|
||||
DEBUGP(DMI, "MSC TX %s\n", hexdump(msg->l2h, msgb_l2len(msg)));
|
||||
LOGP(DMSC, LOGL_DEBUG, "Sending SCCP to MSC: %u\n", msgb_l2len(msg));
|
||||
LOGP(DMI, LOGL_DEBUG, "MSC TX %s\n", hexdump(msg->l2h, msgb_l2len(msg)));
|
||||
|
||||
ret = write(msc_con->write_queue.bfd.fd, msg->data, msg->len);
|
||||
if (ret < msg->len)
|
||||
@@ -612,7 +632,7 @@ static int mgcp_do_read(struct bsc_fd *fd)
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = read(fd->fd, mgcp->data, mgcp->data_len);
|
||||
ret = read(fd->fd, mgcp->data, 4096 - 128);
|
||||
if (ret <= 0) {
|
||||
LOGP(DMGCP, LOGL_ERROR, "Failed to read: %d/%s\n", errno, strerror(errno));
|
||||
msgb_free(mgcp);
|
||||
@@ -705,7 +725,7 @@ static int mgcp_create_port(void)
|
||||
|
||||
static int msc_sccp_accept(struct sccp_connection *connection, void *data)
|
||||
{
|
||||
DEBUGP(DMSC, "Rejecting incoming SCCP connection.\n");
|
||||
LOGP(DMSC, LOGL_DEBUG, "Rejecting incoming SCCP connection.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -713,10 +733,10 @@ static int msc_sccp_read(struct msgb *msgb, unsigned int length, void *data)
|
||||
{
|
||||
struct bssmap_header *bs;
|
||||
|
||||
DEBUGP(DMSC, "Incoming SCCP message ftom MSC: %s\n", hexdump(msgb->l3h, length));
|
||||
LOGP(DMSC, LOGL_DEBUG, "Incoming SCCP message ftom MSC: %s\n", hexdump(msgb->l3h, length));
|
||||
|
||||
if (length < sizeof(*bs)) {
|
||||
DEBUGP(DMSC, "The header is too short.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "The header is too short.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -730,7 +750,7 @@ static int msc_sccp_read(struct msgb *msgb, unsigned int length, void *data)
|
||||
bssmap_rcvmsg_udt(bsc_gsmnet, msgb, length - sizeof(*bs));
|
||||
break;
|
||||
default:
|
||||
DEBUGPC(DMSC, "Unimplemented msg type: %d\n", bs->type);
|
||||
LOGP(DMSC, LOGL_ERROR, "Unimplemented msg type: %d\n", bs->type);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -757,7 +777,7 @@ static void initialize_if_needed(void)
|
||||
/* send a gsm 08.08 reset message from here */
|
||||
msg = bssmap_create_reset();
|
||||
if (!msg) {
|
||||
DEBUGP(DMSC, "Failed to create the reset message.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Failed to create the reset message.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -848,7 +868,7 @@ static int ipaccess_a_fd_cb(struct bsc_fd *bfd)
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGP(DMSC, "From MSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
|
||||
LOGP(DMSC, LOGL_DEBUG, "From MSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
|
||||
|
||||
/* handle base message handling */
|
||||
hh = (struct ipaccess_head *) msg->data;
|
||||
@@ -877,6 +897,7 @@ static void print_help()
|
||||
printf(" -h --help this text\n");
|
||||
printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n");
|
||||
printf(" -s --disable-color\n");
|
||||
printf(" -T --timestamp. Print a timestamp in the debug output.\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");
|
||||
@@ -900,7 +921,7 @@ static void handle_options(int argc, char** argv)
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_long(argc, argv, "hd:sTPc:m:l:",
|
||||
c = getopt_long(argc, argv, "hd:sTPc:m:l:e:",
|
||||
long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
@@ -947,8 +968,10 @@ static void signal_handler(int signal)
|
||||
|
||||
switch (signal) {
|
||||
case SIGINT:
|
||||
bsc_shutdown_net(bsc_gsmnet);
|
||||
sleep(3);
|
||||
if (bsc_gsmnet) {
|
||||
bsc_shutdown_net(bsc_gsmnet);
|
||||
sleep(3);
|
||||
}
|
||||
exit(0);
|
||||
break;
|
||||
case SIGABRT:
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
#define BSSMAP_MSG_SIZE 512
|
||||
#define BSSMAP_MSG_HEADROOM 128
|
||||
|
||||
static void bts_queue_send(struct msgb *msg, int link_id);
|
||||
static void bssmap_free_secondary(struct bss_sccp_connection_data *data);
|
||||
|
||||
|
||||
static const struct tlv_definition bss_att_tlvdef = {
|
||||
.def = {
|
||||
@@ -85,13 +88,13 @@ static u_int16_t get_country_code_for_msc(struct gsm_network *net)
|
||||
|
||||
static int bssmap_paging_cb(unsigned int hooknum, unsigned int event, struct msgb *msg, void *data, void *param)
|
||||
{
|
||||
DEBUGP(DMSC, "Paging is complete.\n");
|
||||
LOGP(DMSC, LOGL_DEBUG, "Paging is complete.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bssmap_handle_reset_ack(struct gsm_network *net, struct msgb *msg, unsigned int length)
|
||||
{
|
||||
DEBUGP(DMSC, "Reset ACK from MSC\n");
|
||||
LOGP(DMSC, LOGL_NOTICE, "Reset ACK from MSC\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -112,15 +115,15 @@ static int bssmap_handle_paging(struct gsm_network *net, struct msgb *msg, unsig
|
||||
tlv_parse(&tp, &bss_att_tlvdef, msg->l4h + 1, payload_length - 1, 0, 0);
|
||||
|
||||
if (!TLVP_PRESENT(&tp, GSM0808_IE_IMSI)) {
|
||||
DEBUGP(DMSC, "Mandantory IMSI not present.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Mandantory IMSI not present.\n");
|
||||
return -1;
|
||||
} else if ((TLVP_VAL(&tp, GSM0808_IE_IMSI)[0] & GSM_MI_TYPE_MASK) != GSM_MI_TYPE_IMSI) {
|
||||
DEBUGP(DMSC, "Wrong content in the IMSI\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Wrong content in the IMSI\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST)) {
|
||||
DEBUGP(DMSC, "Mandantory CELL IDENTIFIER LIST not present.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Mandantory CELL IDENTIFIER LIST not present.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -150,7 +153,7 @@ static int bssmap_handle_paging(struct gsm_network *net, struct msgb *msg, unsig
|
||||
unsigned int *_lac = (unsigned int *)&data[1];
|
||||
lac = ntohs(*_lac);
|
||||
} else if (data_length > 1 || (data[0] & 0x0f) != CELL_IDENT_BSS) {
|
||||
DEBUGPC(DMSC, "Unsupported Cell Identifier List: %s\n", hexdump(data, data_length));
|
||||
LOGP(DMSC, LOGL_ERROR, "Unsupported Cell Identifier List: %s\n", hexdump(data, data_length));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -158,10 +161,10 @@ static int bssmap_handle_paging(struct gsm_network *net, struct msgb *msg, unsig
|
||||
chan_needed = TLVP_VAL(&tp, GSM0808_IE_CHANNEL_NEEDED)[0] & 0x03;
|
||||
|
||||
if (TLVP_PRESENT(&tp, GSM0808_IE_EMLPP_PRIORITY)) {
|
||||
DEBUGP(DMSC, "eMLPP is not handled\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "eMLPP is not handled\n");
|
||||
}
|
||||
|
||||
DEBUGP(DMSC, "Paging request from MSC IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x\n", mi_string, tmsi, tmsi, lac);
|
||||
LOGP(DMSC, LOGL_DEBUG, "Paging request from MSC IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x\n", mi_string, tmsi, tmsi, lac);
|
||||
subscr = subscr_get_or_create(net, mi_string);
|
||||
if (!subscr)
|
||||
return -1;
|
||||
@@ -170,7 +173,7 @@ static int bssmap_handle_paging(struct gsm_network *net, struct msgb *msg, unsig
|
||||
subscr->tmsi = tmsi;
|
||||
subscr->lac = lac;
|
||||
paged = paging_request(net, subscr, chan_needed, bssmap_paging_cb, subscr);
|
||||
DEBUGP(DMSC, "Paged IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x on #bts: %d\n", mi_string, tmsi, tmsi, lac, paged);
|
||||
LOGP(DMSC, LOGL_DEBUG, "Paged IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x on #bts: %d\n", mi_string, tmsi, tmsi, lac, paged);
|
||||
|
||||
subscr_put(subscr);
|
||||
return -1;
|
||||
@@ -185,13 +188,12 @@ static int bssmap_handle_clear_command(struct sccp_connection *conn,
|
||||
/* TODO: handle the cause of this package */
|
||||
|
||||
if (msg->lchan) {
|
||||
DEBUGP(DMSC, "Releasing all transactions on %p\n", conn);
|
||||
LOGP(DMSC, LOGL_DEBUG, "Releasing all transactions on %p\n", conn);
|
||||
bsc_del_timer(&msg->lchan->msc_data->T10);
|
||||
msg->lchan->msc_data->lchan = NULL;
|
||||
|
||||
/* we might got killed during an assignment */
|
||||
if (msg->lchan->msc_data->secondary_lchan)
|
||||
put_subscr_con(&msg->lchan->msc_data->secondary_lchan->conn, 0);
|
||||
bssmap_free_secondary(msg->lchan->msc_data);
|
||||
|
||||
msg->lchan->msc_data = NULL;
|
||||
put_subscr_con(&msg->lchan->conn, 0);
|
||||
@@ -200,7 +202,7 @@ static int bssmap_handle_clear_command(struct sccp_connection *conn,
|
||||
/* send the clear complete message */
|
||||
resp = bssmap_create_clear_complete();
|
||||
if (!resp) {
|
||||
DEBUGP(DMSC, "Sending clear complete failed.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Sending clear complete failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -227,14 +229,13 @@ static int bssmap_handle_cipher_mode(struct sccp_connection *conn,
|
||||
int reject_cause = -1;
|
||||
int include_imeisv = 1;
|
||||
|
||||
/* HACK: Sending A5/0 to the MS */
|
||||
if (!msg->lchan || !msg->lchan->msc_data) {
|
||||
DEBUGP(DMSC, "No lchan/msc_data in cipher mode command.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "No lchan/msc_data in cipher mode command.\n");
|
||||
goto reject;
|
||||
}
|
||||
|
||||
if (msg->lchan->msc_data->ciphering_handled) {
|
||||
DEBUGP(DMSC, "Already seen ciphering command. Protocol Error.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Already seen ciphering command. Protocol Error.\n");
|
||||
goto reject;
|
||||
}
|
||||
|
||||
@@ -243,7 +244,7 @@ static int bssmap_handle_cipher_mode(struct sccp_connection *conn,
|
||||
|
||||
tlv_parse(&tp, &bss_att_tlvdef, msg->l4h + 1, payload_length - 1, 0, 0);
|
||||
if (!TLVP_PRESENT(&tp, GSM0808_IE_ENCRYPTION_INFORMATION)) {
|
||||
DEBUGP(DMSC, "IE Encryption Information missing.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "IE Encryption Information missing.\n");
|
||||
goto reject;
|
||||
}
|
||||
|
||||
@@ -255,7 +256,7 @@ static int bssmap_handle_cipher_mode(struct sccp_connection *conn,
|
||||
*/
|
||||
len = TLVP_LEN(&tp, GSM0808_IE_ENCRYPTION_INFORMATION);
|
||||
if (len < 1) {
|
||||
DEBUGP(DMSC, "IE Encryption Information is too short.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "IE Encryption Information is too short.\n");
|
||||
goto reject;
|
||||
}
|
||||
|
||||
@@ -269,7 +270,7 @@ static int bssmap_handle_cipher_mode(struct sccp_connection *conn,
|
||||
msg->lchan->encr.key_len = len - 1;
|
||||
memcpy(msg->lchan->encr.key, &data[1], len - 1);
|
||||
} else {
|
||||
DEBUGP(DMSC, "Can not select encryption...\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Can not select encryption...\n");
|
||||
goto reject;
|
||||
}
|
||||
|
||||
@@ -280,12 +281,12 @@ static int bssmap_handle_cipher_mode(struct sccp_connection *conn,
|
||||
return gsm48_send_rr_ciph_mode(msg->lchan, include_imeisv);
|
||||
|
||||
reject:
|
||||
if (msg->lchan->msc_data)
|
||||
if (msg->lchan && msg->lchan->msc_data)
|
||||
msg->lchan->msc_data->block_gsm = 0;
|
||||
|
||||
resp = bssmap_create_cipher_reject(reject_cause);
|
||||
if (!resp) {
|
||||
DEBUGP(DMSC, "Sending the cipher reject failed.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Sending the cipher reject failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -293,19 +294,53 @@ reject:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* handle network failures... and free the secondary lchan
|
||||
*/
|
||||
static void bssmap_free_secondary(struct bss_sccp_connection_data *data)
|
||||
{
|
||||
struct gsm_lchan *lchan;
|
||||
|
||||
if (!data || !data->secondary_lchan)
|
||||
return;
|
||||
|
||||
lchan = data->secondary_lchan;
|
||||
if (lchan->msc_data != data) {
|
||||
LOGP(DMSC, LOGL_ERROR, "MSC data does not match on lchan and cb.\n");
|
||||
data->secondary_lchan = NULL;
|
||||
}
|
||||
|
||||
/* give up additional data */
|
||||
lchan->msc_data->secondary_lchan = NULL;
|
||||
if (lchan->msc_data->lchan == lchan)
|
||||
lchan->msc_data->lchan = NULL;
|
||||
lchan->msc_data = NULL;
|
||||
|
||||
/* give up the new channel to not do a SACCH deactivate */
|
||||
subscr_put(lchan->conn.subscr);
|
||||
lchan->conn.subscr = NULL;
|
||||
put_subscr_con(&lchan->conn, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle the network configurable T10 parameter
|
||||
*/
|
||||
static void bssmap_t10_fired(void *_conn)
|
||||
{
|
||||
struct bss_sccp_connection_data *msc_data;
|
||||
struct sccp_connection *conn = (struct sccp_connection *) _conn;
|
||||
struct msgb *resp;
|
||||
|
||||
DEBUGP(DMSC, "T10 fired, assignment failed: %p\n", conn);
|
||||
LOGP(DMSC, LOGL_ERROR, "T10 fired, assignment failed: %p\n", conn);
|
||||
|
||||
/* free the secondary channel if we have one */
|
||||
msc_data = conn->data_ctx;
|
||||
bssmap_free_secondary(msc_data);
|
||||
|
||||
resp = bssmap_create_assignment_failure(
|
||||
GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
|
||||
if (!resp) {
|
||||
DEBUGP(DMSC, "Allocation failure: %p\n", conn);
|
||||
LOGP(DMSC, LOGL_ERROR, "Allocation failure: %p\n", conn);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -329,7 +364,7 @@ enum gsm0808_permitted_speech audio_support_to_gsm88(struct gsm_audio_support *a
|
||||
return GSM0808_PERM_HR3;
|
||||
break;
|
||||
default:
|
||||
DEBUGP(DMSC, "Wrong speech mode: %d\n", audio->ver);
|
||||
LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: %d\n", audio->ver);
|
||||
return GSM0808_PERM_FR1;
|
||||
}
|
||||
} else {
|
||||
@@ -344,8 +379,8 @@ enum gsm0808_permitted_speech audio_support_to_gsm88(struct gsm_audio_support *a
|
||||
return GSM0808_PERM_FR3;
|
||||
break;
|
||||
default:
|
||||
DEBUGP(DMSC, "Wrong speech mode: %d\n", audio->ver);
|
||||
return GSM0808_PERM_HR1;
|
||||
LOGP(DMSC, LOGL_ERROR, "Wrong speech mode: %d\n", audio->ver);
|
||||
return GSM0808_PERM_HR1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -427,6 +462,7 @@ static int handle_new_assignment(struct msgb *msg, int full_rate, int chan_mode)
|
||||
return -1;
|
||||
}
|
||||
|
||||
rsl_lchan_set_state(new_lchan, LCHAN_S_ACT_REQ);
|
||||
msc_data->secondary_lchan = new_lchan;
|
||||
new_lchan->msc_data = msc_data;
|
||||
return 0;
|
||||
@@ -445,6 +481,7 @@ static void continue_new_assignment(struct gsm_lchan *new_lchan)
|
||||
|
||||
if (new_lchan->msc_data->secondary_lchan != new_lchan) {
|
||||
LOGP(DMSC, LOGL_ERROR, "This is not the secondary channel?\n");
|
||||
new_lchan->msc_data = NULL;
|
||||
put_subscr_con(&new_lchan->conn, 0);
|
||||
return;
|
||||
}
|
||||
@@ -472,8 +509,8 @@ static int bssmap_handle_assignm_req(struct sccp_connection *conn,
|
||||
int i, supported, port, full_rate = -1;
|
||||
|
||||
if (!msg->lchan || !msg->lchan->msc_data) {
|
||||
DEBUGP(DMSC, "No lchan/msc_data in cipher mode command.\n");
|
||||
goto reject;
|
||||
LOGP(DMSC, LOGL_ERROR, "No lchan/msc_data in cipher mode command.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
msc_data = msg->lchan->msc_data;
|
||||
@@ -481,12 +518,12 @@ static int bssmap_handle_assignm_req(struct sccp_connection *conn,
|
||||
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");
|
||||
LOGP(DMSC, LOGL_ERROR, "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");
|
||||
LOGP(DMSC, LOGL_ERROR, "Identity code missing. Audio routing will not work.\n");
|
||||
goto reject;
|
||||
}
|
||||
|
||||
@@ -500,7 +537,7 @@ static int bssmap_handle_assignm_req(struct sccp_connection *conn,
|
||||
* multi-slot, limiting the channel coding, speech...
|
||||
*/
|
||||
if (TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE) < 3) {
|
||||
DEBUGP(DMSC, "ChannelType len !=3 not supported: %d\n",
|
||||
LOGP(DMSC, LOGL_ERROR, "ChannelType len !=3 not supported: %d\n",
|
||||
TLVP_LEN(&tp, GSM0808_IE_CHANNEL_TYPE));
|
||||
goto reject;
|
||||
}
|
||||
@@ -512,12 +549,12 @@ static int bssmap_handle_assignm_req(struct sccp_connection *conn,
|
||||
|
||||
data = (u_int8_t *) TLVP_VAL(&tp, GSM0808_IE_CHANNEL_TYPE);
|
||||
if ((data[0] & 0xf) != 0x1) {
|
||||
DEBUGP(DMSC, "ChannelType != speech: %d\n", data[0]);
|
||||
LOGP(DMSC, LOGL_ERROR, "ChannelType != speech: %d\n", data[0]);
|
||||
goto reject;
|
||||
}
|
||||
|
||||
if (data[1] != GSM0808_SPEECH_FULL_PREF && data[1] != GSM0808_SPEECH_HALF_PREF) {
|
||||
DEBUGP(DMSC, "ChannelType full not allowed: %d\n", data[1]);
|
||||
LOGP(DMSC, LOGL_ERROR, "ChannelType full not allowed: %d\n", data[1]);
|
||||
goto reject;
|
||||
}
|
||||
|
||||
@@ -546,7 +583,7 @@ static int bssmap_handle_assignm_req(struct sccp_connection *conn,
|
||||
}
|
||||
|
||||
if (chan_mode == GSM48_CMODE_SIGN) {
|
||||
DEBUGP(DMSC, "No supported audio type found.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "No supported audio type found.\n");
|
||||
goto reject;
|
||||
}
|
||||
|
||||
@@ -567,7 +604,7 @@ static int bssmap_handle_assignm_req(struct sccp_connection *conn,
|
||||
else
|
||||
goto reject;
|
||||
} else {
|
||||
DEBUGP(DMSC, "Sending ChanModify for speech on: sccp: %p mode: 0x%x on port %d %d/0x%x port: %u\n",
|
||||
LOGP(DMSC, LOGL_ERROR, "Sending ChanModify for speech on: sccp: %p mode: 0x%x on port %d %d/0x%x port: %u\n",
|
||||
conn, chan_mode, port, multiplex, timeslot, msc_data->rtp_port);
|
||||
|
||||
if (chan_mode == GSM48_CMODE_SPEECH_AMR) {
|
||||
@@ -590,7 +627,7 @@ int bssmap_rcvmsg_udt(struct gsm_network *net, struct msgb *msg, unsigned int le
|
||||
int ret = 0;
|
||||
|
||||
if (length < 1) {
|
||||
DEBUGP(DMSC, "Not enough room: %d\n", length);
|
||||
LOGP(DMSC, LOGL_ERROR, "Not enough room: %d\n", length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -611,7 +648,7 @@ int bssmap_rcvmsg_dt1(struct sccp_connection *conn, struct msgb *msg, unsigned i
|
||||
int ret = 0;
|
||||
|
||||
if (length < 1) {
|
||||
DEBUGP(DMSC, "Not enough room: %d\n", length);
|
||||
LOGP(DMSC, LOGL_ERROR, "Not enough room: %d\n", length);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -626,7 +663,7 @@ int bssmap_rcvmsg_dt1(struct sccp_connection *conn, struct msgb *msg, unsigned i
|
||||
ret = bssmap_handle_assignm_req(conn, msg, length);
|
||||
break;
|
||||
default:
|
||||
DEBUGP(DMSC, "Unimplemented msg type: %d\n", msg->l4h[0]);
|
||||
LOGP(DMSC, LOGL_DEBUG, "Unimplemented msg type: %d\n", msg->l4h[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -641,29 +678,29 @@ int dtap_rcvmsg(struct gsm_lchan *lchan, struct msgb *msg, unsigned int length)
|
||||
u_int8_t link_id;
|
||||
|
||||
if (!lchan) {
|
||||
DEBUGP(DMSC, "No lchan available\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "No lchan available\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
header = (struct dtap_header *) msg->l3h;
|
||||
if (sizeof(*header) >= length) {
|
||||
DEBUGP(DMSC, "The DTAP header does not fit. Wanted: %u got: %u\n", sizeof(*header), length);
|
||||
DEBUGP(DMSC, "hex: %s\n", hexdump(msg->l3h, length));
|
||||
LOGP(DMSC, LOGL_ERROR, "The DTAP header does not fit. Wanted: %u got: %u\n", sizeof(*header), length);
|
||||
LOGP(DMSC, LOGL_ERROR, "hex: %s\n", hexdump(msg->l3h, length));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (header->length > length - sizeof(*header)) {
|
||||
DEBUGP(DMSC, "The DTAP l4 information does not fit: header: %u length: %u\n", header->length, length);
|
||||
DEBUGP(DMSC, "hex: %s\n", hexdump(msg->l3h, length));
|
||||
LOGP(DMSC, LOGL_ERROR, "The DTAP l4 information does not fit: header: %u length: %u\n", header->length, length);
|
||||
LOGP(DMSC, LOGL_ERROR, "hex: %s\n", hexdump(msg->l3h, length));
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUGP(DMSC, "DTAP message: SAPI: %u CHAN: %u\n", header->link_id & 0x07, header->link_id & 0xC0);
|
||||
LOGP(DMSC, LOGL_DEBUG, "DTAP message: SAPI: %u CHAN: %u\n", header->link_id & 0x07, header->link_id & 0xC0);
|
||||
|
||||
/* forward the data */
|
||||
gsm48 = gsm48_msgb_alloc();
|
||||
if (!gsm48) {
|
||||
DEBUGP(DMSC, "Allocation of the message failed.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Allocation of the message failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -884,7 +921,7 @@ static u_int8_t chan_mode_to_speech(struct gsm_lchan *lchan)
|
||||
case GSM48_CMODE_DATA_6k0:
|
||||
case GSM48_CMODE_DATA_3k6:
|
||||
default:
|
||||
DEBUGP(DMSC, "Using non speech mode: %d\n", mode);
|
||||
LOGP(DMSC, LOGL_ERROR, "Using non speech mode: %d\n", mode);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
@@ -937,7 +974,7 @@ static u_int8_t lchan_to_chosen_channel(struct gsm_lchan *lchan)
|
||||
channel = 0x9;
|
||||
break;
|
||||
case GSM_LCHAN_UNKNOWN:
|
||||
DEBUGP(DMSC, "Unknown lchan type: %p\n", lchan);
|
||||
LOGP(DMSC, LOGL_ERROR, "Unknown lchan type: %p\n", lchan);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1065,8 +1102,14 @@ static int bssap_handle_lchan_signal(unsigned int subsys, unsigned int signal,
|
||||
switch (signal) {
|
||||
case S_LCHAN_UNEXPECTED_RELEASE:
|
||||
/* handle this through the T10 timeout */
|
||||
if (lchan->msc_data->lchan != lchan)
|
||||
if (lchan->msc_data->lchan != lchan) {
|
||||
if (lchan->msc_data->secondary_lchan == lchan) {
|
||||
LOGP(DMSC, LOGL_NOTICE, "Setting secondary to NULL.\n");
|
||||
lchan->msc_data->secondary_lchan = NULL;
|
||||
lchan->msc_data = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bsc_del_timer(&lchan->msc_data->T10);
|
||||
conn = lchan->msc_data->sccp;
|
||||
@@ -1075,7 +1118,7 @@ static int bssap_handle_lchan_signal(unsigned int subsys, unsigned int signal,
|
||||
|
||||
msg = msgb_alloc(30, "sccp: clear request");
|
||||
if (!msg) {
|
||||
DEBUGP(DMSC, "Failed to allocate clear request.\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Failed to allocate clear request.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1088,7 +1131,7 @@ static int bssap_handle_lchan_signal(unsigned int subsys, unsigned int signal,
|
||||
msg->l3h[4] = 1;
|
||||
msg->l3h[5] = GSM0808_CAUSE_RADIO_INTERFACE_FAILURE;
|
||||
|
||||
DEBUGP(DMSC, "Sending clear request on unexpected channel release.\n");
|
||||
LOGP(DMSC, LOGL_NOTICE, "Sending clear request on unexpected channel release.\n");
|
||||
bsc_queue_connection_write(conn, msg);
|
||||
break;
|
||||
case S_LCHAN_ACTIVATE_ACK:
|
||||
@@ -1111,17 +1154,17 @@ void bsc_queue_connection_write(struct sccp_connection *conn, struct msgb *msg)
|
||||
data = (struct bss_sccp_connection_data *)conn->data_ctx;
|
||||
|
||||
if (conn->connection_state > SCCP_CONNECTION_STATE_ESTABLISHED) {
|
||||
DEBUGP(DMSC, "Connection closing, dropping packet on: %p\n", conn);
|
||||
LOGP(DMSC, LOGL_ERROR, "Connection closing, dropping packet on: %p\n", conn);
|
||||
msgb_free(msg);
|
||||
} else if (conn->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED
|
||||
&& data->sccp_queue_size == 0) {
|
||||
sccp_connection_write(conn, msg);
|
||||
msgb_free(msg);
|
||||
} else if (data->sccp_queue_size > 10) {
|
||||
DEBUGP(DMSC, "Dropping packet on %p due queue overflow\n", conn);
|
||||
LOGP(DMSC, LOGL_ERROR, "Dropping packet on %p due queue overflow\n", conn);
|
||||
msgb_free(msg);
|
||||
} else {
|
||||
DEBUGP(DMSC, "Queuing packet on %p. Queue size: %d\n", conn, data->sccp_queue_size);
|
||||
LOGP(DMSC, LOGL_DEBUG, "Queuing packet on %p. Queue size: %d\n", conn, data->sccp_queue_size);
|
||||
++data->sccp_queue_size;
|
||||
msgb_enqueue(&data->sccp_queue, msg);
|
||||
}
|
||||
@@ -1166,13 +1209,13 @@ static void rll_ind_cb(struct gsm_lchan *lchan, u_int8_t link_id,
|
||||
struct bss_sccp_connection_data *data = lchan->msc_data;
|
||||
|
||||
if (!data || !data->sccp) {
|
||||
DEBUGP(DMSC, "Time-out/Establish after sccp release? Ind: %d lchan: %p\n",
|
||||
LOGP(DMSC, LOGL_ERROR, "Time-out/Establish after sccp release? Ind: %d lchan: %p\n",
|
||||
rllr_ind, lchan);
|
||||
return;
|
||||
}
|
||||
|
||||
if (memcmp(&data->sccp->source_local_reference, &ref, sizeof(ref)) != 0) {
|
||||
DEBUGP(DMSC, "Wrong SCCP connection. Not handling RLL callback: %u %u\n",
|
||||
LOGP(DMSC, LOGL_ERROR, "Wrong SCCP connection. Not handling RLL callback: %u %u\n",
|
||||
sccp_src_ref_to_int(&ref),
|
||||
sccp_src_ref_to_int(&data->sccp->source_local_reference));
|
||||
return;
|
||||
@@ -1192,7 +1235,7 @@ static void rll_ind_cb(struct gsm_lchan *lchan, u_int8_t link_id,
|
||||
bts_free_queued(data);
|
||||
sapi_reject = bssmap_create_sapi_reject(link_id);
|
||||
if (!sapi_reject){
|
||||
DEBUGP(DMSC, "Failed to create SAPI reject\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "Failed to create SAPI reject\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1203,9 +1246,17 @@ static void rll_ind_cb(struct gsm_lchan *lchan, u_int8_t link_id,
|
||||
}
|
||||
|
||||
/* decide if we need to queue because of SAPI != 0 */
|
||||
void bts_queue_send(struct msgb *msg, int link_id)
|
||||
static void bts_queue_send(struct msgb *msg, int link_id)
|
||||
{
|
||||
struct bss_sccp_connection_data *data = msg->lchan->msc_data;
|
||||
|
||||
struct bss_sccp_connection_data *data;
|
||||
|
||||
if (!msg->lchan || !msg->lchan->msc_data) {
|
||||
LOGP(DMSC, LOGL_ERROR, "BAD: Wrongly configured lchan: %p\n", msg->lchan);
|
||||
msgb_free(msg);
|
||||
}
|
||||
|
||||
data = msg->lchan->msc_data;
|
||||
|
||||
if (!data->block_gsm && data->gsm_queue_size == 0) {
|
||||
if (msg->lchan->sapis[link_id & 0x7] != LCHAN_SAPI_UNUSED) {
|
||||
@@ -1221,9 +1272,10 @@ void bts_queue_send(struct msgb *msg, int link_id)
|
||||
(void *)sccp_src_ref_to_int(&data->sccp->source_local_reference));
|
||||
}
|
||||
} else if (data->gsm_queue_size == 10) {
|
||||
DEBUGP(DMSC, "Queue full on %p. Dropping GSM0408.\n", data->sccp);
|
||||
LOGP(DMSC, LOGL_ERROR, "Queue full on %p. Dropping GSM0408.\n", data->sccp);
|
||||
msgb_free(msg);
|
||||
} else {
|
||||
DEBUGP(DMSC, "Queueing GSM0408 message on %p. Queue size: %d\n",
|
||||
LOGP(DMSC, LOGL_DEBUG, "Queueing GSM0408 message on %p. Queue size: %d\n",
|
||||
data->sccp, data->gsm_queue_size + 1);
|
||||
|
||||
msg->smsh = (unsigned char*) link_id;
|
||||
@@ -1283,9 +1335,10 @@ void gsm0808_send_assignment_failure(struct gsm_lchan *lchan, u_int8_t cause, u_
|
||||
struct msgb *resp;
|
||||
|
||||
bsc_del_timer(&lchan->msc_data->T10);
|
||||
bssmap_free_secondary(lchan->msc_data);
|
||||
resp = bssmap_create_assignment_failure(cause, rr_value);
|
||||
if (!resp) {
|
||||
DEBUGP(DMSC, "Allocation failure: %p\n", lchan_get_sccp(lchan));
|
||||
LOGP(DMSC, LOGL_ERROR, "Allocation failure: %p\n", lchan_get_sccp(lchan));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1299,7 +1352,7 @@ void gsm0808_send_assignment_compl(struct gsm_lchan *lchan, u_int8_t rr_cause)
|
||||
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));
|
||||
LOGP(DMSC, LOGL_ERROR, "Creating MSC response failed: %p\n", lchan_get_sccp(lchan));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -322,14 +322,31 @@ void lchan_free(struct gsm_lchan *lchan)
|
||||
* channel using it */
|
||||
}
|
||||
|
||||
/* Consider releasing the channel now */
|
||||
int _lchan_release(struct gsm_lchan *lchan, u_int8_t release_reason)
|
||||
static int _lchan_release_next_sapi(struct gsm_lchan *lchan)
|
||||
{
|
||||
if (lchan->conn.use_count > 0) {
|
||||
DEBUGP(DRLL, "BUG: _lchan_release called without zero use_count.\n");
|
||||
int sapi;
|
||||
|
||||
for (sapi = 1; sapi < ARRAY_SIZE(lchan->sapis); ++sapi) {
|
||||
u_int8_t link_id;
|
||||
if (lchan->sapis[sapi] == LCHAN_SAPI_UNUSED)
|
||||
continue;
|
||||
|
||||
link_id = sapi;
|
||||
if (lchan->type == GSM_LCHAN_TCH_F || lchan->type == GSM_LCHAN_TCH_H)
|
||||
link_id |= 0x40;
|
||||
rsl_release_request(lchan, link_id, lchan->release_reason);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void _lchan_handle_release(struct gsm_lchan *lchan)
|
||||
{
|
||||
/* Ask for SAPI != 0 to be freed first and stop if we need to wait */
|
||||
if (_lchan_release_next_sapi(lchan) == 0)
|
||||
return;
|
||||
|
||||
/* Assume we have GSM04.08 running and send a release */
|
||||
if (lchan->conn.subscr) {
|
||||
++lchan->conn.use_count;
|
||||
@@ -342,8 +359,42 @@ int _lchan_release(struct gsm_lchan *lchan, u_int8_t release_reason)
|
||||
LOGP(DRLL, LOGL_ERROR, "Channel count is negative: %d\n",
|
||||
lchan->conn.use_count);
|
||||
|
||||
rsl_release_request(lchan, 0, lchan->release_reason);
|
||||
}
|
||||
|
||||
/* called from abis rsl */
|
||||
int rsl_lchan_rll_release(struct gsm_lchan *lchan, u_int8_t link_id)
|
||||
{
|
||||
if (lchan->state != LCHAN_S_REL_REQ)
|
||||
return -1;
|
||||
|
||||
if ((link_id & 0x7) != 0)
|
||||
_lchan_handle_release(lchan);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Start the channel release procedure now. We will start by shutting
|
||||
* down SAPI!=0, then we will deactivate the SACCH and finish by releasing
|
||||
* the last SAPI at which point the RSL code will send the channel release
|
||||
* for us. We should guard the whole shutdown by T3109 or similiar and then
|
||||
* update the fixme inside gsm_04_08_utils.c
|
||||
* When we request to release the RLL and we don't get an answer within T200
|
||||
* the BTS will send us an Error indication which we will handle by closing
|
||||
* the channel and be done.
|
||||
*/
|
||||
int _lchan_release(struct gsm_lchan *lchan, u_int8_t release_reason)
|
||||
{
|
||||
if (lchan->conn.use_count > 0) {
|
||||
DEBUGP(DRLL, "BUG: _lchan_release called without zero use_count.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUGP(DRLL, "%s Recycling Channel\n", gsm_lchan_name(lchan));
|
||||
rsl_release_request(lchan, 0, release_reason);
|
||||
rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ);
|
||||
lchan->release_reason = release_reason;
|
||||
_lchan_handle_release(lchan);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +88,7 @@ static const struct value_string lchan_s_names[] = {
|
||||
{ LCHAN_S_ACTIVE, "ACTIVE" },
|
||||
{ LCHAN_S_INACTIVE, "INACTIVE" },
|
||||
{ LCHAN_S_REL_REQ, "RELEASE REQUESTED" },
|
||||
{ LCHAN_S_REL_ERR, "RELEASE DUE ERROR" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
|
||||
@@ -134,6 +134,7 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts)
|
||||
return rc;
|
||||
}
|
||||
|
||||
rsl_lchan_set_state(new_lchan, LCHAN_S_ACT_REQ);
|
||||
llist_add(&ho->list, &bsc_handovers);
|
||||
/* we continue in the SS_LCHAN handler / ho_chan_activ_ack */
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <endian.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
@@ -122,8 +123,8 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
|
||||
rc = recvfrom(fd->fd, &buf, sizeof(buf), 0,
|
||||
(struct sockaddr *) &addr, &slen);
|
||||
if (rc < 0) {
|
||||
LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x errno: %d/%s\n",
|
||||
ENDPOINT_NUMBER(endp), errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -164,6 +165,12 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
|
||||
}
|
||||
}
|
||||
|
||||
/* do this before the loop handling */
|
||||
if (dest == DEST_NETWORK)
|
||||
++endp->in_bts;
|
||||
else
|
||||
++endp->in_remote;
|
||||
|
||||
/* dispatch */
|
||||
if (cfg->audio_loop)
|
||||
dest = !dest;
|
||||
|
||||
@@ -386,8 +386,14 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
|
||||
return create_response(500, "CRCX", trans_id);
|
||||
|
||||
if (endp->ci != CI_UNUSED) {
|
||||
LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n", ENDPOINT_NUMBER(endp));
|
||||
return create_response(500, "CRCX", trans_id);
|
||||
if (cfg->force_realloc) {
|
||||
LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
} else {
|
||||
LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
|
||||
ENDPOINT_NUMBER(endp));
|
||||
return create_response(500, "CRCX", trans_id);
|
||||
}
|
||||
}
|
||||
|
||||
/* parse CallID C: and LocalParameters L: */
|
||||
@@ -728,6 +734,7 @@ void mgcp_free_endp(struct mgcp_endpoint *endp)
|
||||
|
||||
endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
|
||||
endp->net_payload_type = endp->bts_payload_type = -1;
|
||||
endp->in_bts = endp->in_remote = 0;
|
||||
memset(&endp->remote, 0, sizeof(endp->remote));
|
||||
memset(&endp->bts, 0, sizeof(endp->bts));
|
||||
}
|
||||
|
||||
@@ -77,11 +77,12 @@ DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp",
|
||||
vty_out(vty, "MGCP is up and running with %u endpoints:%s", g_cfg->number_endpoints - 1, VTY_NEWLINE);
|
||||
for (i = 1; i < g_cfg->number_endpoints; ++i) {
|
||||
struct mgcp_endpoint *endp = &g_cfg->endpoints[i];
|
||||
vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u on %s%s",
|
||||
vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u on %s traffic in :%u/%u%s",
|
||||
i, endp->ci,
|
||||
ntohs(endp->net_rtp), ntohs(endp->net_rtcp),
|
||||
ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp),
|
||||
inet_ntoa(endp->bts), VTY_NEWLINE);
|
||||
inet_ntoa(endp->bts), endp->in_bts, endp->in_remote,
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
|
||||
@@ -148,9 +148,18 @@ int bsc_mgcp_policy_cb(struct mgcp_config *cfg, int endpoint, int state, const c
|
||||
talloc_free(bsc_endp->transaction_id);
|
||||
}
|
||||
|
||||
/* we need to generate a new and patched message */
|
||||
bsc_msg = bsc_mgcp_rewrite((char *) nat->mgcp_msg, nat->mgcp_length,
|
||||
nat->mgcp_cfg->source_addr, mgcp_endp->rtp_port);
|
||||
if (!bsc_msg) {
|
||||
LOGP(DMGCP, LOGL_ERROR, "Failed to patch the msg.\n");
|
||||
return MGCP_POLICY_CONT;
|
||||
}
|
||||
|
||||
|
||||
bsc_endp->transaction_id = talloc_strdup(nat, transaction_id);
|
||||
bsc_endp->bsc = bsc_con;
|
||||
bsc_endp->pending_delete = state == MGCP_ENDP_DLCX;
|
||||
bsc_endp->pending_delete = 0;
|
||||
|
||||
/* we need to update some bits */
|
||||
if (state == MGCP_ENDP_CRCX) {
|
||||
@@ -162,17 +171,13 @@ int bsc_mgcp_policy_cb(struct mgcp_config *cfg, int endpoint, int state, const c
|
||||
} else {
|
||||
mgcp_endp->bts = sock.sin_addr;
|
||||
}
|
||||
} else if (state == MGCP_ENDP_DLCX) {
|
||||
/* we will free the endpoint now in case the BSS does not respond */
|
||||
bsc_endp->pending_delete = 1;
|
||||
mgcp_free_endp(mgcp_endp);
|
||||
}
|
||||
|
||||
/* we need to generate a new and patched message */
|
||||
bsc_msg = bsc_mgcp_rewrite((char *) nat->mgcp_msg, nat->mgcp_length,
|
||||
nat->mgcp_cfg->source_addr, mgcp_endp->rtp_port);
|
||||
if (!bsc_msg) {
|
||||
LOGP(DMGCP, LOGL_ERROR, "Failed to patch the msg.\n");
|
||||
return MGCP_POLICY_CONT;
|
||||
}
|
||||
|
||||
bsc_write_mgcp_msg(bsc_con, bsc_msg);
|
||||
bsc_write(bsc_con, bsc_msg, NAT_IPAC_PROTO_MGCP);
|
||||
return MGCP_POLICY_DEFER;
|
||||
}
|
||||
|
||||
@@ -223,21 +228,26 @@ void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg)
|
||||
return;
|
||||
}
|
||||
|
||||
/* make it point to our endpoint if it was not deleted */
|
||||
if (bsc_endp->pending_delete) {
|
||||
bsc_endp->bsc = NULL;
|
||||
bsc_endp->pending_delete = 0;
|
||||
} else {
|
||||
endp->ci = bsc_mgcp_extract_ci((const char *) msg->l2h);
|
||||
}
|
||||
|
||||
/* free some stuff */
|
||||
talloc_free(bsc_endp->transaction_id);
|
||||
bsc_endp->transaction_id = NULL;
|
||||
|
||||
/* make it point to our endpoint */
|
||||
endp->ci = bsc_mgcp_extract_ci((const char *) msg->l2h);
|
||||
/*
|
||||
* rewrite the information. In case the endpoint was deleted
|
||||
* there should be nothing for us to rewrite so putting endp->rtp_port
|
||||
* with the value of 0 should be no problem.
|
||||
*/
|
||||
output = bsc_mgcp_rewrite((char * ) msg->l2h, msgb_l2len(msg),
|
||||
bsc->nat->mgcp_cfg->source_addr, endp->rtp_port);
|
||||
|
||||
if (bsc_endp->pending_delete) {
|
||||
mgcp_free_endp(endp);
|
||||
bsc_endp->bsc = NULL;
|
||||
bsc_endp->pending_delete = 0;
|
||||
}
|
||||
|
||||
if (!output) {
|
||||
LOGP(DMGCP, LOGL_ERROR, "Failed to rewrite MGCP msg.\n");
|
||||
return;
|
||||
@@ -447,6 +457,7 @@ int bsc_mgcp_init(struct bsc_nat *nat)
|
||||
nat->mgcp_cfg->audio_payload = -1;
|
||||
nat->mgcp_cfg->data = nat;
|
||||
nat->mgcp_cfg->policy_cb = bsc_mgcp_policy_cb;
|
||||
nat->mgcp_cfg->force_realloc = 1;
|
||||
nat->bsc_endpoints = talloc_zero_array(nat,
|
||||
struct bsc_endpoint,
|
||||
nat->mgcp_cfg->number_endpoints + 1);
|
||||
|
||||
@@ -58,8 +58,9 @@ static struct bsc_fd bsc_listen;
|
||||
|
||||
|
||||
static struct bsc_nat *nat;
|
||||
static void bsc_write(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length);
|
||||
static void bsc_send_data(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length, int);
|
||||
static void remove_bsc_connection(struct bsc_connection *connection);
|
||||
static void msc_send_reset(struct bsc_msc_connection *con);
|
||||
|
||||
struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num)
|
||||
{
|
||||
@@ -92,28 +93,27 @@ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
|
||||
static void send_reset_ack(struct bsc_connection *bsc)
|
||||
{
|
||||
static const u_int8_t gsm_reset_ack[] = {
|
||||
0x00, 0x13, 0xfd,
|
||||
0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01,
|
||||
0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03,
|
||||
0x00, 0x01, 0x31,
|
||||
};
|
||||
|
||||
bsc_write(bsc, gsm_reset_ack, sizeof(gsm_reset_ack));
|
||||
bsc_send_data(bsc, gsm_reset_ack, sizeof(gsm_reset_ack), IPAC_PROTO_SCCP);
|
||||
}
|
||||
|
||||
static void send_id_ack(struct bsc_connection *bsc)
|
||||
{
|
||||
static const u_int8_t id_ack[] = {
|
||||
0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK
|
||||
IPAC_MSGT_ID_ACK
|
||||
};
|
||||
|
||||
bsc_write(bsc, id_ack, sizeof(id_ack));
|
||||
bsc_send_data(bsc, id_ack, sizeof(id_ack), IPAC_PROTO_IPACCESS);
|
||||
}
|
||||
|
||||
static void send_id_req(struct bsc_connection *bsc)
|
||||
{
|
||||
static const u_int8_t id_req[] = {
|
||||
0, 17, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_GET,
|
||||
IPAC_MSGT_ID_GET,
|
||||
0x01, IPAC_IDTAG_UNIT,
|
||||
0x01, IPAC_IDTAG_MACADDR,
|
||||
0x01, IPAC_IDTAG_LOCATION1,
|
||||
@@ -124,7 +124,7 @@ static void send_id_req(struct bsc_connection *bsc)
|
||||
0x01, IPAC_IDTAG_SERNR,
|
||||
};
|
||||
|
||||
bsc_write(bsc, id_req, sizeof(id_req));
|
||||
bsc_send_data(bsc, id_req, sizeof(id_req), IPAC_PROTO_IPACCESS);
|
||||
}
|
||||
|
||||
static void nat_send_rlsd(struct sccp_connections *conn)
|
||||
@@ -153,6 +153,32 @@ static void nat_send_rlsd(struct sccp_connections *conn)
|
||||
}
|
||||
}
|
||||
|
||||
static void nat_send_rlc(struct sccp_source_reference *src,
|
||||
struct sccp_source_reference *dst)
|
||||
{
|
||||
struct sccp_connection_release_complete *rlc;
|
||||
struct msgb *msg;
|
||||
|
||||
msg = msgb_alloc_headroom(4096, 128, "rlc");
|
||||
if (!msg) {
|
||||
LOGP(DNAT, LOGL_ERROR, "Failed to allocate clear command.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
msg->l2h = msgb_put(msg, sizeof(*rlc));
|
||||
rlc = (struct sccp_connection_release_complete *) msg->l2h;
|
||||
rlc->type = SCCP_MSG_TYPE_RLC;
|
||||
rlc->destination_local_reference = *dst;
|
||||
rlc->source_local_reference = *src;
|
||||
|
||||
ipaccess_prepend_header(msg, IPAC_PROTO_SCCP);
|
||||
|
||||
if (write_queue_enqueue(&msc_con->write_queue, msg) != 0) {
|
||||
LOGP(DINP, LOGL_ERROR, "Failed to enqueue the write.\n");
|
||||
msgb_free(msg);
|
||||
}
|
||||
}
|
||||
|
||||
static void send_mgcp_reset(struct bsc_connection *bsc)
|
||||
{
|
||||
static const u_int8_t mgcp_reset[] = {
|
||||
@@ -169,36 +195,35 @@ static void send_mgcp_reset(struct bsc_connection *bsc)
|
||||
*/
|
||||
static void initialize_msc_if_needed()
|
||||
{
|
||||
static int init = 0;
|
||||
init = 1;
|
||||
if (nat->first_contact)
|
||||
return;
|
||||
|
||||
/* do we need to send a GSM 08.08 message here? */
|
||||
nat->first_contact = 1;
|
||||
msc_send_reset(msc_con);
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently we are lacking refcounting so we need to copy each message.
|
||||
*/
|
||||
static void bsc_write(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length)
|
||||
static void bsc_send_data(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length, int proto)
|
||||
{
|
||||
struct msgb *msg;
|
||||
|
||||
if (length > 4096) {
|
||||
if (length > 4096 - 128) {
|
||||
LOGP(DINP, LOGL_ERROR, "Can not send message of that size.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
msg = msgb_alloc(4096, "to-bsc");
|
||||
msg = msgb_alloc_headroom(4096, 128, "to-bsc");
|
||||
if (!msg) {
|
||||
LOGP(DINP, LOGL_ERROR, "Failed to allocate memory for BSC msg.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
msgb_put(msg, length);
|
||||
msg->l2h = msgb_put(msg, length);
|
||||
memcpy(msg->data, data, length);
|
||||
if (write_queue_enqueue(&bsc->write_queue, msg) != 0) {
|
||||
LOGP(DINP, LOGL_ERROR, "Failed to enqueue the write.\n");
|
||||
msgb_free(msg);
|
||||
}
|
||||
|
||||
bsc_write(bsc, msg, proto);
|
||||
}
|
||||
|
||||
static int forward_sccp_to_bts(struct msgb *msg)
|
||||
@@ -206,6 +231,7 @@ static int forward_sccp_to_bts(struct msgb *msg)
|
||||
struct sccp_connections *con;
|
||||
struct bsc_connection *bsc;
|
||||
struct bsc_nat_parsed *parsed;
|
||||
int proto;
|
||||
|
||||
/* filter, drop, patch the message? */
|
||||
parsed = bsc_nat_parse(msg);
|
||||
@@ -217,8 +243,10 @@ static int forward_sccp_to_bts(struct msgb *msg)
|
||||
if (bsc_nat_filter_ipa(DIR_BSC, msg, parsed))
|
||||
goto exit;
|
||||
|
||||
proto = parsed->ipa_proto;
|
||||
|
||||
/* Route and modify the SCCP packet */
|
||||
if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
|
||||
if (proto == IPAC_PROTO_SCCP) {
|
||||
switch (parsed->sccp_type) {
|
||||
case SCCP_MSG_TYPE_UDT:
|
||||
/* forward UDT messages to every BSC */
|
||||
@@ -252,7 +280,11 @@ static int forward_sccp_to_bts(struct msgb *msg)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!con)
|
||||
if (!con && parsed->sccp_type == SCCP_MSG_TYPE_RLSD) {
|
||||
LOGP(DNAT, LOGL_NOTICE, "Sending fake RLC on RLSD message to network.\n");
|
||||
/* Exchange src/dest for the reply */
|
||||
nat_send_rlc(parsed->dest_local_ref, parsed->src_local_ref);
|
||||
} else if (!con)
|
||||
LOGP(DNAT, LOGL_ERROR, "Unknown connection for msg type: 0x%x.\n", parsed->sccp_type);
|
||||
}
|
||||
|
||||
@@ -264,7 +296,7 @@ static int forward_sccp_to_bts(struct msgb *msg)
|
||||
return -1;
|
||||
}
|
||||
|
||||
bsc_write(con->bsc, msg->data, msg->len);
|
||||
bsc_send_data(con->bsc, msg->l2h, msgb_l2len(msg), proto);
|
||||
return 0;
|
||||
|
||||
send_to_all:
|
||||
@@ -276,7 +308,7 @@ send_to_all:
|
||||
if (parsed->ipa_proto == IPAC_PROTO_SCCP && parsed->gsm_type == BSS_MAP_MSG_PAGING) {
|
||||
bsc = bsc_nat_find_bsc(nat, msg);
|
||||
if (bsc)
|
||||
bsc_write(bsc, msg->data, msg->len);
|
||||
bsc_send_data(bsc, msg->l2h, msgb_l2len(msg), parsed->ipa_proto);
|
||||
else
|
||||
LOGP(DNAT, LOGL_ERROR, "Could not determine BSC for paging.\n");
|
||||
|
||||
@@ -287,7 +319,7 @@ send_to_all:
|
||||
if (!bsc->authenticated)
|
||||
continue;
|
||||
|
||||
bsc_write(bsc, msg->data, msg->len);
|
||||
bsc_send_data(bsc, msg->l2h, msgb_l2len(msg), parsed->ipa_proto);
|
||||
}
|
||||
|
||||
exit:
|
||||
@@ -303,10 +335,39 @@ static void msc_connection_was_lost(struct bsc_msc_connection *con)
|
||||
llist_for_each_entry_safe(bsc, tmp, &nat->bsc_connections, list_entry)
|
||||
remove_bsc_connection(bsc);
|
||||
|
||||
nat->first_contact = 0;
|
||||
bsc_mgcp_free_endpoints(nat);
|
||||
bsc_msc_schedule_connect(con);
|
||||
}
|
||||
|
||||
static void msc_send_reset(struct bsc_msc_connection *msc_con)
|
||||
{
|
||||
static const u_int8_t reset[] = {
|
||||
0x00, 0x12, 0xfd,
|
||||
0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe,
|
||||
0x02, 0x42, 0xfe, 0x06, 0x00, 0x04, 0x30, 0x04,
|
||||
0x01, 0x20
|
||||
};
|
||||
|
||||
struct msgb *msg;
|
||||
|
||||
msg = msgb_alloc_headroom(4096, 128, "08.08 reset");
|
||||
if (!msg) {
|
||||
LOGP(DMSC, LOGL_ERROR, "Failed to allocate reset msg.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
msg->l2h = msgb_put(msg, sizeof(reset));
|
||||
memcpy(msg->l2h, reset, msgb_l2len(msg));
|
||||
|
||||
if (write_queue_enqueue(&msc_con->write_queue, msg) != 0) {
|
||||
LOGP(DMSC, LOGL_ERROR, "Failed to enqueue reset msg.\n");
|
||||
msgb_free(msg);
|
||||
}
|
||||
|
||||
LOGP(DMSC, LOGL_NOTICE, "Scheduled GSM0808 reset msg for the MSC.\n");
|
||||
}
|
||||
|
||||
static int ipaccess_msc_read_cb(struct bsc_fd *bfd)
|
||||
{
|
||||
int error;
|
||||
|
||||
@@ -146,13 +146,13 @@ int bsc_write_mgcp(struct bsc_connection *bsc, const u_int8_t *data, unsigned in
|
||||
msg->l3h = msgb_put(msg, length);
|
||||
memcpy(msg->l3h, data, length);
|
||||
|
||||
return bsc_write_mgcp_msg(bsc, msg);
|
||||
return bsc_write(bsc, msg, NAT_IPAC_PROTO_MGCP);
|
||||
}
|
||||
|
||||
int bsc_write_mgcp_msg(struct bsc_connection *bsc, struct msgb *msg)
|
||||
int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int proto)
|
||||
{
|
||||
/* prepend the header */
|
||||
ipaccess_prepend_header(msg, NAT_IPAC_PROTO_MGCP);
|
||||
ipaccess_prepend_header(msg, proto);
|
||||
|
||||
if (write_queue_enqueue(&bsc->write_queue, msg) != 0) {
|
||||
LOGP(DINP, LOGL_ERROR, "Failed to enqueue the write.\n");
|
||||
|
||||
@@ -92,11 +92,16 @@ DEFUN(show_bsc, show_bsc_cmd, "show connections bsc",
|
||||
SHOW_STR "Display information about current BSCs")
|
||||
{
|
||||
struct bsc_connection *con;
|
||||
struct sockaddr_in sock;
|
||||
socklen_t len = sizeof(sock);
|
||||
|
||||
llist_for_each_entry(con, &_nat->bsc_connections, list_entry) {
|
||||
vty_out(vty, "BSC lac: %d, %d auth: %d fd: %d%s",
|
||||
getpeername(con->write_queue.bfd.fd, (struct sockaddr *) &sock, &len);
|
||||
vty_out(vty, "BSC lac: %d, %d auth: %d fd: %d peername: %s%s",
|
||||
con->cfg ? con->cfg->nr : -1,
|
||||
con->cfg ? con->cfg->lac : -1,
|
||||
con->authenticated, con->write_queue.bfd.fd, VTY_NEWLINE);
|
||||
con->authenticated, con->write_queue.bfd.fd,
|
||||
inet_ntoa(sock.sin_addr), VTY_NEWLINE);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
|
||||
@@ -208,11 +208,11 @@ static void paging_T3113_expired(void *data)
|
||||
sig_data.lchan = NULL;
|
||||
|
||||
/* must be destroyed before calling cbfn, to prevent double free */
|
||||
counter_inc(req->bts->network->stats.paging.expired);
|
||||
cbfn_param = req->cbfn_param;
|
||||
cbfn = req->cbfn;
|
||||
paging_remove_request(&req->bts->paging, req);
|
||||
|
||||
counter_inc(req->bts->network->stats.paging.expired);
|
||||
|
||||
dispatch_signal(SS_PAGING, S_PAGING_EXPIRED, &sig_data);
|
||||
if (cbfn)
|
||||
|
||||
@@ -652,7 +652,7 @@ static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan)
|
||||
vty_out(vty, " No Subscriber%s", VTY_NEWLINE);
|
||||
if (is_ipaccess_bts(lchan->ts->trx->bts)) {
|
||||
struct in_addr ia;
|
||||
ia.s_addr = lchan->abis_ip.bound_ip;
|
||||
ia.s_addr = htonl(lchan->abis_ip.bound_ip);
|
||||
vty_out(vty, " Bound IP: %s Port %u RTP_TYPE2=%u CONN_ID=%u%s",
|
||||
inet_ntoa(ia), lchan->abis_ip.bound_port,
|
||||
lchan->abis_ip.rtp_payload2, lchan->abis_ip.conn_id,
|
||||
@@ -955,6 +955,50 @@ DEFUN(show_stats,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(drop_bts,
|
||||
drop_bts_cmd,
|
||||
"drop bts connection [nr] (oml|rsl)",
|
||||
SHOW_STR "Debug/Simulation command to drop ipaccess BTS\n")
|
||||
{
|
||||
struct gsm_bts_trx *trx;
|
||||
struct gsm_bts *bts;
|
||||
unsigned int bts_nr;
|
||||
|
||||
bts_nr = atoi(argv[0]);
|
||||
if (bts_nr >= gsmnet->num_bts) {
|
||||
vty_out(vty, "BTS number must be between 0 and %d. It was %d.%s",
|
||||
gsmnet->num_bts, bts_nr, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
bts = gsm_bts_num(gsmnet, bts_nr);
|
||||
if (!bts) {
|
||||
vty_out(vty, "BTS Nr. %d could not be found.%s", bts_nr, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (!is_ipaccess_bts(bts)) {
|
||||
vty_out(vty, "This command only works for ipaccess.%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
|
||||
/* close all connections */
|
||||
if (strcmp(argv[1], "oml") == 0) {
|
||||
close(bts->oml_link->ts->driver.ipaccess.fd.fd);
|
||||
} else if (strcmp(argv[1], "rsl") == 0) {
|
||||
/* close all rsl connections */
|
||||
llist_for_each_entry(trx, &bts->trx_list, list) {
|
||||
close(trx->rsl_link->ts->driver.ipaccess.fd.fd);
|
||||
}
|
||||
} else {
|
||||
vty_out(vty, "Argument must be 'oml# or 'rsl'.%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net,
|
||||
cfg_net_cmd,
|
||||
"network",
|
||||
@@ -1287,7 +1331,7 @@ DECLARE_TIMER(3103, "Set the timeout value for HANDOVER.")
|
||||
DECLARE_TIMER(3105, "Currently not used.")
|
||||
DECLARE_TIMER(3107, "Currently not used.")
|
||||
DECLARE_TIMER(3109, "Currently not used.")
|
||||
DECLARE_TIMER(3111, "Currently not used.")
|
||||
DECLARE_TIMER(3111, "Set the RSL timeout to wait before releasing the RF Channel.")
|
||||
DECLARE_TIMER(3113, "Set the time to try paging a subscriber.")
|
||||
DECLARE_TIMER(3115, "Currently not used.")
|
||||
DECLARE_TIMER(3117, "Currently not used.")
|
||||
@@ -1922,6 +1966,8 @@ int bsc_vty_init(struct gsm_network *net)
|
||||
install_element(VIEW_NODE, &show_paging_cmd);
|
||||
install_element(VIEW_NODE, &show_stats_cmd);
|
||||
|
||||
install_element(VIEW_NODE, &drop_bts_cmd);
|
||||
|
||||
openbsc_vty_add_cmds();
|
||||
|
||||
install_element(CONFIG_NODE, &cfg_net_cmd);
|
||||
|
||||
Reference in New Issue
Block a user