Compare commits

..

42 Commits

Author SHA1 Message Date
Holger Hans Peter Freyther
2b4e366083 Bump the version to 0.3.94... 2010-04-09 17:18:25 +02:00
Holger Hans Peter Freyther
bf1eb64b02 [rsl] Set the right state when asking for the activation.
Set the state to activation to avoid a warning about the
getting a CHAN ACK without waiting for it. We set it in
the code to make sure it is set after all error checking
to avoid inconsistent state as the state is only set back
to NONE/ACT due replies from the BTS.
2010-04-09 15:04:17 +02:00
Holger Hans Peter Freyther
f0fbae94ea [rsl] Rework the lchan channel release procedure
1.) free every SAPI from 1-7 and wait for the confirmation
    and then continue until all of them are freed. If the
    SAPI is not torn down we will receive a timeout and then
    we force the RF Channel Release...
2.) once SAPI is down we send the RR Release, SACCH Deact
3.) the abis_rsl will see that all SAPIs are down and then
    will release channel...
2010-04-09 14:30:52 +02:00
Holger Hans Peter Freyther
8fe4df503c [rsl] Remove method that is not called by anything. 2010-04-09 13:06:56 +02:00
Holger Hans Peter Freyther
8da7103070 [rsl] Set the release state from within the lchan class
Currently our GSM04.11 code is closing the link for SAPI=3
and this would mean that the whole channel would be scheduled
for close... where we only want to close everything when freeing
the lchan or handling an error.
2010-04-09 12:44:21 +02:00
Holger Hans Peter Freyther
f73f6fad8c [rsl] Introduce a method to set the state of the lchan
Setting the state through a dedicated method allows us to
track the state transitions and check if they are done in
a proper way.
2010-04-09 12:42:37 +02:00
Holger Hans Peter Freyther
25cb84be12 [rsl] Introduce an error state for the lchan and set it on release
When we issue a RF Channel Release in case of a failure we receive
RLL release indications after the channel was tearn down and we
issue another RF Channel Release as a result. The channel allocator
might have already allocated this channel and we release the channel
again with another MS on it.

Make rsl_rf_chan_release take an error argument and make it set
a new state in case of an error and change the RF Channel Release
ack to not set the state back to none in case of an error but wait
for a timeout that is a bit higher than T3111.

I tested this with removing the battery during a phonecall and
waiting for the channel failure. With this test we only send the
release once.
2010-04-09 12:26:32 +02:00
Holger Hans Peter Freyther
d9ae25c1bf [rsl] Implement the T3111 timer to delay the RF Channel release 2010-04-09 11:53:35 +02:00
Holger Hans Peter Freyther
5c011366c9 [rsl] Check the assumption that RF Channel Release is sent during release
We assume that the lchan_free will initiate the release and
that when we handle the RLL release indication or the release
request as part of the shutdown sequence.
2010-04-09 11:53:12 +02:00
Holger Hans Peter Freyther
79e2d4230d bsc_msc_ip.c: Fix crash when gsmnet is not yet initialized. 2010-04-09 11:53:12 +02:00
Holger Hans Peter Freyther
8ecd029b12 [rsl] Move rf channel release scheduling to a new method
The current channel release has a couple of issues we will
need to fix in a set of upcoming commits.

The issues include:
    1.) sending release twice
    2.) reassigning the channel inbetween the relase..
2010-04-08 22:39:34 +02:00
Holger Hans Peter Freyther
3c0508e94a [vty] Add ipa specific command to provoke failures to test OML/RSL reconnect
We need to simulate OML/RSL failure in an easy and fast way
and adding a command to do so seems like a good way to achieve
this. The command is a bit misplaced, in one way it is no config
and does not belong into the config node but then again it does
not belong into the VIEW_NODE either as it is manipulating content.
2010-04-08 22:11:29 +02:00
Holger Hans Peter Freyther
f535aad612 bssap: Reset the msc_data on the lchan earlier/just in case
The refcount should drop to zero immediately and then the
msc_data would be reset automatically but it is better to
remove all traces of it right away.
2010-04-08 22:11:29 +02:00
Holger Hans Peter Freyther
d0ac8866f1 bssap: Use the new method to give up the secondary lchan and related resources 2010-04-08 22:11:24 +02:00
Holger Hans Peter Freyther
73f9a65f12 bssap: Forget the secondary lchan in the MSC data and forget the MSC data
We will handle sending the assignment failure inside the T10
timer but it is better to reset the secondary_lchan inside the
msc_data right away before we might accidently use it.
2010-04-08 21:35:00 +02:00
Holger Hans Peter Freyther
b2c55c49a8 bsc_msc_ip: Attempt to handle assignment failures more properly
1.) when we do get a assignment failure from the MS. It is coming
    on the old channel and not the new one. Fix the comparison. Also
    always reset the msc_data to NULL before dropping the reference
2.) the LCHAN signal handler in bssap.c claims that the T10 expire
    cb should free the secondary channel. It currently does not do
    it and we have to do it now...

the whole thing was not tested and even after this commit this
behavior is not heavily excercised... with OsmocoreBB we would be
able to do this in the future.
2010-04-08 21:29:31 +02:00
Holger Hans Peter Freyther
8dc241959c bsc_msc_ip.c: Move from DEBUG to LOG logging
Use the oppurtunity to flag errors as errors in the code
base.
2010-04-08 20:29:36 +02:00
Holger Hans Peter Freyther
f99709430a bsc_msc_ip.c: Mention the timestamp config option. 2010-04-08 20:17:12 +02:00
Holger Hans Peter Freyther
b9bc45b1b0 bssap: Speculative crash fix when queueing messages for the BTS
It appears to be possible that we attempt to submit a DTAP
on a SCCP connection when we have a channel without the msc_data
assigned. This change should fix the crash (which is not well
understood), fix a memleak in the case of the queue being full.
2010-04-08 20:09:48 +02:00
Holger Hans Peter Freyther
65d10c1320 bsc_msc_ip: Specify the size we can read directly...
data_len is wrong as well as we have reserved... specifying
it directly seems to make valgrind happy. This also means that
we might receive more than one UDP message and do not properly
forward things. I will need to investigate.
2010-04-08 17:07:45 +02:00
Holger Hans Peter Freyther
414ba77f75 [paging] Do not use request after it was was destroyed..
Increment the counter before we call the remove request
which is freeing the request...
2010-04-08 16:48:46 +02:00
Holger Hans Peter Freyther
59f2470650 nat: Handle unknown RLSD by send a RLC back to the network. 2010-04-08 11:28:12 +02:00
Holger Hans Peter Freyther
339dfdb624 nat: Attempt to handle exceptions on the fd and trat them as connection loss 2010-04-08 11:16:43 +02:00
Holger Hans Peter Freyther
9e2e2e04d1 nat: Print the IP address of the connected BSCs 2010-04-08 10:35:20 +02:00
Holger Hans Peter Freyther
2ab6db0153 nat: Rename variable to make it use msc in the name 2010-04-08 10:31:07 +02:00
Holger Hans Peter Freyther
6cb97bdebe nat: Attempt to have a single BSC write method
This method currently prepends the IPA header and sends
the data. In the future we might be able to use SCTP for
it.

We have to remove the IPA header from the static messages
for that to work.

This code is untested.
2010-04-08 10:24:57 +02:00
Holger Hans Peter Freyther
8c3694a282 Bump the version for the BSC. 2010-04-08 10:09:49 +02:00
Holger Hans Peter Freyther
191d23a889 nat: Rename bsc_write to bsc_send_data 2010-04-08 09:20:48 +02:00
Holger Hans Peter Freyther
a5963097ac bssap: Comment and code cleanup 2010-04-07 20:35:59 +02:00
Holger Hans Peter Freyther
221fb37518 bssap: Switch to use LOGP and pick some debug categories 2010-04-07 20:35:02 +02:00
Holger Hans Peter Freyther
4ec8a390cc bssap: Another possible null derference on the code.
We do not want to send a msg over the NULL lchan. Let us
return fast from here.
2010-04-07 20:22:21 +02:00
Holger Hans Peter Freyther
cf3f1c8b3d vty: Fix the byteorder... of the bound_ip
We are storing the bound_ip in host byteorder but when
using ntohl we need to convert it back to to network
byte order.
2010-04-07 15:39:16 +02:00
Holger Hans Peter Freyther
984f3b8047 bssap: Speculative crash fix. 2010-04-07 15:37:33 +02:00
Holger Hans Peter Freyther
ec1f15d513 [mgcp] Print the errno/strerror when we can not receive from our socket 2010-04-07 12:55:40 +02:00
Holger Hans Peter Freyther
b76cd5ed7e nat: Send the reset after we have received the init ack
Sending the reset right away will upset the MSC and we
need to wait for the first contact.
2010-04-07 11:20:36 +02:00
Holger Hans Peter Freyther
1592550d98 nat: Fix the reset message and prepend the IPA header 2010-04-07 11:11:11 +02:00
Holger Hans Peter Freyther
5cdf42b1a4 nat: Allow to realloc already allocated endpoints
E.g. when the MGCP on the BSS is not responding we could block
all of our endpoints. As we are mostly in the middle and forward
bits we will happily reallocate the endpoints.
2010-04-07 10:52:48 +02:00
Holger Hans Peter Freyther
3a6b1a41fb [mgcp] Add an option to allow using reallocing an endpoint
For some mode of operation it can be acceptable to reallocate
an already allocated endpoint. This can be the case when we
only deal with one call agent that is keeping track of the
endpoint but slightly confused.
2010-04-07 10:51:27 +02:00
Holger Hans Peter Freyther
1b5b3bbfdb nat: Send a GSM0808 message to the MSC when we are reconnecting
The rest of the code should filter the reset ack msg. This should
make the MSC give up all resources it had allocated for us.
2010-04-07 10:46:30 +02:00
Holger Hans Peter Freyther
3a67035411 nat: Attempt to make MGCP forwarding more robust
When not being able to allocate the msgb for the forwarded data
there is no point in keeping and preparing the transaction. So
we can move the msg creation a bit up and only do the allocations
after having done the msgb allocation.

When receiving a DLCX we will now delete the endpoint right away. This
means when a BSS does not respond to the DLCX our endpoint will not
be blocked. E.g. this could happen when the MGCP is restarting or
in similiar conditions. When the BSS is not responding we move the
burden up the chain to the CallAgent. We have to still keep track
of the transaction id and the bsc pointer to keep the mgcp forward
routine working.
2010-04-07 09:53:54 +02:00
Holger Hans Peter Freyther
cb1937a4c5 [mgcp] Count incoming RTP packets from the BTS and remote 2010-04-07 09:37:17 +02:00
Holger Hans Peter Freyther
3cfd5d6a02 bsc_msc_ip.c: Fix the -e command line option 2010-04-07 08:41:01 +02:00
23 changed files with 565 additions and 192 deletions

View File

@@ -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])])

View File

@@ -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);

View File

@@ -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

View File

@@ -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*);

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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)

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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 }
};

View File

@@ -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 */

View File

@@ -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;

View File

@@ -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));
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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");

View File

@@ -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;

View File

@@ -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)

View File

@@ -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);