Compare commits

...

63 Commits

Author SHA1 Message Date
Holger Hans Peter Freyther
61e5e7bd8b Bump version..
* ping pong and possible crash fix.
2010-05-03 17:27:07 +08:00
Holger Hans Peter Freyther
f7b06fbe0c bsc: Speculative crash fix.
Make sure the sccp_cc_timeout is stopped when we delete the
associated data. There is one crash report that indicates that
we have a pending timer that is inside freed memory.

A crash could have occured when the connection to the MSC was
lost while have unconfirmed connections.
2010-05-03 16:13:02 +08:00
Holger Hans Peter Freyther
45403b1804 nat/bsc: Send PONG on PING, send PING from the BSC too
We do want to send PING/PONG in both ways to have a heartbeat
on the TCP connection. When switching over to SCTP we can rely
on the builtin heartbeat functionality.
2010-05-03 11:51:07 +08:00
Holger Hans Peter Freyther
6782cea4bf nat: Send a IPA PING down the stream and wait for the pong.
We will send a ping every 20 seconds and if we have no pong
within 5 seconds we will close down the BSC connection and
wait for a reconnect. We will start this after having
authenticated the BSC and we stop the timer when destructing
the BSC connection.
2010-05-02 19:31:14 +08:00
Holger Hans Peter Freyther
ec7ecab66f nat: Allow to only show statistics for a given BSC Cfg. 2010-05-02 19:31:14 +08:00
Holger Hans Peter Freyther
d1287e379b nat: Do not allow a BSC to send auth messages twice. 2010-05-02 19:31:13 +08:00
Holger Hans Peter Freyther
3fb44f3e61 nat: Fix vty output for connected BSCs 2010-05-02 19:31:13 +08:00
Holger Hans Peter Freyther
d48bfe0e93 bssap: Store the link_id in the new msgb->cb.
Work with a new version of libosmocore that gets rid of
additional pointers.
2010-05-01 15:22:40 +08:00
Holger Hans Peter Freyther
41cdaf520d remove any reference to 'struct gsm_bts_link' 2010-05-01 15:19:14 +08:00
Harald Welte
f94418a129 gsm_04_11.c: Use msgb->l4h instead of sms->smsh, as the latter is gone 2010-05-01 15:18:37 +08:00
Holger Hans Peter Freyther
88b299ca24 configure.in: Bump the version due mem leak fixes.
The nat is stable and in testing..
2010-05-01 15:01:45 +08:00
Holger Hans Peter Freyther
58a2758e78 nat: Improve log message and refer to the BSC that was lost. 2010-05-01 10:37:15 +08:00
Holger Hans Peter Freyther
be3fdc2c6e nat: Fix memory leak... in MGCP forwarding
The code needs to be refactored but this is fixing the leak for
now. We used to forward everything to the BSC but now we handle
the DLCX locally and this means we need to clear the patched
message. We should refactor it to not generate the patched msg
until a lot later.
2010-05-01 10:31:53 +08:00
Holger Hans Peter Freyther
6a8d765334 [vty] Free the matched at the end of the routine.
Remove the return from the case labels and cleanup at
the end matched array at the end of the routine.
2010-04-30 13:24:09 +08:00
Holger Hans Peter Freyther
adebbfdfa7 [vty] Plug memory leak on auto completion.
I assume the original code crashed with a double free as we
have a cleanup at the end of the method. Return from the routine
like the case label below. This is fixing a memory leak I am
experimenting.
2010-04-30 13:18:05 +08:00
Holger Hans Peter Freyther
afccfb9380 [vty] Allow to create a buffer in a given context.
Stop using the global vty context for all allocations
and allow to embed the buffer into a given context, and
allocate sub buffers with the context of its parent.
2010-04-30 12:26:52 +08:00
Holger Hans Peter Freyther
0f7a8258f0 [vty] Move some allocations into the context of the vty. 2010-04-30 12:18:32 +08:00
Holger Hans Peter Freyther
2aa7f10939 [vty] Remove FIXME as it appears to do the right thing. 2010-04-30 11:33:34 +08:00
Holger Hans Peter Freyther
37ba5b3e35 nat: Report some more contexts 2010-04-30 11:08:22 +08:00
Holger Hans Peter Freyther
9f63d2b4ad [mgcp] Remove talloc.h header. 2010-04-29 21:03:43 +08:00
Holger Hans Peter Freyther
d21b5de8c0 nat: Do not use \n in the vty code.
When we really need a newline we need to use VTY_NEWLINE.
2010-04-27 15:35:14 +08:00
Holger Hans Peter Freyther
12b63716e2 nat: Add a command to close a given BSC Connection
This can be used to clear stale connections for a given BSC
or to force a reconnect of the BSC.
2010-04-27 13:21:39 +08:00
Holger Hans Peter Freyther
184961ea3e nat: Print the remote reference as well. 2010-04-27 13:11:18 +08:00
Holger Hans Peter Freyther
a9ec86029f Bump the version of OpenBSC. 2010-04-26 16:08:13 +08:00
Holger Hans Peter Freyther
d1b19f3308 [ts] Make the e1inp_ts delay configurable
Currently the nanoBTS bootstrap code requires a high delay
otherwise we are not bringing the device up properly. Changing
the init code turns out harder than it seems like. So this is
a workaround for that to allow a high speed RSL/OML connection
after the bringup.

The line driver can have a default TS delay. It is set to the
current default for the nanoBTS and the BS11. For the ipaccess
case we will set the delay lower for the RSL connection and
inside the ipaccess-config we can set it low right away to
have fast firmware flashing and such.
2010-04-26 16:02:04 +08:00
Holger Hans Peter Freyther
33f531fd12 ipaccess: Restore the original delay for the nanoBTS delay. 2010-04-26 10:33:56 +08:00
Holger Hans Peter Freyther
b051b3b161 bsc_init: Do not use magic numbers for GSM 12.21 states. 2010-04-26 10:32:34 +08:00
Holger Hans Peter Freyther
479a3aa707 bsc_init: Remove printf that sneaked in. 2010-04-26 10:27:42 +08:00
Holger Hans Peter Freyther
fd2a877e25 nat: Release the transaction id earlier, always reset the BSC
In case we can not find the SCCP connection we still want to
free any pending transaction ids and reset the BSC inside the
endpoint. In most cases this should be already done when the
SCCP connection or the whole BSC is gone.
2010-04-24 21:05:18 +08:00
Holger Hans Peter Freyther
53f797305f [mgcp] Possible memleak fix for the allowed reallocation case
When allowing to reallocate an allocated endpoint we will need
to free it first. When freeing we will free the call id and other
ids that we would have leaked otherwise.
2010-04-24 21:02:48 +08:00
Holger Hans Peter Freyther
691b40e834 nat: Attempt to clarify the text inside the log message. 2010-04-24 21:02:01 +08:00
Holger Hans Peter Freyther
e511d54dd0 nat: Allocate a named context to make dumping allocations possible
This is fixing the SIGUSR1 to really report the allocated
memory on stderr.
2010-04-23 21:56:57 +08:00
Holger Hans Peter Freyther
6edf7b9a51 bsc_msc_ip: Add a timeout for waiting for the CC of the network
Start a timeout to wait for the CC of the network and if it does
not come in time we will abort the connection and take down the
allocated lchans.
2010-04-23 18:22:26 +08:00
Holger Hans Peter Freyther
e4045679a8 nat: Only close connections that were fully connected
Remember that we have seen a CC and have a valid destination
local reference now and only send a fake RLC to the MSC when
we had connections in this state.
2010-04-23 14:13:27 +08:00
Holger Hans Peter Freyther
52ae9a461b nat: When having a proper close down, or a short read close the connection
For now close the connection when having a short read. This might
be due a network issue (loss of segment) or similiar. As we are not
handling these issues well, let us close the connection.
2010-04-23 00:23:03 +08:00
Holger Hans Peter Freyther
5bd9493257 nat: Only send DLCX when we have send a CRCX to the BSC on this endpoint 2010-04-22 20:12:13 +08:00
Holger Hans Peter Freyther
c92fd5d9d3 nat: Handle all queueing to the MSC through the same function. 2010-04-22 19:11:37 +08:00
Holger Hans Peter Freyther
01cf14d679 nat: Use show bsc config for showing the configuration. 2010-04-22 13:36:46 +08:00
Holger Hans Peter Freyther
840447e2bf [mgcp] Add a change callback and send a dummy packet on MDCX.
Send a dummy packet to make sure our Gateway will discover us
and can send the ringtone to us.
2010-04-22 13:23:05 +08:00
Holger Hans Peter Freyther
3f7586d571 nat: Use hex for the endpoint names 2010-04-22 13:06:24 +08:00
Holger Hans Peter Freyther
b74a9f13e5 [mgcp] Ignore every dummy packet...
This routine should operate on different packets and the
dummy load is smaller than a legitimate RTP header so it
is unlikely we will filture out genuine traffic.

The reason is the dummy load might be send more than once.
2010-04-22 12:15:38 +08:00
Holger Hans Peter Freyther
bbc2c6e765 nat: Change MGCP DLCX handling and send dummy MDCX to the BTS.
When setting a new MSC timeslot to a SCCP connection check if
any of the existing connections have this timeslot, if so we will
send a DLCX down the stream to make sure it is closed there, when
we will CRCX this new timeslot we will happily reallocate it.

When the SCCP connection goes away, or we get a DLCX from the
network, or the BSC is gone we will send a DLCX message down the
stream as well.

When we receive a CRCX from the network we will forward the CRCX
as usual and send a dummy MDCX after it.

For the DLCX and the dummy MDCX we send a custom MGCP message
that will not provoke an answer. Even if the downstream MGCP GW
will answer we will ignore it due the dummy transaction id that
is not used anywhere else.

This change should make sure that we close the dowstream endpoint
all the time, even when the DLCX arrives after the SCCP connection
is torndown.
2010-04-22 12:13:44 +08:00
Holger Hans Peter Freyther
7e3724ad18 nat: Move the write queue init to the allocation function
This is required for unit tests that want to queue messages
and see if we can provoke a memleak.
2010-04-22 12:13:44 +08:00
Holger Hans Peter Freyther
569dccf947 nat: Clear the queued messages at the end
It is possible that the calls from the loop would queue
more messages for the BSC and then we would have a nice
memory leak... Move it to the bottom.
2010-04-22 12:13:44 +08:00
Holger Hans Peter Freyther
89a378e9aa [mgcp] Protocol extension to not generate answers.
For the NAT we want to send requests in a send and forget
way and we are not interested in seeing the answers, so tell
the gateway to not answer them.
2010-04-22 12:13:44 +08:00
Holger Hans Peter Freyther
4a78c7b250 [mgcp] Print a Deleted endpoint message again. 2010-04-22 12:13:44 +08:00
Holger Hans Peter Freyther
c71013091a [mgcp] Add a dummy send method...
This can be used by higher level code to send one dummy
message from the audio port to the network. This can be
used to make the remote discover the nated port of this
endpoint.
2010-04-21 21:25:13 +08:00
Holger Hans Peter Freyther
4b1cde10fe [sccp] Move from DEBUGP to LOGP in sccp.c 2010-04-21 21:08:58 +08:00
Holger Hans Peter Freyther
0f5a2345d1 [nat] Degrade the message to a plain debug output. 2010-04-21 20:17:18 +08:00
Holger Hans Peter Freyther
ae81ff95ea [nat] Fix the vty option... use the right argument. 2010-04-21 20:07:07 +08:00
Holger Hans Peter Freyther
e5981edf6a [nat] Add option to forbid the paging to the BSC.
This can be done for testing purposes and to allow making
a BTS crash that can not handle paging requests properly.
2010-04-21 19:05:14 +08:00
Holger Hans Peter Freyther
93cc16ae4f [nat] Lookup by BSC Connection otherwise the point of reassigning the is defeated
When sending a MSG to the MSC try to find the to be used "src" reference
by comparing the reference on the BSC and the BSC connection. Only this
tuple needs to be unique.
Actually only when looking at the SRC REF we need to compare the BSC as the
dest reference should be unique but we are just making the check a bit stronger
to make it look symmetric.
2010-04-21 18:56:12 +08:00
Holger Hans Peter Freyther
119a1976f5 [nat] Slightly improve logging..
If we find the connection of a different BSC at least log the
BSCs that had duplicated references. We should also dump the
src ref and such but i am not doing this right now.
2010-04-21 18:49:55 +08:00
Holger Hans Peter Freyther
c53c2ab524 [nat] Ignore paging that is to page by BSS...
We do not want to handle this identity. If we can not page by
lac there is no need to page anything else.
2010-04-21 18:47:24 +08:00
Holger Hans Peter Freyther
32423500f6 [nat] Add unit test to forward Proto Error messages back both ways. 2010-04-21 15:46:38 +08:00
Holger Hans Peter Freyther
c3a6a1dbe5 [sccp] Parse the error message and add a unit test for it. 2010-04-21 15:46:38 +08:00
Holger Hans Peter Freyther
f4f090ee36 [nat] Reword warning when we had a pending transaction and forget about it. 2010-04-21 15:17:45 +08:00
Holger Hans Peter Freyther
2a554bfcc4 [nat] Cope with a bad BSC reassigning in use SRC REF
Some closed source BSC like to assign the SRC REF from a
small static pool and might reuses one we have not yet given
up on.
2010-04-21 10:47:25 +08:00
Holger Hans Peter Freyther
a12dea66ca [ipaccess] Attempt to fix setting unit ids with a multi trx setup
Add a --trx/-t NR option to set the TRX nr to be used when calling
set unit id and NVRAM. This was not tested and might or might not
work.
2010-04-20 22:22:00 +08:00
Holger Hans Peter Freyther
ec59bb04df Versioning for the bsc_msc_ip 2010-04-20 18:10:27 +08:00
Holger Hans Peter Freyther
4417f7f477 [vty] Allow to set the RACH NM attributes on a per BTS basis
Be able to tune the RACH settings of the BTS via the vty interface,
by default they are initialized to -1 which means we will use the
content of the static array (BTS default) and can be changed via
the VTY interface. I have verified the setting on the nanoBTS with
wireshark and I have tested writing the config file.
2010-04-20 18:02:25 +08:00
Holger Hans Peter Freyther
39563af27c [paging] Implement the counting for TCH/H and TCH/F
Add some code to count TCH/H and TCH/F and also handle
the neci bit of the network. Our channel allocator will
allocate a TCH/F if we request a TCH/H but can not allocate it.
2010-04-20 17:15:21 +08:00
Holger Hans Peter Freyther
242faaafd1 [paging] Only page if we have some free channels right now
Only page if we have a load that is acceptable for paging. This
option is off by default, and can be enabled per bts. The idea
is that when we have no resources right now we will not page as
it will only create more RACHs and increase the load.
2010-04-20 17:10:43 +08:00
33 changed files with 815 additions and 225 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.98.2onwaves)
AM_INIT_AUTOMAKE(openbsc, 0.3.99.3onwaves)
dnl kernel style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])

View File

@@ -93,6 +93,10 @@ struct bsc_connection {
/* a timeout node */
struct timer_list id_timeout;
/* pong timeout */
struct timer_list ping_timeout;
struct timer_list pong_timeout;
/* a back pointer */
struct bsc_nat *nat;
};
@@ -110,8 +114,10 @@ struct sccp_connections {
struct sccp_source_reference real_ref;
struct sccp_source_reference patched_ref;
struct sccp_source_reference remote_ref;
int has_remote_ref;
/* GSM audio handling. That is 32 * multiplex + ts */
int crcx;
int msc_timeslot;
int bsc_timeslot;
};
@@ -146,6 +152,8 @@ struct bsc_config {
char *imsi_deny;
regex_t imsi_deny_re;
int forbid_paging;
/* backpointer */
struct bsc_nat *nat;
@@ -160,8 +168,6 @@ struct bsc_endpoint {
char *transaction_id;
/* the bsc we are talking to */
struct bsc_connection *bsc;
/* pending delete */
int pending_delete;
};
/**
@@ -228,6 +234,7 @@ struct bsc_connection *bsc_connection_alloc(struct bsc_nat *nat);
void bsc_nat_set_msc_ip(struct bsc_nat *bsc, const char *ip);
void sccp_connection_destroy(struct sccp_connections *);
void bsc_close_connection(struct bsc_connection *);
/**
* parse the given message into the above structure
@@ -248,17 +255,17 @@ int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc
int update_sccp_src_ref(struct sccp_connections *sccp, struct bsc_nat_parsed *parsed);
void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed);
struct sccp_connections *patch_sccp_src_ref_to_bsc(struct msgb *, struct bsc_nat_parsed *, struct bsc_nat *);
struct sccp_connections *patch_sccp_src_ref_to_msc(struct msgb *, struct bsc_nat_parsed *, struct bsc_nat *);
struct sccp_connections *patch_sccp_src_ref_to_msc(struct msgb *, struct bsc_nat_parsed *, struct bsc_connection *);
/**
* MGCP/Audio handling
*/
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 *);
void bsc_mgcp_free_endpoint(struct bsc_nat *nat, int);
void bsc_mgcp_init(struct sccp_connections *);
void bsc_mgcp_dlcx(struct sccp_connections *);
void bsc_mgcp_free_endpoints(struct bsc_nat *nat);
int bsc_mgcp_init(struct bsc_nat *nat);
int bsc_mgcp_nat_init(struct bsc_nat *nat);
struct sccp_connections *bsc_mgcp_find_con(struct bsc_nat *, int endpoint_number);
struct msgb *bsc_mgcp_rewrite(char *input, int length, const char *ip, int port);

View File

@@ -66,6 +66,8 @@ struct e1inp_ts {
struct {
/* list of all signalling links on this TS */
struct llist_head sign_links;
/* delay for the queue */
int delay;
/* timer when to dequeue next frame */
struct timer_list tx_timer;
} sign;
@@ -93,6 +95,7 @@ struct e1inp_driver {
struct llist_head list;
const char *name;
int (*want_write)(struct e1inp_ts *ts);
int default_delay;
};
struct e1inp_line {

View File

@@ -85,11 +85,6 @@ typedef int gsm_cbfn(unsigned int hooknum,
struct msgb *msg,
void *data, void *param);
/* communications link with a BTS */
struct gsm_bts_link {
struct gsm_bts *bts;
};
struct sccp_connection;
/* Real authentication information containing Ki */
@@ -132,6 +127,7 @@ struct bss_sccp_connection_data {
struct timer_list T10;
/* for SCCP ... */
struct timer_list sccp_cc_timeout;
struct timer_list sccp_it;
/* audio handling */
@@ -407,6 +403,9 @@ struct gsm_bts_paging_state {
struct timer_list work_timer;
struct timer_list credit_timer;
/* free chans needed */
int free_chans_need;
/* load */
u_int16_t available_slots;
};
@@ -522,6 +521,10 @@ struct gsm_bts {
struct gsm_bts_gprs_nsvc nsvc[2];
u_int8_t rac;
} gprs;
/* RACH NM values */
int rach_b_thresh;
int rach_ldavg_slots;
/* transceivers */
int num_trx;

View File

@@ -73,5 +73,6 @@ struct mgcp_msg_ptr {
int mgcp_analyze_header(struct mgcp_config *cfg, struct msgb *msg,
struct mgcp_msg_ptr *ptr, int size,
const char **transaction_id, struct mgcp_endpoint **endp);
int mgcp_send_dummy(struct mgcp_endpoint *endp);
#endif

View File

@@ -411,4 +411,10 @@ struct sccp_data_it {
u_int8_t credit;
} __attribute__((packed));
struct sccp_proto_err {
u_int8_t type;
struct sccp_source_reference destination_local_reference;
u_int8_t error_cause;
};
#endif

View File

@@ -28,7 +28,7 @@
/* Create a new buffer. Memory will be allocated in chunks of the given
size. If the argument is 0, the library will supply a reasonable
default size suitable for buffering socket I/O. */
struct buffer *buffer_new(size_t);
struct buffer *buffer_new(void *ctx, size_t);
/* Free all data in the buffer. */
void buffer_reset(struct buffer *);

View File

@@ -418,16 +418,15 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
switch (obj_class) {
case NM_OC_SITE_MANAGER:
bts = container_of(obj, struct gsm_bts, site_mgr);
if ((new_state->operational == 2 &&
if ((new_state->operational == NM_OPSTATE_ENABLED &&
new_state->availability == NM_AVSTATE_OK) ||
(new_state->operational == 1 &&
(new_state->operational == NM_OPSTATE_DISABLED &&
new_state->availability == NM_AVSTATE_OFF_LINE))
abis_nm_opstart(bts, obj_class, 0xff, 0xff, 0xff);
break;
case NM_OC_BTS:
bts = obj;
if (new_state->availability == NM_AVSTATE_DEPENDENCY) {
printf("STARTING BTS...\n");
patch_nm_tables(bts);
abis_nm_set_bts_attr(bts, nanobts_attr_bts,
sizeof(nanobts_attr_bts));
@@ -441,9 +440,8 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
case NM_OC_CHANNEL:
ts = obj;
trx = ts->trx;
if (new_state->operational == 1 &&
if (new_state->operational == NM_OPSTATE_DISABLED &&
new_state->availability == NM_AVSTATE_DEPENDENCY) {
printf("STARTING OC Channel...\n");
patch_nm_tables(trx->bts);
enum abis_nm_chan_comb ccomb =
abis_nm_chcomb4pchan(ts->pchan);
@@ -457,7 +455,7 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
break;
case NM_OC_RADIO_CARRIER:
trx = obj;
if (new_state->operational == 1 &&
if (new_state->operational == NM_OPSTATE_DISABLED &&
new_state->availability == NM_AVSTATE_OK)
abis_nm_opstart(trx->bts, obj_class, trx->bts->bts_nr,
trx->nr, 0xff);
@@ -466,7 +464,7 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
bts = container_of(obj, struct gsm_bts, gprs.nse);
if (bts->gprs.mode == BTS_GPRS_NONE)
break;
if (new_state->availability == 5) {
if (new_state->availability == NM_AVSTATE_DEPENDENCY) {
abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
0xff, 0xff, nanobts_attr_nse,
sizeof(nanobts_attr_nse));
@@ -480,7 +478,7 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
bts = container_of(obj, struct gsm_bts, gprs.cell);
if (bts->gprs.mode == BTS_GPRS_NONE)
break;
if (new_state->availability == 5) {
if (new_state->availability == NM_AVSTATE_DEPENDENCY) {
abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
0, 0xff, nanobts_attr_cell,
sizeof(nanobts_attr_cell));
@@ -855,6 +853,22 @@ static void patch_nm_tables(struct gsm_bts *bts)
bs11_attr_radio[2] |= arfcn_high;
bs11_attr_radio[3] = arfcn_low;
/* patch the RACH attributes */
if (bts->rach_b_thresh != -1) {
nanobts_attr_bts[33] = bts->rach_b_thresh & 0xff;
bs11_attr_bts[33] = bts->rach_b_thresh & 0xff;
}
if (bts->rach_ldavg_slots != -1) {
u_int8_t avg_high = bts->rach_ldavg_slots & 0xff;
u_int8_t avg_low = (bts->rach_ldavg_slots >> 8) & 0x0f;
nanobts_attr_bts[35] = avg_high;
nanobts_attr_bts[36] = avg_low;
bs11_attr_bts[35] = avg_high;
bs11_attr_bts[36] = avg_low;
}
/* patch BSIC */
bs11_attr_bts[1] = bts->bsic;
nanobts_attr_bts[sizeof(nanobts_attr_bts)-11] = bts->bsic;

View File

@@ -60,13 +60,17 @@ static struct log_target *stderr_target;
struct gsm_network *bsc_gsmnet = 0;
static const char *config_file = "openbsc.cfg";
static char *msc_address = NULL;
static struct bsc_msc_connection *msc_con;
static struct in_addr local_addr;
static LLIST_HEAD(active_connections);
static struct write_queue mgcp_agent;
static const char *rf_ctl = NULL;
extern int ipacc_rtp_direct;
/* msc handling */
static struct bsc_msc_connection *msc_con;
static struct timer_list msc_ping_timeout;
static struct timer_list msc_pong_timeout;
extern int bsc_bootstrap_network(int (*layer4)(struct gsm_network *, int, void *), const char *cfg_file);
extern int bsc_shutdown_net(struct gsm_network *net);
@@ -95,6 +99,7 @@ struct bss_sccp_connection_data *bss_sccp_create_data()
void bss_sccp_free_data(struct bss_sccp_connection_data *data)
{
bsc_del_timer(&data->T10);
bsc_del_timer(&data->sccp_cc_timeout);
bsc_del_timer(&data->sccp_it);
if (data->sccp)
bsc_free_queued(data->sccp);
@@ -112,6 +117,41 @@ static void sccp_it_fired(void *_data)
bsc_schedule_timer(&data->sccp_it, SCCP_IT_TIMER, 0);
}
static void bss_force_close(struct bss_sccp_connection_data *bss)
{
if (bss->lchan) {
bss->lchan->msc_data = NULL;
put_subscr_con(&bss->lchan->conn, 0);
bss->lchan = NULL;
}
if (bss->secondary_lchan) {
bss->secondary_lchan->msc_data = NULL;
put_subscr_con(&bss->secondary_lchan->conn, 0);
bss->secondary_lchan = NULL;
}
/* force the close by poking stuff */
if (bss->sccp) {
sccp_connection_force_free(bss->sccp);
bss->sccp = NULL;
}
bss_sccp_free_data(bss);
}
/* check if this connection was ever confirmed and then recycle */
static void sccp_check_cc(void *_data)
{
struct bss_sccp_connection_data *data = _data;
if (data->sccp->connection_state >= SCCP_CONNECTION_STATE_ESTABLISHED)
return;
LOGP(DMSC, LOGL_ERROR, "The connection was never established\n");
bss_force_close(data);
}
/* GSM subscriber drop-ins */
extern struct llist_head *subscr_bsc_active_subscriber(void);
@@ -200,8 +240,12 @@ void msc_outgoing_sccp_state(struct sccp_connection *conn, int old_state)
LOGP(DMSC, LOGL_DEBUG, "Connection established: %p\n", conn);
/* start the inactivity test timer */
con_data = (struct bss_sccp_connection_data *) conn->data_ctx;
/* stop the CC timeout */
bsc_del_timer(&con_data->sccp_cc_timeout);
/* start the inactivity test timer */
con_data->sccp_it.cb = sccp_it_fired;
con_data->sccp_it.data = con_data;
bsc_schedule_timer(&con_data->sccp_it, SCCP_IT_TIMER, 0);
@@ -263,6 +307,11 @@ static int open_sccp_connection(struct msgb *layer3)
sccp_connection->data_ctx = con_data;
layer3->lchan->msc_data = con_data;
/* Make sure we open the connection */
con_data->sccp_cc_timeout.data = con_data;
con_data->sccp_cc_timeout.cb = sccp_check_cc;
bsc_schedule_timer(&con_data->sccp_cc_timeout, 10, 0);
/* FIXME: Use transaction for this */
use_subscr_con(&layer3->lchan->conn);
sccp_connection_connect(sccp_connection, &sccp_ssn_bssap, data);
@@ -820,31 +869,54 @@ static void msc_connection_was_lost(struct bsc_msc_connection *msc)
LOGP(DMSC, LOGL_ERROR, "Lost MSC connection. Freing stuff.\n");
llist_for_each_entry_safe(bss, tmp, &active_connections, active_connections) {
if (bss->lchan) {
bss->lchan->msc_data = NULL;
put_subscr_con(&bss->lchan->conn, 0);
bss->lchan = NULL;
}
if (bss->secondary_lchan) {
bss->secondary_lchan->msc_data = NULL;
put_subscr_con(&bss->secondary_lchan->conn, 0);
bss->secondary_lchan = NULL;
}
/* force the close by poking stuff */
if (bss->sccp) {
sccp_connection_force_free(bss->sccp);
bss->sccp = NULL;
}
bss_sccp_free_data(bss);
bss_force_close(bss);
}
bsc_del_timer(&msc_ping_timeout);
bsc_del_timer(&msc_pong_timeout);
msc->is_authenticated = 0;
bsc_msc_schedule_connect(msc);
}
static void msc_pong_timeout_cb(void *data)
{
LOGP(DMSC, LOGL_ERROR, "MSC didn't answer PING. Closing connection.\n");
bsc_msc_lost(msc_con);
}
static void send_ping(void)
{
struct msgb *msg;
msg = msgb_alloc_headroom(4096, 128, "ping");
if (!msg) {
LOGP(DMSC, LOGL_ERROR, "Failed to create PING.\n");
return;
}
msg->l2h = msgb_put(msg, 1);
msg->l2h[0] = IPAC_MSGT_PING;
msc_queue_write(msg, IPAC_PROTO_IPACCESS);
}
static void msc_ping_timeout_cb(void *data)
{
send_ping();
/* send another ping in 20 seconds */
bsc_schedule_timer(&msc_ping_timeout, 20, 0);
/* also start a pong timer */
bsc_schedule_timer(&msc_pong_timeout, 5, 0);
}
static void msc_connection_connected(struct bsc_msc_connection *con)
{
msc_ping_timeout_cb(con);
}
/*
* callback with IP access data
*/
@@ -877,6 +949,8 @@ static int ipaccess_a_fd_cb(struct bsc_fd *bfd)
initialize_if_needed();
else if (msg->l2h[0] == IPAC_MSGT_ID_GET) {
send_id_get_response(bfd->fd);
} else if (msg->l2h[0] == IPAC_MSGT_PONG) {
bsc_del_timer(&msc_pong_timeout);
}
} else if (hh->proto == IPAC_PROTO_SCCP) {
sccp_system_incoming(msg);
@@ -1105,7 +1179,11 @@ int main(int argc, char **argv)
exit(1);
}
msc_ping_timeout.cb = msc_ping_timeout_cb;
msc_pong_timeout.cb = msc_pong_timeout_cb;
msc_con->connection_loss = msc_connection_was_lost;
msc_con->connected = msc_connection_connected;
msc_con->write_queue.read_cb = ipaccess_a_fd_cb;
msc_con->write_queue.write_cb = msc_sccp_do_write;
bsc_msc_connect(msc_con);

View File

@@ -40,6 +40,8 @@
#define BSSMAP_MSG_SIZE 512
#define BSSMAP_MSG_HEADROOM 128
#define LINK_ID_CB 0
static void bts_queue_send(struct msgb *msg, int link_id);
static void bssmap_free_secondary(struct bss_sccp_connection_data *data);
@@ -1236,7 +1238,7 @@ static void bts_queue_send(struct msgb *msg, int link_id)
if (msg->lchan->sapis[link_id & 0x7] != LCHAN_SAPI_UNUSED) {
rsl_data_request(msg, link_id);
} else {
msg->smsh = (unsigned char*) link_id;
msg->cb[LINK_ID_CB] = link_id;
msgb_enqueue(&data->gsm_queue, msg);
++data->gsm_queue_size;
@@ -1252,7 +1254,7 @@ static void bts_queue_send(struct msgb *msg, int link_id)
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;
msg->cb[LINK_ID_CB] = link_id;
msgb_enqueue(&data->gsm_queue, msg);
++data->gsm_queue_size;
}
@@ -1278,7 +1280,7 @@ void bts_send_queued(struct bss_sccp_connection_data *data)
while (!llist_empty(&data->gsm_queue)) {
/* this is not allowed to fail */
msg = msgb_dequeue(&data->gsm_queue);
rsl_data_request(msg, (int) msg->smsh);
rsl_data_request(msg, msg->cb[LINK_ID_CB]);
}
data->gsm_queue_size = 0;
@@ -1300,7 +1302,7 @@ void bts_unblock_queue(struct bss_sccp_connection_data *data)
/* now queue them again to send RSL establish and such */
while (!llist_empty(&head)) {
msg = msgb_dequeue(&head);
bts_queue_send(msg, (int) msg->smsh);
bts_queue_send(msg, msg->cb[LINK_ID_CB]);
}
}

View File

@@ -303,6 +303,10 @@ int e1inp_ts_config(struct e1inp_ts *ts, struct e1inp_line *line,
switch (type) {
case E1INP_TS_TYPE_SIGN:
if (line->driver)
ts->sign.delay = line->driver->default_delay;
else
ts->sign.delay = 100000;
INIT_LLIST_HEAD(&ts->sign.sign_links);
break;
case E1INP_TS_TYPE_TRAU:

View File

@@ -675,7 +675,7 @@ static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm_trans *trans,
GSM411_RP_CAUSE_INV_MAND_INF);
return -EIO;
}
msg->smsh = tpdu;
msg->l4h = tpdu;
DEBUGP(DSMS, "DST(%u,%s)\n", dst_len, hexdump(dst, dst_len));

View File

@@ -257,7 +257,6 @@ int gsm0480_send_ussd_response(const struct msgb *in_msg, const char *response_t
if (((strlen(response_text) * 7) % 8) != 0)
response_len += 1;
msg->bts_link = in_msg->bts_link;
msg->lchan = in_msg->lchan;
/* First put the payload text into the message */
@@ -304,7 +303,6 @@ int gsm0480_send_ussd_reject(const struct msgb *in_msg,
struct msgb *msg = gsm48_msgb_alloc();
struct gsm48_hdr *gh;
msg->bts_link = in_msg->bts_link;
msg->lchan = in_msg->lchan;
/* First insert the problem code */

View File

@@ -222,6 +222,10 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type,
}
bts->c0->ts[0].pchan = GSM_PCHAN_CCCH_SDCCH4;
bts->paging.free_chans_need = -1;
bts->rach_b_thresh = -1;
bts->rach_ldavg_slots = -1;
llist_add_tail(&bts->list, &net->bts_list);
return bts;

View File

@@ -265,6 +265,7 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg,
trx->rsl_link = e1inp_sign_link_create(e1i_ts,
E1INP_SIGN_RSL, trx,
trx->rsl_tei, 0);
trx->rsl_link->ts->sign.delay = 10;
/* get rid of our old temporary bfd */
memcpy(newbfd, bfd, sizeof(*newbfd));
@@ -572,8 +573,7 @@ static int handle_ts1_write(struct bsc_fd *bfd)
e1i_ts->sign.tx_timer.data = e1i_ts;
/* Reducing this might break the nanoBTS 900 init. */
/* BAND AID for paging problem */
bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, 100);
bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, e1i_ts->sign.delay);
return ret;
}
@@ -607,6 +607,7 @@ static int ipaccess_fd_cb(struct bsc_fd *bfd, unsigned int what)
struct e1inp_driver ipaccess_driver = {
.name = "ip.access",
.want_write = ts_want_write,
.default_delay = 100000,
};
/* callback of the OML listening filedescriptor */

View File

@@ -235,7 +235,7 @@ static int handle_ts1_write(struct bsc_fd *bfd)
/* set tx delay timer for next event */
e1i_ts->sign.tx_timer.cb = timeout_ts1_write;
e1i_ts->sign.tx_timer.data = e1i_ts;
bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, 50000);
bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, e1i_ts->sign.delay);
return ret;
}
@@ -375,6 +375,7 @@ static int activate_bchan(struct e1inp_line *line, int ts, int act)
struct e1inp_driver misdn_driver = {
.name = "mISDNuser",
.want_write = ts_want_write,
.default_delay = 50000,
};
static int mi_e1_setup(struct e1inp_line *line, int release_l2)

View File

@@ -59,6 +59,7 @@ static int sw_load_state = 0;
static int oml_state = 0;
static int dump_files = 0;
static char *firmware_analysis = NULL;
static int trx_nr = 0;
struct sw_load {
u_int8_t file_id[255];
@@ -316,7 +317,8 @@ static void bootstrap_om(struct gsm_bts *bts)
memcpy(buf+3, unit_id, len);
buf[3+len] = 0;
printf("setting Unit ID to '%s'\n", unit_id);
abis_nm_ipaccess_set_nvattr(bts->c0, buf, 3+len+1);
abis_nm_ipaccess_set_nvattr(gsm_bts_trx_by_nr(bts, trx_nr),
buf, 3+len+1);
}
if (prim_oml_ip) {
struct in_addr ia;
@@ -354,7 +356,8 @@ static void bootstrap_om(struct gsm_bts *bts)
*cur++ = nv_mask >> 8;
printf("setting NV Flags/Mask to 0x%04x/0x%04x\n",
nv_flags, nv_mask);
abis_nm_ipaccess_set_nvattr(bts->c0, buf, 3+len);
abis_nm_ipaccess_set_nvattr(gsm_bts_trx_by_nr(bts, trx_nr),
buf, 3+len);
}
if (restart && !prim_oml_ip && !software) {
@@ -605,6 +608,7 @@ static void print_help(void)
printf(" -d --software firmware\n");
printf(" -f --firmware firmware Provide firmware information\n");
printf(" -w --write-firmware. This will dump the firmware parts to the filesystem. Use with -f.\n");
printf(" -t --trx NR. The TRX to use for the Unit ID and NVRAM attributes.\n");
}
int main(int argc, char **argv)
@@ -639,9 +643,11 @@ int main(int argc, char **argv)
{ "software", 1, 0, 'd' },
{ "firmware", 1, 0, 'f' },
{ "write-firmware", 0, 0, 'w' },
{ "trx", 1, 0, 't' },
{ 0, 0, 0, 0 },
};
c = getopt_long(argc, argv, "u:o:rn:l:hs:d:f:w", long_options,
c = getopt_long(argc, argv, "u:o:rn:l:hs:d:f:wt:", long_options,
&option_index);
if (c == -1)
@@ -683,6 +689,9 @@ int main(int argc, char **argv)
case 'w':
dump_files = 1;
break;
case 't':
trx_nr = atoi(optarg);
break;
case 'h':
print_usage();
print_help();
@@ -724,6 +733,8 @@ int main(int argc, char **argv)
exit(1);
}
bts->oml_link->ts->sign.delay = 10;
bts->c0->rsl_link->ts->sign.delay = 10;
while (1) {
rc = bsc_select_main(0);
if (rc < 0)

View File

@@ -128,6 +128,15 @@ static int mgcp_rsip_cb(struct mgcp_config *cfg)
return 0;
}
static int mgcp_change_cb(struct mgcp_config *cfg, int endpoint, int state, int local_rtp)
{
if (state != MGCP_ENDP_MDCX)
return 0;
mgcp_send_dummy(&cfg->endpoints[endpoint]);
return 0;
}
static int read_call_agent(struct bsc_fd *fd, unsigned int what)
{
struct sockaddr_in addr;
@@ -200,6 +209,7 @@ int main(int argc, char** argv)
/* set some callbacks */
cfg->reset_cb = mgcp_rsip_cb;
cfg->change_cb = mgcp_change_cb;
/* we need to bind a socket */
if (rc == 0) {

View File

@@ -31,7 +31,6 @@
#include <arpa/inet.h>
#include <osmocore/msgb.h>
#include <osmocore/talloc.h>
#include <osmocore/select.h>
#include <openbsc/debug.h>
@@ -73,6 +72,8 @@ enum {
PROTO_RTCP,
};
#define DUMMY_LOAD 0x23
static int udp_send(int fd, struct in_addr *addr, int port, char *buf, int len)
{
@@ -84,6 +85,14 @@ static int udp_send(int fd, struct in_addr *addr, int port, char *buf, int len)
return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out));
}
int mgcp_send_dummy(struct mgcp_endpoint *endp)
{
static char buf[] = { DUMMY_LOAD };
return udp_send(endp->local_rtp.fd, &endp->remote,
endp->net_rtp, buf, 1);
}
static void patch_payload(int payload, char *data, int len)
{
struct rtp_hdr *rtp_hdr;
@@ -163,9 +172,17 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
LOGP(DMGCP, LOGL_NOTICE, "Found BTS for endpoint: 0x%x on port: %d/%d of %s\n",
ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp),
inet_ntoa(addr.sin_addr));
}
}
/* throw away dummy message */
if (rc == 1 && buf[0] == DUMMY_LOAD) {
LOGP(DMGCP, LOGL_NOTICE, "Filtered dummy on 0x%x\n",
ENDPOINT_NUMBER(endp));
return 0;
}
/* do this before the loop handling */
if (dest == DEST_NETWORK)
++endp->in_bts;

View File

@@ -389,6 +389,7 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
if (cfg->force_realloc) {
LOGP(DMGCP, LOGL_NOTICE, "Endpoint 0x%x already allocated. Forcing realloc.\n",
ENDPOINT_NUMBER(endp));
mgcp_free_endp(endp);
} else {
LOGP(DMGCP, LOGL_ERROR, "Endpoint is already used. 0x%x\n",
ENDPOINT_NUMBER(endp));
@@ -485,6 +486,7 @@ static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg)
const char *trans_id;
struct mgcp_endpoint *endp;
int error_code = 500;
int silent = 0;
found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
if (found != 0)
@@ -517,6 +519,9 @@ static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg)
goto error3;
}
break;
case 'Z':
silent = strcmp("noanswer", (const char *)&msg->l3h[line_start + 3]) == 0;
break;
case '\0':
/* SDP file begins */
break;
@@ -562,6 +567,8 @@ static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg)
case MGCP_POLICY_REJECT:
LOGP(DMGCP, LOGL_NOTICE, "MDCX rejected by policy on 0x%x\n",
ENDPOINT_NUMBER(endp));
if (silent)
goto out_silent;
return create_response(500, "MDCX", trans_id);
break;
case MGCP_POLICY_DEFER:
@@ -579,6 +586,9 @@ static struct msgb *handle_modify_con(struct mgcp_config *cfg, struct msgb *msg)
ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), ntohs(endp->net_rtp));
if (cfg->change_cb)
cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_MDCX, endp->rtp_port);
if (silent)
goto out_silent;
return create_response_with_sdp(endp, "MDCX", trans_id);
error:
@@ -589,6 +599,10 @@ error:
error3:
return create_response(error_code, "MDCX", trans_id);
out_silent:
return NULL;
}
static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
@@ -598,6 +612,7 @@ static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
const char *trans_id;
struct mgcp_endpoint *endp;
int error_code = 500;
int silent = 0;
found = mgcp_analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
if (found != 0)
@@ -619,6 +634,9 @@ static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
if (verify_ci(endp, (const char *)&msg->l3h[line_start + 3]) != 0)
goto error3;
break;
case 'Z':
silent = strcmp("noanswer", (const char *)&msg->l3h[line_start + 3]) == 0;
break;
}
default:
LOGP(DMGCP, LOGL_NOTICE, "Unhandled option: '%c'/%d on 0x%x\n",
@@ -634,6 +652,8 @@ static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
case MGCP_POLICY_REJECT:
LOGP(DMGCP, LOGL_NOTICE, "DLCX rejected by policy on 0x%x\n",
ENDPOINT_NUMBER(endp));
if (silent)
goto out_silent;
return create_response(500, "DLCX", trans_id);
break;
case MGCP_POLICY_DEFER:
@@ -647,10 +667,14 @@ static struct msgb *handle_delete_con(struct mgcp_config *cfg, struct msgb *msg)
}
/* free the connection */
LOGP(DMGCP, LOGL_NOTICE, "Deleted endpoint on: 0x%x Server: %s:%u\n",
ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), ntohs(endp->net_rtp));
mgcp_free_endp(endp);
if (cfg->change_cb)
cfg->change_cb(cfg, ENDPOINT_NUMBER(endp), MGCP_ENDP_DLCX, endp->rtp_port);
if (silent)
goto out_silent;
return create_response(250, "DLCX", trans_id);
error:
@@ -661,6 +685,9 @@ error:
error3:
return create_response(error_code, "DLCX", trans_id);
out_silent:
return NULL;
}
static struct msgb *handle_rsip(struct mgcp_config *cfg, struct msgb *msg)

View File

@@ -26,6 +26,8 @@
#include <openbsc/mgcp.h>
#include <openbsc/mgcp_internal.h>
#include <sccp/sccp.h>
#include <osmocore/talloc.h>
#include <osmocore/gsm0808.h>
@@ -37,10 +39,12 @@
int bsc_mgcp_assign(struct sccp_connections *con, struct msgb *msg)
{
struct sccp_connections *mcon;
struct tlv_parsed tp;
u_int16_t cic;
u_int8_t timeslot;
u_int8_t multiplex;
int combined;
if (!msg->l3h) {
LOGP(DNAT, LOGL_ERROR, "Assignment message should have l3h pointer.\n");
@@ -62,18 +66,27 @@ int bsc_mgcp_assign(struct sccp_connections *con, struct msgb *msg)
timeslot = cic & 0x1f;
multiplex = (cic & ~0x1f) >> 5;
con->msc_timeslot = (32 * multiplex) + timeslot;
combined = (32 * multiplex) + timeslot;
/* find stale connections using that endpoint */
llist_for_each_entry(mcon, &con->bsc->nat->sccp_connections, list_entry) {
if (mcon->msc_timeslot == combined) {
LOGP(DNAT, LOGL_ERROR,
"Timeslot %d was assigned to 0x%x and now 0x%x\n",
combined,
sccp_src_ref_to_int(&mcon->patched_ref),
sccp_src_ref_to_int(&con->patched_ref));
bsc_mgcp_dlcx(mcon);
}
}
con->msc_timeslot = combined;
con->bsc_timeslot = con->msc_timeslot;
return 0;
}
void bsc_mgcp_clear(struct sccp_connections *con)
{
con->msc_timeslot = -1;
con->bsc_timeslot = -1;
}
void bsc_mgcp_free_endpoint(struct bsc_nat *nat, int i)
static void bsc_mgcp_free_endpoint(struct bsc_nat *nat, int i)
{
if (nat->bsc_endpoints[i].transaction_id) {
talloc_free(nat->bsc_endpoints[i].transaction_id);
@@ -81,17 +94,75 @@ void bsc_mgcp_free_endpoint(struct bsc_nat *nat, int i)
}
nat->bsc_endpoints[i].bsc = NULL;
mgcp_free_endp(&nat->mgcp_cfg->endpoints[i]);
}
void bsc_mgcp_free_endpoints(struct bsc_nat *nat)
{
int i;
for (i = 1; i < nat->mgcp_cfg->number_endpoints; ++i)
for (i = 1; i < nat->mgcp_cfg->number_endpoints; ++i){
bsc_mgcp_free_endpoint(nat, i);
mgcp_free_endp(&nat->mgcp_cfg->endpoints[i]);
}
}
/* send a MDCX where we do not want a response */
static void bsc_mgcp_send_mdcx(struct bsc_connection *bsc, struct mgcp_endpoint *endp)
{
char buf[2096];
int len;
len = snprintf(buf, sizeof(buf),
"MDCX 23 %x@mgw MGCP 1.0\r\n"
"Z: noanswer\r\n"
"\r\n"
"c=IN IP4 %s\r\n"
"m=audio %d RTP/AVP 255\r\n",
ENDPOINT_NUMBER(endp),
bsc->nat->mgcp_cfg->source_addr,
endp->rtp_port);
if (len < 0) {
LOGP(DMGCP, LOGL_ERROR, "snprintf for DLCX failed.\n");
return;
}
}
static void bsc_mgcp_send_dlcx(struct bsc_connection *bsc, int endpoint)
{
char buf[2096];
int len;
len = snprintf(buf, sizeof(buf),
"DLCX 23 %x@mgw MGCP 1.0\r\n"
"Z: noanswer\r\n", endpoint);
if (len < 0) {
LOGP(DMGCP, LOGL_ERROR, "snprintf for DLCX failed.\n");
return;
}
bsc_write_mgcp(bsc, (u_int8_t *) buf, len);
}
void bsc_mgcp_init(struct sccp_connections *con)
{
con->msc_timeslot = -1;
con->bsc_timeslot = -1;
con->crcx = 0;
}
void bsc_mgcp_dlcx(struct sccp_connections *con)
{
/* send a DLCX down the stream */
if (con->bsc_timeslot != -1 && con->crcx) {
int endp = mgcp_timeslot_to_endpoint(0, con->msc_timeslot);
bsc_mgcp_send_dlcx(con->bsc, endp);
bsc_mgcp_free_endpoint(con->bsc->nat, endp);
}
bsc_mgcp_init(con);
}
struct sccp_connections *bsc_mgcp_find_con(struct bsc_nat *nat, int endpoint)
{
struct sccp_connections *con = NULL;
@@ -125,10 +196,18 @@ int bsc_mgcp_policy_cb(struct mgcp_config *cfg, int endpoint, int state, const c
bsc_endp = &nat->bsc_endpoints[endpoint];
mgcp_endp = &nat->mgcp_cfg->endpoints[endpoint];
if (bsc_endp->transaction_id) {
LOGP(DMGCP, LOGL_ERROR, "Endpoint 0x%x had pending transaction: '%s'\n",
endpoint, bsc_endp->transaction_id);
talloc_free(bsc_endp->transaction_id);
bsc_endp->transaction_id = NULL;
}
bsc_endp->bsc = NULL;
sccp = bsc_mgcp_find_con(nat, endpoint);
if (!sccp) {
LOGP(DMGCP, LOGL_ERROR, "Did not find BSC for a new connection on 0x%x for %d\n", endpoint, state);
LOGP(DMGCP, LOGL_ERROR, "Did not find BSC for change on endpoint: 0x%x state: %d\n", endpoint, state);
switch (state) {
case MGCP_ENDP_CRCX:
@@ -147,12 +226,6 @@ int bsc_mgcp_policy_cb(struct mgcp_config *cfg, int endpoint, int state, const c
}
}
if (bsc_endp->transaction_id) {
LOGP(DMGCP, LOGL_ERROR, "One transaction with id '%s' on 0x%x\n",
bsc_endp->transaction_id, endpoint);
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);
@@ -164,7 +237,6 @@ int bsc_mgcp_policy_cb(struct mgcp_config *cfg, int endpoint, int state, const c
bsc_endp->transaction_id = talloc_strdup(nat, transaction_id);
bsc_endp->bsc = sccp->bsc;
bsc_endp->pending_delete = 0;
/* we need to update some bits */
if (state == MGCP_ENDP_CRCX) {
@@ -176,15 +248,21 @@ 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_mgcp_clear(sccp);
bsc_endp->pending_delete = 1;
mgcp_free_endp(mgcp_endp);
}
bsc_write(sccp->bsc, bsc_msg, NAT_IPAC_PROTO_MGCP);
return MGCP_POLICY_DEFER;
/* send the message and a fake MDCX for force sending of a dummy packet */
sccp->crcx = 1;
bsc_write(sccp->bsc, bsc_msg, NAT_IPAC_PROTO_MGCP);
bsc_mgcp_send_mdcx(sccp->bsc, mgcp_endp);
return MGCP_POLICY_DEFER;
} else if (state == MGCP_ENDP_DLCX) {
/* we will free the endpoint now and send a DLCX to the BSC */
msgb_free(bsc_msg);
bsc_mgcp_dlcx(sccp);
return MGCP_POLICY_CONT;
} else {
bsc_write(sccp->bsc, bsc_msg, NAT_IPAC_PROTO_MGCP);
return MGCP_POLICY_DEFER;
}
}
/*
@@ -234,13 +312,7 @@ 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);
}
endp->ci = bsc_mgcp_extract_ci((const char *) msg->l2h);
/* free some stuff */
talloc_free(bsc_endp->transaction_id);
@@ -401,7 +473,7 @@ static int mgcp_do_write(struct bsc_fd *bfd, struct msgb *msg)
return rc;
}
int bsc_mgcp_init(struct bsc_nat *nat)
int bsc_mgcp_nat_init(struct bsc_nat *nat)
{
int on;
struct sockaddr_in addr;
@@ -481,11 +553,7 @@ void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc)
if (bsc_endp->bsc != bsc)
continue;
bsc_endp->bsc = NULL;
bsc_endp->pending_delete = 0;
if (bsc_endp->transaction_id)
talloc_free(bsc_endp->transaction_id);
bsc_endp->transaction_id = NULL;
bsc_mgcp_free_endpoint(bsc->nat, i);
mgcp_free_endp(&bsc->nat->mgcp_cfg->endpoints[i]);
}
}

View File

@@ -59,7 +59,6 @@ static const char *msc_ip = NULL;
static struct bsc_nat *nat;
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)
@@ -90,6 +89,14 @@ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
return -1;
}
static void queue_for_msc(struct bsc_msc_connection *con, struct msgb *msg)
{
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_reset_ack(struct bsc_connection *bsc)
{
static const u_int8_t gsm_reset_ack[] = {
@@ -101,6 +108,55 @@ static void send_reset_ack(struct bsc_connection *bsc)
bsc_send_data(bsc, gsm_reset_ack, sizeof(gsm_reset_ack), IPAC_PROTO_SCCP);
}
static void send_ping(struct bsc_connection *bsc)
{
static const u_int8_t id_ping[] = {
IPAC_MSGT_PING,
};
bsc_send_data(bsc, id_ping, sizeof(id_ping), IPAC_PROTO_IPACCESS);
}
static void send_pong(struct bsc_connection *bsc)
{
static const u_int8_t id_pong[] = {
IPAC_MSGT_PONG,
};
bsc_send_data(bsc, id_pong, sizeof(id_pong), IPAC_PROTO_IPACCESS);
}
static void bsc_pong_timeout(void *_bsc)
{
struct bsc_connection *bsc = _bsc;
LOGP(DNAT, LOGL_ERROR, "BSC Nr: %d PONG timeout.\n", bsc->cfg->nr);
bsc_close_connection(bsc);
}
static void bsc_ping_timeout(void *_bsc)
{
struct bsc_connection *bsc = _bsc;
send_ping(bsc);
/* send another ping in 20 seconds */
bsc_schedule_timer(&bsc->ping_timeout, 20, 0);
/* also start a pong timer */
bsc_schedule_timer(&bsc->pong_timeout, 5, 0);
}
static void start_ping_pong(struct bsc_connection *bsc)
{
bsc->pong_timeout.data = bsc;
bsc->pong_timeout.cb = bsc_pong_timeout;
bsc->ping_timeout.data = bsc;
bsc->ping_timeout.cb = bsc_ping_timeout;
bsc_ping_timeout(bsc);
}
static void send_id_ack(struct bsc_connection *bsc)
{
static const u_int8_t id_ack[] = {
@@ -147,10 +203,7 @@ static void nat_send_rlsd(struct sccp_connections *conn)
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);
}
queue_for_msc(msc_con, msg);
}
static void nat_send_rlc(struct sccp_source_reference *src,
@@ -173,10 +226,7 @@ static void nat_send_rlc(struct sccp_source_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);
}
queue_for_msc(msc_con, msg);
}
static void send_mgcp_reset(struct bsc_connection *bsc)
@@ -311,7 +361,9 @@ send_to_all:
if (parsed->ipa_proto == IPAC_PROTO_SCCP && parsed->gsm_type == BSS_MAP_MSG_PAGING) {
int lac;
bsc = bsc_nat_find_bsc(nat, msg, &lac);
if (bsc)
if (bsc && bsc->cfg->forbid_paging)
LOGP(DNAT, LOGL_DEBUG, "Paging forbidden for BTS: %d\n", bsc->cfg->nr);
else if (bsc)
bsc_send_data(bsc, msg->l2h, msgb_l2len(msg), parsed->ipa_proto);
else
LOGP(DNAT, LOGL_ERROR, "Could not determine BSC for paging on lac: %d/0x%x\n",
@@ -340,7 +392,7 @@ static void msc_connection_was_lost(struct bsc_msc_connection *con)
LOGP(DMSC, LOGL_ERROR, "Closing all connections downstream.\n");
llist_for_each_entry_safe(bsc, tmp, &nat->bsc_connections, list_entry)
remove_bsc_connection(bsc);
bsc_close_connection(bsc);
nat->first_contact = 0;
bsc_mgcp_free_endpoints(nat);
@@ -367,10 +419,7 @@ static void msc_send_reset(struct bsc_msc_connection *msc_con)
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);
}
queue_for_msc(msc_con, msg);
LOGP(DMSC, LOGL_NOTICE, "Scheduled GSM0808 reset msg for the MSC.\n");
}
@@ -382,13 +431,12 @@ static int ipaccess_msc_read_cb(struct bsc_fd *bfd)
struct ipaccess_head *hh;
if (!msg) {
if (error == 0) {
if (error == 0)
LOGP(DNAT, LOGL_FATAL, "The connection the MSC was lost, exiting\n");
bsc_msc_lost(msc_con);
return -1;
}
else
LOGP(DNAT, LOGL_ERROR, "Failed to parse ip access message: %d\n", error);
LOGP(DNAT, LOGL_ERROR, "Failed to parse ip access message: %d\n", error);
bsc_msc_lost(msc_con);
return -1;
}
@@ -432,29 +480,33 @@ static int ipaccess_msc_write_cb(struct bsc_fd *bfd, struct msgb *msg)
* remove it from the patching of SCCP header lists
* as well. Maybe in the future even close connection..
*/
static void remove_bsc_connection(struct bsc_connection *connection)
void bsc_close_connection(struct bsc_connection *connection)
{
struct sccp_connections *sccp_patch, *tmp;
bsc_unregister_fd(&connection->write_queue.bfd);
close(connection->write_queue.bfd.fd);
write_queue_clear(&connection->write_queue);
llist_del(&connection->list_entry);
/* stop the timeout timer */
bsc_del_timer(&connection->id_timeout);
bsc_del_timer(&connection->ping_timeout);
bsc_del_timer(&connection->pong_timeout);
/* remove all SCCP connections */
llist_for_each_entry_safe(sccp_patch, tmp, &nat->sccp_connections, list_entry) {
if (sccp_patch->bsc != connection)
continue;
nat_send_rlsd(sccp_patch);
if (sccp_patch->has_remote_ref)
nat_send_rlsd(sccp_patch);
sccp_connection_destroy(sccp_patch);
}
/* close endpoints allocated by this BSC */
bsc_mgcp_clear_endpoints_for(connection);
bsc_unregister_fd(&connection->write_queue.bfd);
close(connection->write_queue.bfd.fd);
write_queue_clear(&connection->write_queue);
llist_del(&connection->list_entry);
talloc_free(connection);
}
@@ -468,7 +520,7 @@ static void ipaccess_close_bsc(void *data)
getpeername(conn->write_queue.bfd.fd, (struct sockaddr *) &sock, &len);
LOGP(DNAT, LOGL_ERROR, "BSC on %s didn't respond to identity request. Closing.\n",
inet_ntoa(sock.sin_addr));
remove_bsc_connection(conn);
bsc_close_connection(conn);
}
static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc)
@@ -476,6 +528,12 @@ static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc
struct bsc_config *conf;
const char* token = (const char *) TLVP_VAL(tvp, IPAC_IDTAG_UNITNAME);
if (bsc->cfg) {
LOGP(DNAT, LOGL_ERROR, "Reauth on fd %d bsc nr %d\n",
bsc->write_queue.bfd.fd, bsc->cfg->nr);
return;
}
llist_for_each_entry(conf, &bsc->nat->bsc_configs, entry) {
if (strcmp(conf->token, token) == 0) {
counter_inc(conf->stats.net.reconn);
@@ -483,6 +541,7 @@ static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc
bsc->cfg = conf;
bsc_del_timer(&bsc->id_timeout);
LOGP(DNAT, LOGL_NOTICE, "Authenticated bsc nr: %d lac: %d\n", conf->nr, conf->lac);
start_ping_pong(bsc);
return;
}
}
@@ -524,17 +583,17 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
case SCCP_MSG_TYPE_CR:
if (create_sccp_src_ref(bsc, msg, parsed) != 0)
goto exit2;
con = patch_sccp_src_ref_to_msc(msg, parsed, nat);
con = patch_sccp_src_ref_to_msc(msg, parsed, bsc);
break;
case SCCP_MSG_TYPE_RLSD:
case SCCP_MSG_TYPE_CREF:
case SCCP_MSG_TYPE_DT1:
case SCCP_MSG_TYPE_CC:
case SCCP_MSG_TYPE_IT:
con = patch_sccp_src_ref_to_msc(msg, parsed, nat);
con = patch_sccp_src_ref_to_msc(msg, parsed, bsc);
break;
case SCCP_MSG_TYPE_RLC:
con = patch_sccp_src_ref_to_msc(msg, parsed, nat);
con = patch_sccp_src_ref_to_msc(msg, parsed, bsc);
remove_sccp_src_ref(bsc, msg, parsed);
break;
case SCCP_MSG_TYPE_UDT:
@@ -556,15 +615,13 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
}
if (con && con->bsc != bsc) {
LOGP(DNAT, LOGL_ERROR, "Found the wrong entry.\n");
LOGP(DNAT, LOGL_ERROR, "The connection belongs to a different BTS: input: %d con: %d\n",
bsc->cfg->nr, con->bsc->cfg->nr);
goto exit2;
}
/* send the non-filtered but maybe modified msg */
if (write_queue_enqueue(&msc_con->write_queue, msg) != 0) {
LOGP(DNAT, LOGL_ERROR, "Can not queue message for the MSC.\n");
msgb_free(msg);
}
queue_for_msc(msc_con, msg);
talloc_free(parsed);
return 0;
@@ -598,14 +655,19 @@ static int ipaccess_bsc_read_cb(struct bsc_fd *bfd)
int error;
struct bsc_connection *bsc = bfd->data;
struct msgb *msg = ipaccess_read_msg(bfd, &error);
struct ipaccess_head *hh;
if (!msg) {
if (error == 0) {
LOGP(DNAT, LOGL_ERROR, "The connection to the BSC was lost. Cleaning it\n");
remove_bsc_connection(bsc);
} else {
LOGP(DNAT, LOGL_ERROR, "Failed to parse ip access message: %d\n", error);
}
if (error == 0)
LOGP(DNAT, LOGL_ERROR,
"The connection to the BSC Nr: %d was lost. Cleaning it\n",
bsc->cfg ? bsc->cfg->nr : -1);
else
LOGP(DNAT, LOGL_ERROR,
"Stream error on BSC Nr: %d. Failed to parse ip access message: %d\n",
bsc->cfg ? bsc->cfg->nr : -1, error);
bsc_close_connection(bsc);
return -1;
}
@@ -613,6 +675,21 @@ static int ipaccess_bsc_read_cb(struct bsc_fd *bfd)
LOGP(DNAT, LOGL_DEBUG, "MSG from BSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
/* Handle messages from the BSC */
hh = (struct ipaccess_head *) msg->data;
/* stop the pong timeout */
if (hh->proto == IPAC_PROTO_IPACCESS) {
if (msg->l2h[0] == IPAC_MSGT_PONG) {
bsc_del_timer(&bsc->pong_timeout);
msgb_free(msg);
return 0;
} else if (msg->l2h[0] == IPAC_MSGT_PING) {
send_pong(bsc);
msgb_free(msg);
return 0;
}
}
/* FIXME: Currently no PONG is sent to the BSC */
/* FIXME: Currently no ID ACK is sent to the BSC */
forward_sccp_to_msc(bsc, msg);
@@ -672,7 +749,6 @@ static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what)
return -1;
}
write_queue_init(&bsc->write_queue, 100);
bsc->write_queue.bfd.data = bsc;
bsc->write_queue.bfd.fd = ret;
bsc->write_queue.read_cb = ipaccess_bsc_read_cb;
@@ -817,9 +893,20 @@ static void signal_handler(int signal)
}
}
extern void *tall_msgb_ctx;
extern void *tall_ctr_ctx;
static void talloc_init_ctx()
{
tall_bsc_ctx = talloc_named_const(NULL, 0, "nat");
tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb");
tall_ctr_ctx = talloc_named_const(tall_bsc_ctx, 0, "counter");
}
int main(int argc, char** argv)
{
talloc_init_ctx();
log_init(&log_info);
stderr_target = log_target_create_stderr();
log_add_target(stderr_target);
log_set_all_filter(stderr_target, 1);
@@ -858,7 +945,7 @@ int main(int argc, char** argv)
/*
* Setup the MGCP code..
*/
if (bsc_mgcp_init(nat) != 0)
if (bsc_mgcp_nat_init(nat) != 0)
return -4;
/* connect to the MSC */

View File

@@ -70,6 +70,7 @@ struct bsc_connection *bsc_connection_alloc(struct bsc_nat *nat)
return NULL;
con->nat = nat;
write_queue_init(&con->write_queue, 100);
return con;
}
@@ -99,7 +100,7 @@ void sccp_connection_destroy(struct sccp_connections *conn)
LOGP(DNAT, LOGL_DEBUG, "Destroy 0x%x <-> 0x%x mapping for con %p\n",
sccp_src_ref_to_int(&conn->real_ref),
sccp_src_ref_to_int(&conn->patched_ref), conn->bsc);
bsc_mgcp_clear(conn);
bsc_mgcp_dlcx(conn);
llist_del(&conn->list_entry);
talloc_free(conn);
}
@@ -127,7 +128,11 @@ struct bsc_connection *bsc_nat_find_bsc(struct bsc_nat *nat, struct msgb *msg, i
data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST);
data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST);
if (data[0] != CELL_IDENT_LAC) {
/* No need to try a different BSS */
if (data[0] == CELL_IDENT_BSS) {
return NULL;
} else if (data[0] != CELL_IDENT_LAC) {
LOGP(DNAT, LOGL_ERROR, "Unhandled cell ident discrminator: %d\n", data[0]);
return NULL;
}

View File

@@ -69,6 +69,7 @@ static void config_write_bsc_single(struct vty *vty, struct bsc_config *bsc)
vty_out(vty, " imsi allow %s%s", bsc->imsi_allow, VTY_NEWLINE);
if (bsc->imsi_deny)
vty_out(vty, " imsi deny %s%s", bsc->imsi_deny, VTY_NEWLINE);
vty_out(vty, " paging forbidden %d%s", bsc->forbid_paging, VTY_NEWLINE);
}
static int config_write_bsc(struct vty *vty)
@@ -85,12 +86,16 @@ DEFUN(show_sccp, show_sccp_cmd, "show sccp connections",
SHOW_STR "Display information about current SCCP connections")
{
struct sccp_connections *con;
vty_out(vty, "Listing all opening SCCP connections%s", VTY_NEWLINE);
llist_for_each_entry(con, &_nat->sccp_connections, list_entry) {
vty_out(vty, "SCCP for BSC: Nr: %d lac: %d BSC ref: 0x%x Local ref: 0x%x MSC/BSC mux: 0x%x/0x%x%s",
vty_out(vty, "For BSC Nr: %d lac: %d; BSC ref: 0x%x; MUX ref: 0x%x; Network has ref: %d ref: 0x%x MSC/BSC mux: 0x%x/0x%x%s",
con->bsc->cfg ? con->bsc->cfg->nr : -1,
con->bsc->cfg ? con->bsc->cfg->lac : -1,
sccp_src_ref_to_int(&con->real_ref),
sccp_src_ref_to_int(&con->patched_ref),
con->has_remote_ref,
sccp_src_ref_to_int(&con->remote_ref),
con->msc_timeslot, con->bsc_timeslot,
VTY_NEWLINE);
}
@@ -107,7 +112,7 @@ DEFUN(show_bsc, show_bsc_cmd, "show bsc connections",
llist_for_each_entry(con, &_nat->bsc_connections, list_entry) {
getpeername(con->write_queue.bfd.fd, (struct sockaddr *) &sock, &len);
vty_out(vty, "BSC lac: %d, %d auth: %d fd: %d peername: %s%s",
vty_out(vty, "BSC nr: %d lac: %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,
@@ -117,8 +122,8 @@ DEFUN(show_bsc, show_bsc_cmd, "show bsc connections",
return CMD_SUCCESS;
}
DEFUN(show_bsc_cfg, show_bsc_cfg_cmd, "bsc config show",
"Display information about known BSC configs")
DEFUN(show_bsc_cfg, show_bsc_cfg_cmd, "show bsc config",
SHOW_STR "Display information about known BSC configs")
{
struct bsc_config *conf;
llist_for_each_entry(conf, &_nat->bsc_configs, entry) {
@@ -128,6 +133,8 @@ DEFUN(show_bsc_cfg, show_bsc_cfg_cmd, "bsc config show",
conf->imsi_allow ? conf->imsi_allow: "any",
conf->imsi_deny ? conf->imsi_deny : "none",
VTY_NEWLINE);
vty_out(vty, " paging forbidden: %d%s",
conf->forbid_paging, VTY_NEWLINE);
}
return CMD_SUCCESS;
@@ -135,11 +142,16 @@ DEFUN(show_bsc_cfg, show_bsc_cfg_cmd, "bsc config show",
DEFUN(show_stats,
show_stats_cmd,
"show statistics",
SHOW_STR "Display network statistics\n")
"show statistics [NR]",
SHOW_STR "Display network statistics")
{
struct bsc_config *conf;
int nr = -1;
if (argc == 1)
nr = atoi(argv[0]);
vty_out(vty, "NAT statistics%s", VTY_NEWLINE);
vty_out(vty, " SCCP Connections %lu total, %lu calls%s",
counter_get(_nat->stats.sccp.conn),
@@ -151,6 +163,9 @@ DEFUN(show_stats,
counter_get(_nat->stats.bsc.auth_fail), VTY_NEWLINE);
llist_for_each_entry(conf, &_nat->bsc_configs, entry) {
if (argc == 1 && nr != conf->nr)
continue;
vty_out(vty, " BSC lac: %d nr: %d%s",
conf->lac, conf->nr, VTY_NEWLINE);
vty_out(vty, " SCCP Connnections %lu total, %lu calls%s",
@@ -163,6 +178,24 @@ DEFUN(show_stats,
return CMD_SUCCESS;
}
DEFUN(close_bsc,
close_bsc_cmd,
"close bsc connection BSC_NR",
"Close the connection with the BSC identified by the config number.")
{
struct bsc_connection *bsc;
int bsc_nr = atoi(argv[0]);
llist_for_each_entry(bsc, &_nat->bsc_connections, list_entry) {
if (!bsc->cfg || bsc->cfg->nr != bsc_nr)
continue;
bsc_close_connection(bsc);
break;
}
return CMD_SUCCESS;
}
DEFUN(cfg_nat, cfg_nat_cmd, "nat", "Configute the NAT")
{
vty->index = _nat;
@@ -224,7 +257,7 @@ DEFUN(cfg_nat_msc_port,
}
/* per BSC configuration */
DEFUN(cfg_bsc, cfg_bsc_cmd, "bsc BSC_NR", "Select a BSC to configure\n")
DEFUN(cfg_bsc, cfg_bsc_cmd, "bsc BSC_NR", "Select a BSC to configure")
{
int bsc_nr = atoi(argv[0]);
struct bsc_config *bsc;
@@ -259,7 +292,7 @@ DEFUN(cfg_bsc_token, cfg_bsc_token_cmd, "token TOKEN", "Set the token")
}
DEFUN(cfg_bsc_lac, cfg_bsc_lac_cmd, "location_area_code <0-65535>",
"Set the Location Area Code (LAC) of this BSC\n")
"Set the Location Area Code (LAC) of this BSC")
{
struct bsc_config *tmp;
struct bsc_config *conf = vty->index;
@@ -315,6 +348,21 @@ DEFUN(cfg_bsc_imsi_deny,
return CMD_SUCCESS;
}
DEFUN(cfg_bsc_paging,
cfg_bsc_paging_cmd,
"paging forbidden (0|1)",
"Forbid sending PAGING REQUESTS to the BSC.")
{
struct bsc_config *conf = vty->index;
if (strcmp("1", argv[0]) == 0)
conf->forbid_paging = 1;
else
conf->forbid_paging = 0;
return CMD_SUCCESS;
}
int bsc_nat_vty_init(struct bsc_nat *nat)
{
_nat = nat;
@@ -327,6 +375,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
install_element(VIEW_NODE, &show_bsc_cmd);
install_element(VIEW_NODE, &show_bsc_cfg_cmd);
install_element(VIEW_NODE, &show_stats_cmd);
install_element(VIEW_NODE, &close_bsc_cmd);
openbsc_vty_add_cmds();
@@ -347,6 +396,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
install_element(BSC_NODE, &cfg_bsc_lac_cmd);
install_element(BSC_NODE, &cfg_bsc_imsi_allow_cmd);
install_element(BSC_NODE, &cfg_bsc_imsi_deny_cmd);
install_element(BSC_NODE, &cfg_bsc_paging_cmd);
mgcp_vty_init();

View File

@@ -85,6 +85,28 @@ int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc
{
struct sccp_connections *conn;
/* Some commercial BSCs like to reassign there SRC ref */
llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) {
if (conn->bsc != bsc)
continue;
if (memcmp(&conn->real_ref, parsed->src_local_ref, sizeof(conn->real_ref)) != 0)
continue;
/* the BSC has reassigned the SRC ref and we failed to keep track */
memset(&conn->remote_ref, 0, sizeof(conn->remote_ref));
if (assign_src_local_reference(&conn->patched_ref, bsc->nat) != 0) {
LOGP(DNAT, LOGL_ERROR, "BSC %d reused src ref: %d and we failed to generate a new id.\n",
bsc->cfg->nr, sccp_src_ref_to_int(parsed->src_local_ref));
llist_del(&conn->list_entry);
talloc_free(conn);
return -1;
} else {
bsc_mgcp_dlcx(conn);
return 0;
}
}
conn = talloc_zero(bsc->nat, struct sccp_connections);
if (!conn) {
LOGP(DNAT, LOGL_ERROR, "Memory allocation failure.\n");
@@ -99,7 +121,7 @@ int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc
return -1;
}
bsc_mgcp_clear(conn);
bsc_mgcp_init(conn);
llist_add_tail(&conn->list_entry, &bsc->nat->sccp_connections);
counter_inc(bsc->cfg->stats.sccp.conn);
counter_inc(bsc->cfg->nat->stats.sccp.conn);
@@ -119,6 +141,7 @@ int update_sccp_src_ref(struct sccp_connections *sccp, struct bsc_nat_parsed *pa
}
sccp->remote_ref = *parsed->src_local_ref;
sccp->has_remote_ref = 1;
LOGP(DNAT, LOGL_DEBUG, "Updating 0x%x to remote 0x%x on %p\n",
sccp_src_ref_to_int(&sccp->patched_ref),
sccp_src_ref_to_int(&sccp->remote_ref), sccp->bsc);
@@ -182,11 +205,14 @@ struct sccp_connections *patch_sccp_src_ref_to_bsc(struct msgb *msg,
*/
struct sccp_connections *patch_sccp_src_ref_to_msc(struct msgb *msg,
struct bsc_nat_parsed *parsed,
struct bsc_nat *nat)
struct bsc_connection *bsc)
{
struct sccp_connections *conn;
llist_for_each_entry(conn, &nat->sccp_connections, list_entry) {
llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) {
if (conn->bsc != bsc)
continue;
if (parsed->src_local_ref) {
if (equal(parsed->src_local_ref, &conn->real_ref)) {
*parsed->src_local_ref = conn->patched_ref;

View File

@@ -118,6 +118,52 @@ static void paging_give_credit(void *data)
paging_handle_pending_requests(paging_bts);
}
static int can_send_pag_req(struct gsm_bts *bts, int rsl_type)
{
struct pchan_load pl;
int count;
memset(&pl, 0, sizeof(pl));
bts_chan_load(&pl, bts);
switch (rsl_type) {
case RSL_CHANNEED_TCH_F:
case RSL_CHANNEED_TCH_ForH:
goto count_tch;
break;
case RSL_CHANNEED_SDCCH:
goto count_sdcch;
break;
case RSL_CHANNEED_ANY:
default:
if (bts->network->pag_any_tch)
goto count_tch;
else
goto count_sdcch;
break;
}
return 0;
/* could available SDCCH */
count_sdcch:
count = 0;
count += pl.pchan[GSM_PCHAN_SDCCH8_SACCH8C].total
- pl.pchan[GSM_PCHAN_SDCCH8_SACCH8C].used;
count += pl.pchan[GSM_PCHAN_CCCH_SDCCH4].total
- pl.pchan[GSM_PCHAN_CCCH_SDCCH4].used;
return bts->paging.free_chans_need > count;
count_tch:
count = 0;
count += pl.pchan[GSM_PCHAN_TCH_F].total
- pl.pchan[GSM_PCHAN_TCH_F].used;
if (bts->network->neci)
count += pl.pchan[GSM_PCHAN_TCH_H].total
- pl.pchan[GSM_PCHAN_TCH_H].used;
return bts->paging.free_chans_need > count;
}
/*
* This is kicked by the periodic PAGING LOAD Indicator
* coming from abis_rsl.c
@@ -154,6 +200,12 @@ static void paging_handle_pending_requests(struct gsm_bts_paging_state *paging_b
request = llist_entry(paging_bts->pending_requests.next,
struct gsm_paging_request, entry);
/* we need to determine the number of free channels */
if (paging_bts->free_chans_need != -1) {
if (can_send_pag_req(request->bts, request->chan_type) != 0)
goto skip_paging;
}
/* handle the paging request now */
page_ms(request);
paging_bts->available_slots--;
@@ -162,6 +214,7 @@ static void paging_handle_pending_requests(struct gsm_bts_paging_state *paging_b
llist_del(&request->entry);
llist_add_tail(&request->entry, &paging_bts->pending_requests);
skip_paging:
bsc_schedule_timer(&paging_bts->work_timer, PAGING_TIMER);
}

View File

@@ -81,7 +81,7 @@ static struct sccp_data_callback *_find_ssn(u_int8_t ssn)
/* need to add one */
cb = talloc_zero(tall_sccp_ctx, struct sccp_data_callback);
if (!cb) {
DEBUGP(DSCCP, "Failed to allocate sccp callback.\n");
LOGP(DSCCP, LOGL_ERROR, "Failed to allocate sccp callback.\n");
return NULL;
}
@@ -108,13 +108,13 @@ static int copy_address(struct sccp_address *addr, u_int8_t offset, struct msgb
u_int8_t length;
if (room <= 0) {
DEBUGP(DSCCP, "Not enough room for an address: %u\n", room);
LOGP(DSCCP, LOGL_ERROR, "Not enough room for an address: %u\n", room);
return -1;
}
length = msgb->l2h[offset];
if (room <= length) {
DEBUGP(DSCCP, "Not enough room for optional data %u %u\n", room, length);
LOGP(DSCCP, LOGL_ERROR, "Not enough room for optional data %u %u\n", room, length);
return -1;
}
@@ -122,7 +122,7 @@ static int copy_address(struct sccp_address *addr, u_int8_t offset, struct msgb
party = (struct sccp_called_party_address *)(msgb->l2h + offset + 1);
if (party->point_code_indicator) {
if (length <= read + 2) {
DEBUGP(DSCCP, "POI does not fit %u\n", length);
LOGP(DSCCP, LOGL_ERROR, "POI does not fit %u\n", length);
return -1;
}
@@ -133,7 +133,7 @@ static int copy_address(struct sccp_address *addr, u_int8_t offset, struct msgb
if (party->ssn_indicator) {
if (length <= read + 1) {
DEBUGP(DSCCP, "SSN does not fit %u\n", length);
LOGP(DSCCP, LOGL_ERROR, "SSN does not fit %u\n", length);
return -1;
}
@@ -142,7 +142,7 @@ static int copy_address(struct sccp_address *addr, u_int8_t offset, struct msgb
}
if (party->global_title_indicator) {
DEBUGP(DSCCP, "GTI not supported %u\n", *(u_int8_t *)party);
LOGP(DSCCP, LOGL_ERROR, "GTI not supported %u\n", *(u_int8_t *)party);
return -1;
}
@@ -156,7 +156,8 @@ static int check_address(struct sccp_address *addr)
if (addr->address.ssn_indicator != 1
|| addr->address.global_title_indicator == 1
|| addr->address.routing_indicator != 1) {
DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
LOGP(DSCCP, LOGL_ERROR,
"Invalid called address according to 08.06: 0x%x 0x%x\n",
*(u_int8_t *)&addr->address, addr->ssn);
return -1;
}
@@ -176,7 +177,7 @@ static int _sccp_parse_optional_data(const int offset,
return 0;
if (read + 1 >= room) {
DEBUGP(DSCCP, "no place for length\n");
LOGP(DSCCP, LOGL_ERROR, "no place for length\n");
return 0;
}
@@ -185,7 +186,8 @@ static int _sccp_parse_optional_data(const int offset,
if (room <= read) {
DEBUGP(DSCCP, "no space for the data: type: %d read: %d room: %d l2: %d\n",
LOGP(DSCCP, LOGL_ERROR,
"no space for the data: type: %d read: %d room: %d l2: %d\n",
type, read, room, msgb_l2len(msgb));
return 0;
}
@@ -214,7 +216,7 @@ int _sccp_parse_connection_request(struct msgb *msgb, struct sccp_parse_result *
/* header check */
if (msgb_l2len(msgb) < header_size) {
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n",
msgb_l2len(msgb), header_size);
return -1;
}
@@ -224,7 +226,7 @@ int _sccp_parse_connection_request(struct msgb *msgb, struct sccp_parse_result *
return -1;
if (check_address(&result->called) != 0) {
DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
LOGP(DSCCP, LOGL_ERROR, "Invalid called address according to 08.06: 0x%x 0x%x\n",
*(u_int8_t *)&result->called.address, result->called.ssn);
return -1;
}
@@ -236,7 +238,7 @@ int _sccp_parse_connection_request(struct msgb *msgb, struct sccp_parse_result *
*/
memset(&optional_data, 0, sizeof(optional_data));
if (_sccp_parse_optional_data(optional_offset + req->optional_start, msgb, &optional_data) != 0) {
DEBUGP(DSCCP, "parsing of optional data failed.\n");
LOGP(DSCCP, LOGL_ERROR, "parsing of optional data failed.\n");
return -1;
}
@@ -260,14 +262,14 @@ int _sccp_parse_connection_released(struct msgb *msgb, struct sccp_parse_result
/* we don't have enough size for the struct */
if (msgb_l2len(msgb) < header_size) {
DEBUGP(DSCCP, "msgb > header_size %u %u\n",
LOGP(DSCCP, LOGL_ERROR, "msgb > header_size %u %u\n",
msgb_l2len(msgb), header_size);
return -1;
}
memset(&optional_data, 0, sizeof(optional_data));
if (_sccp_parse_optional_data(optional_offset + rls->optional_start, msgb, &optional_data) != 0) {
DEBUGP(DSCCP, "parsing of optional data failed.\n");
LOGP(DSCCP, LOGL_ERROR, "parsing of optional data failed.\n");
return -1;
}
@@ -295,7 +297,7 @@ int _sccp_parse_connection_refused(struct msgb *msgb, struct sccp_parse_result *
/* header check */
if (msgb_l2len(msgb) < header_size) {
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n",
msgb_l2len(msgb), header_size);
return -1;
}
@@ -306,7 +308,7 @@ int _sccp_parse_connection_refused(struct msgb *msgb, struct sccp_parse_result *
memset(&optional_data, 0, sizeof(optional_data));
if (_sccp_parse_optional_data(optional_offset + ref->optional_start, msgb, &optional_data) != 0) {
DEBUGP(DSCCP, "parsing of optional data failed.\n");
LOGP(DSCCP, LOGL_ERROR, "parsing of optional data failed.\n");
return -1;
}
@@ -333,7 +335,7 @@ int _sccp_parse_connection_confirm(struct msgb *msgb, struct sccp_parse_result *
/* header check */
if (msgb_l2len(msgb) < header_size) {
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n",
msgb_l2len(msgb), header_size);
return -1;
}
@@ -344,7 +346,7 @@ int _sccp_parse_connection_confirm(struct msgb *msgb, struct sccp_parse_result *
memset(&optional_data, 0, sizeof(optional_data));
if (_sccp_parse_optional_data(optional_offset + con->optional_start, msgb, &optional_data) != 0) {
DEBUGP(DSCCP, "parsing of optional data failed.\n");
LOGP(DSCCP, LOGL_ERROR, "parsing of optional data failed.\n");
return -1;
}
@@ -366,7 +368,7 @@ int _sccp_parse_connection_release_complete(struct msgb *msgb, struct sccp_parse
/* header check */
if (msgb_l2len(msgb) < header_size) {
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n",
msgb_l2len(msgb), header_size);
return -1;
}
@@ -387,13 +389,13 @@ int _sccp_parse_connection_dt1(struct msgb *msgb, struct sccp_parse_result *resu
/* we don't have enough size for the struct */
if (msgb_l2len(msgb) < header_size) {
DEBUGP(DSCCP, "msgb > header_size %u %u\n",
LOGP(DSCCP, LOGL_ERROR, "msgb > header_size %u %u\n",
msgb_l2len(msgb), header_size);
return -1;
}
if (dt1->segmenting != 0) {
DEBUGP(DSCCP, "This packet has segmenting, not supported: %d\n", dt1->segmenting);
LOGP(DSCCP, LOGL_ERROR, "This packet has segmenting, not supported: %d\n", dt1->segmenting);
return -1;
}
@@ -401,7 +403,7 @@ int _sccp_parse_connection_dt1(struct msgb *msgb, struct sccp_parse_result *resu
/* some more size checks in here */
if (msgb_l2len(msgb) < variable_offset + dt1->variable_start + 1) {
DEBUGP(DSCCP, "Not enough space for variable start: %u %u\n",
LOGP(DSCCP, LOGL_ERROR, "Not enough space for variable start: %u %u\n",
msgb_l2len(msgb), dt1->variable_start);
return -1;
}
@@ -410,7 +412,7 @@ int _sccp_parse_connection_dt1(struct msgb *msgb, struct sccp_parse_result *resu
msgb->l3h = &msgb->l2h[dt1->variable_start + variable_offset + 1];
if (msgb_l3len(msgb) < result->data_len) {
DEBUGP(DSCCP, "Not enough room for the payload: %u %u\n",
LOGP(DSCCP, LOGL_ERROR, "Not enough room for the payload: %u %u\n",
msgb_l3len(msgb), result->data_len);
return -1;
}
@@ -428,7 +430,7 @@ int _sccp_parse_udt(struct msgb *msgb, struct sccp_parse_result *result)
struct sccp_data_unitdata *udt = (struct sccp_data_unitdata *)msgb->l2h;
if (msgb_l2len(msgb) < header_size) {
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n",
msgb_l2len(msgb), header_size);
return -1;
}
@@ -438,7 +440,7 @@ int _sccp_parse_udt(struct msgb *msgb, struct sccp_parse_result *result)
return -1;
if (check_address(&result->called) != 0) {
DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
LOGP(DSCCP, LOGL_ERROR, "Invalid called address according to 08.06: 0x%x 0x%x\n",
*(u_int8_t *)&result->called.address, result->called.ssn);
return -1;
}
@@ -447,13 +449,13 @@ int _sccp_parse_udt(struct msgb *msgb, struct sccp_parse_result *result)
return -1;
if (check_address(&result->calling) != 0) {
DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
LOGP(DSCCP, LOGL_ERROR, "Invalid called address according to 08.06: 0x%x 0x%x\n",
*(u_int8_t *)&result->called.address, result->called.ssn);
}
/* we don't have enough size for the data */
if (msgb_l2len(msgb) < data_offset + udt->variable_data + 1) {
DEBUGP(DSCCP, "msgb < header + offset %u %u %u\n",
LOGP(DSCCP, LOGL_ERROR, "msgb < header + offset %u %u %u\n",
msgb_l2len(msgb), header_size, udt->variable_data);
return -1;
}
@@ -463,7 +465,7 @@ int _sccp_parse_udt(struct msgb *msgb, struct sccp_parse_result *result)
result->data_len = msgb_l3len(msgb);
if (msgb_l3len(msgb) != msgb->l3h[-1]) {
DEBUGP(DSCCP, "msgb is truncated is: %u should: %u\n",
LOGP(DSCCP, LOGL_ERROR, "msgb is truncated is: %u should: %u\n",
msgb_l3len(msgb), msgb->l3h[-1]);
return -1;
}
@@ -478,7 +480,7 @@ static int _sccp_parse_it(struct msgb *msgb, struct sccp_parse_result *result)
struct sccp_data_it *it;
if (msgb_l2len(msgb) < header_size) {
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n",
msgb_l2len(msgb), header_size);
return -1;
}
@@ -490,6 +492,23 @@ static int _sccp_parse_it(struct msgb *msgb, struct sccp_parse_result *result)
return 0;
}
static int _sccp_parse_err(struct msgb *msgb, struct sccp_parse_result *result)
{
static const u_int32_t header_size = sizeof(struct sccp_proto_err);
struct sccp_proto_err *err;
if (msgb_l2len(msgb) < header_size) {
LOGP(DSCCP, LOGL_ERROR, "msgb < header_size %u %u\n",
msgb_l2len(msgb), header_size);
return -1;
}
err = (struct sccp_proto_err *) msgb->l2h;
result->data_len = 0;
result->destination_local_reference = &err->destination_local_reference;
return 0;
}
/*
* Send UDT. Currently we have a fixed address...
@@ -501,7 +520,7 @@ static int _sccp_send_data(int class, const struct sockaddr_sccp *in,
u_int8_t *data;
if (msgb_l3len(payload) > 256) {
DEBUGP(DSCCP, "The payload is too big for one udt\n");
LOGP(DSCCP, LOGL_ERROR, "The payload is too big for one udt\n");
return -1;
}
@@ -546,7 +565,7 @@ static int _sccp_handle_read(struct msgb *msgb)
cb = _find_ssn(result.called.ssn);
if (!cb || !cb->read_cb) {
DEBUGP(DSCCP, "No routing for UDT for called SSN: %u\n", result.called.ssn);
LOGP(DSCCP, LOGL_ERROR, "No routing for UDT for called SSN: %u\n", result.called.ssn);
return -1;
}
@@ -595,7 +614,7 @@ static int assign_source_local_reference(struct sccp_connection *connection)
++last_ref;
/* do not use the reversed word and wrap around */
if ((last_ref & 0x00FFFFFF) == 0x00FFFFFF) {
DEBUGP(DSCCP, "Wrapped searching for a free code\n");
LOGP(DSCCP, LOGL_DEBUG, "Wrapped searching for a free code\n");
last_ref = 0;
++wrapped;
}
@@ -606,7 +625,7 @@ static int assign_source_local_reference(struct sccp_connection *connection)
}
} while (wrapped != 2);
DEBUGP(DSCCP, "Finding a free reference failed\n");
LOGP(DSCCP, LOGL_ERROR, "Finding a free reference failed\n");
return -1;
}
@@ -686,13 +705,13 @@ static int _sccp_send_connection_request(struct sccp_connection *connection,
if (msg && (msgb_l3len(msg) < 3 || msgb_l3len(msg) > 130)) {
DEBUGP(DSCCP, "Invalid amount of data... %d\n", msgb_l3len(msg));
LOGP(DSCCP, LOGL_ERROR, "Invalid amount of data... %d\n", msgb_l3len(msg));
return -1;
}
/* try to find a id */
if (assign_source_local_reference(connection) != 0) {
DEBUGP(DSCCP, "Assigning a local reference failed.\n");
LOGP(DSCCP, LOGL_ERROR, "Assigning a local reference failed.\n");
_sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_SETUP_ERROR);
return -1;
}
@@ -744,7 +763,7 @@ static int _sccp_send_connection_data(struct sccp_connection *conn, struct msgb
int extra_size;
if (msgb_l3len(_data) < 2 || msgb_l3len(_data) > 256) {
DEBUGP(DSCCP, "data size too big, segmenting unimplemented.\n");
LOGP(DSCCP, LOGL_ERROR, "data size too big, segmenting unimplemented.\n");
return -1;
}
@@ -840,14 +859,14 @@ static int _sccp_handle_connection_request(struct msgb *msgb)
cb = _find_ssn(result.called.ssn);
if (!cb || !cb->accept_cb) {
DEBUGP(DSCCP, "No routing for CR for called SSN: %u\n", result.called.ssn);
LOGP(DSCCP, LOGL_ERROR, "No routing for CR for called SSN: %u\n", result.called.ssn);
return -1;
}
/* check if the system wants this connection */
connection = talloc_zero(tall_sccp_ctx, struct sccp_connection);
if (!connection) {
DEBUGP(DSCCP, "Allocation failed\n");
LOGP(DSCCP, LOGL_ERROR, "Allocation failed\n");
return -1;
}
@@ -859,7 +878,7 @@ static int _sccp_handle_connection_request(struct msgb *msgb)
* one....
*/
if (destination_local_reference_is_free(result.source_local_reference) != 0) {
DEBUGP(DSCCP, "Need to reject connection with existing reference\n");
LOGP(DSCCP, LOGL_ERROR, "Need to reject connection with existing reference\n");
_sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_SCCP_FAILURE);
talloc_free(connection);
return -1;
@@ -879,7 +898,7 @@ static int _sccp_handle_connection_request(struct msgb *msgb)
llist_add_tail(&connection->list, &sccp_connections);
if (_sccp_send_connection_confirm(connection) != 0) {
DEBUGP(DSCCP, "Sending confirm failed... no available source reference?\n");
LOGP(DSCCP, LOGL_ERROR, "Sending confirm failed... no available source reference?\n");
_sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_SCCP_FAILURE);
_sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED);
@@ -922,7 +941,7 @@ static int _sccp_handle_connection_release_complete(struct msgb *msgb)
}
DEBUGP(DSCCP, "Release complete of unknown connection\n");
LOGP(DSCCP, LOGL_ERROR, "Release complete of unknown connection\n");
return -1;
found:
@@ -950,7 +969,7 @@ static int _sccp_handle_connection_dt1(struct msgb *msgb)
}
}
DEBUGP(DSCCP, "No connection found for dt1 data\n");
LOGP(DSCCP, LOGL_ERROR, "No connection found for dt1 data\n");
return -1;
found:
@@ -1009,7 +1028,7 @@ static int _sccp_handle_connection_released(struct msgb *msgb)
}
DEBUGP(DSCCP, "Unknown connection was released.\n");
LOGP(DSCCP, LOGL_ERROR, "Unknown connection was released.\n");
return -1;
/* we have found a connection */
@@ -1021,7 +1040,7 @@ found:
/* generate a response */
if (_sccp_send_connection_release_complete(conn) != 0) {
DEBUGP(DSCCP, "Sending release confirmed failed\n");
LOGP(DSCCP, LOGL_ERROR, "Sending release confirmed failed\n");
return -1;
}
@@ -1046,7 +1065,7 @@ static int _sccp_handle_connection_refused(struct msgb *msgb)
}
}
DEBUGP(DSCCP, "Refused but no connection found\n");
LOGP(DSCCP, LOGL_ERROR, "Refused but no connection found\n");
return -1;
found:
@@ -1079,7 +1098,7 @@ static int _sccp_handle_connection_confirm(struct msgb *msgb)
}
}
DEBUGP(DSCCP, "Confirmed but no connection found\n");
LOGP(DSCCP, LOGL_ERROR, "Confirmed but no connection found\n");
return -1;
found:
@@ -1108,7 +1127,7 @@ int sccp_system_init(void (*outgoing)(struct msgb *data, void *ctx), void *ctx)
int sccp_system_incoming(struct msgb *msgb)
{
if (msgb_l2len(msgb) < 1 ) {
DEBUGP(DSCCP, "Too short packet\n");
LOGP(DSCCP, LOGL_ERROR, "Too short packet\n");
return -1;
}
@@ -1137,7 +1156,7 @@ int sccp_system_incoming(struct msgb *msgb)
return _sccp_handle_read(msgb);
break;
default:
DEBUGP(DSCCP, "unimplemented msg type: %d\n", type);
LOGP(DSCCP, LOGL_ERROR, "unimplemented msg type: %d\n", type);
};
return -1;
@@ -1148,7 +1167,7 @@ int sccp_connection_write(struct sccp_connection *connection, struct msgb *data)
{
if (connection->connection_state < SCCP_CONNECTION_STATE_CONFIRM
|| connection->connection_state > SCCP_CONNECTION_STATE_ESTABLISHED) {
DEBUGP(DSCCP, "sccp_connection_write: Wrong connection state: %p %d\n",
LOGP(DSCCP, LOGL_ERROR, "sccp_connection_write: Wrong connection state: %p %d\n",
connection, connection->connection_state);
return -1;
}
@@ -1165,7 +1184,7 @@ int sccp_connection_send_it(struct sccp_connection *connection)
{
if (connection->connection_state < SCCP_CONNECTION_STATE_CONFIRM
|| connection->connection_state > SCCP_CONNECTION_STATE_ESTABLISHED) {
DEBUGP(DSCCP, "sccp_connection_write: Wrong connection state: %p %d\n",
LOGP(DSCCP, LOGL_ERROR, "sccp_connection_write: Wrong connection state: %p %d\n",
connection, connection->connection_state);
return -1;
}
@@ -1178,7 +1197,7 @@ int sccp_connection_close(struct sccp_connection *connection, int cause)
{
if (connection->connection_state < SCCP_CONNECTION_STATE_CONFIRM
|| connection->connection_state > SCCP_CONNECTION_STATE_ESTABLISHED) {
DEBUGPC(DSCCP, "Can not close the connection. It was never opened: %p %d\n",
LOGP(DSCCP, LOGL_ERROR, "Can not close the connection. It was never opened: %p %d\n",
connection, connection->connection_state);
return -1;
}
@@ -1190,7 +1209,7 @@ int sccp_connection_free(struct sccp_connection *connection)
{
if (connection->connection_state > SCCP_CONNECTION_STATE_NONE
&& connection->connection_state < SCCP_CONNECTION_STATE_RELEASE_COMPLETE) {
DEBUGP(DSCCP, "The connection needs to be released before it is freed");
LOGP(DSCCP, LOGL_ERROR, "The connection needs to be released before it is freed");
return -1;
}
@@ -1318,6 +1337,9 @@ int sccp_parse_header(struct msgb *msg, struct sccp_parse_result *result)
case SCCP_MSG_TYPE_IT:
return _sccp_parse_it(msg, result);
break;
case SCCP_MSG_TYPE_ERR:
return _sccp_parse_err(msg, result);
break;
};
LOGP(DSCCP, LOGL_ERROR, "Unimplemented MSG Type: 0x%x\n", type);

View File

@@ -65,11 +65,11 @@ struct buffer_data {
#define BUFFER_DATA_FREE(D) talloc_free((D))
/* Make new buffer. */
struct buffer *buffer_new(size_t size)
struct buffer *buffer_new(void *ctx, size_t size)
{
struct buffer *b;
b = talloc_zero(tall_vty_ctx, struct buffer);
b = talloc_zero(ctx, struct buffer);
if (size)
b->size = size;
@@ -138,7 +138,7 @@ static struct buffer_data *buffer_add(struct buffer *b)
{
struct buffer_data *d;
d = _talloc_zero(tall_vty_ctx,
d = _talloc_zero(b,
offsetof(struct buffer_data, data[b->size]),
"buffer_add");
if (!d)

View File

@@ -51,10 +51,10 @@ struct vty *vty_new()
if (!new)
goto out;
new->obuf = buffer_new(0); /* Use default buffer size. */
new->obuf = buffer_new(new, 0); /* Use default buffer size. */
if (!new->obuf)
goto out_new;
new->buf = _talloc_zero(tall_vty_ctx, VTY_BUFSIZ, "vty_new->buf");
new->buf = _talloc_zero(new, VTY_BUFSIZ, "vty_new->buf");
if (!new->buf)
goto out_obuf;
@@ -170,8 +170,7 @@ void vty_close(struct vty *vty)
/* Check configure. */
vty_config_unlock(vty);
/* FIXME: memory leak. We need to call telnet_close_client() but don't
* have bfd */
/* VTY_CLOSED is handled by the telnet_interface */
vty_event(VTY_CLOSED, vty->fd, vty);
/* OK free vty. */
@@ -211,7 +210,7 @@ int vty_out(struct vty *vty, const char *format, ...)
else
size = size * 2;
p = talloc_realloc_size(tall_vty_ctx, p, size);
p = talloc_realloc_size(vty, p, size);
if (!p)
return -1;
@@ -358,7 +357,7 @@ static void vty_ensure(struct vty *vty, int length)
{
if (vty->max <= length) {
vty->max *= 2;
vty->buf = talloc_realloc_size(tall_vty_ctx, vty->buf, vty->max);
vty->buf = talloc_realloc_size(vty, vty->buf, vty->max);
// FIXME: check return
}
}
@@ -459,7 +458,7 @@ static void vty_hist_add(struct vty *vty)
/* Insert history entry. */
if (vty->hist[vty->hindex])
talloc_free(vty->hist[vty->hindex]);
vty->hist[vty->hindex] = talloc_strdup(tall_vty_ctx, vty->buf);
vty->hist[vty->hindex] = talloc_strdup(vty, vty->buf);
/* History index rotation. */
vty->hindex++;
@@ -916,7 +915,7 @@ static void vty_complete_command(struct vty *vty)
vty_backward_pure_word(vty);
vty_insert_word_overwrite(vty, matched[0]);
vty_self_insert(vty, ' ');
//talloc_free(matched[0]);
talloc_free(matched[0]);
break;
case CMD_COMPLETE_MATCH:
vty_prompt(vty);
@@ -924,8 +923,6 @@ static void vty_complete_command(struct vty *vty)
vty_backward_pure_word(vty);
vty_insert_word_overwrite(vty, matched[0]);
talloc_free(matched[0]);
vector_only_index_free(matched);
return;
break;
case CMD_COMPLETE_LIST_MATCH:
for (i = 0; matched[i] != NULL; i++) {
@@ -966,7 +963,7 @@ vty_describe_fold(struct vty *vty, int cmd_width,
return;
}
buf = _talloc_zero(tall_vty_ctx, strlen(desc->str) + 1, "describe_fold");
buf = _talloc_zero(vty, strlen(desc->str) + 1, "describe_fold");
if (!buf)
return;

View File

@@ -350,6 +350,13 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
vty_out(vty, " rach max transmission %u%s",
rach_max_trans_raw2val(bts->si_common.rach_control.max_trans),
VTY_NEWLINE);
if (bts->rach_b_thresh != -1)
vty_out(vty, " rach nm busy threshold %u%s",
bts->rach_b_thresh, VTY_NEWLINE);
if (bts->rach_ldavg_slots != -1)
vty_out(vty, " rach nm load average %u%s",
bts->rach_ldavg_slots, VTY_NEWLINE);
if (bts->si_common.rach_control.cell_bar)
vty_out(vty, " cell barred 1%s", VTY_NEWLINE);
if (is_ipaccess_bts(bts)) {
@@ -360,6 +367,11 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
config_write_e1_link(vty, &bts->oml_e1_link, " oml ");
vty_out(vty, " oml e1 tei %u%s", bts->oml_tei, VTY_NEWLINE);
}
/* if we have a limit, write it */
if (bts->paging.free_chans_need >= 0)
vty_out(vty, " paging free %d%s", bts->paging.free_chans_need, VTY_NEWLINE);
vty_out(vty, " gprs mode %s%s", bts_gprs_mode_name(bts->gprs.mode),
VTY_NEWLINE);
if (bts->gprs.mode != BTS_GPRS_NONE) {
@@ -1599,6 +1611,26 @@ DEFUN(cfg_bts_rach_max_trans,
return CMD_SUCCESS;
}
DEFUN(cfg_bts_rach_nm_b_thresh,
cfg_bts_rach_nm_b_thresh_cmd,
"rach nm busy threshold <0-255>",
"Set the NM Busy Threshold in DB")
{
struct gsm_bts *bts = vty->index;
bts->rach_b_thresh = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_bts_rach_nm_ldavg,
cfg_bts_rach_nm_ldavg_cmd,
"rach nm load average <0-65535>",
"Set the NM Loadaver Slots value")
{
struct gsm_bts *bts = vty->index;
bts->rach_ldavg_slots = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_bts_cell_barred, cfg_bts_cell_barred_cmd,
"cell barred (0|1)",
"Should this cell be barred from access?")
@@ -1757,6 +1789,16 @@ DEFUN(cfg_bts_gprs_nsvc_rip, cfg_bts_gprs_nsvc_rip_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_bts_pag_free, cfg_bts_pag_free_cmd,
"paging free FREE_NR",
"Only page when having a certain amount of free slots. -1 to disable")
{
struct gsm_bts *bts = vty->index;
bts->paging.free_chans_need = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_bts_gprs_rac, cfg_bts_gprs_rac_cmd,
"gprs routing area <0-255>",
"GPRS Routing Area Code")
@@ -2045,6 +2087,8 @@ int bsc_vty_init(struct gsm_network *net)
install_element(BTS_NODE, &cfg_bts_challoc_cmd);
install_element(BTS_NODE, &cfg_bts_rach_tx_integer_cmd);
install_element(BTS_NODE, &cfg_bts_rach_max_trans_cmd);
install_element(BTS_NODE, &cfg_bts_rach_nm_b_thresh_cmd);
install_element(BTS_NODE, &cfg_bts_rach_nm_ldavg_cmd);
install_element(BTS_NODE, &cfg_bts_cell_barred_cmd);
install_element(BTS_NODE, &cfg_bts_ms_max_power_cmd);
install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd);
@@ -2058,6 +2102,7 @@ int bsc_vty_init(struct gsm_network *net)
install_element(BTS_NODE, &cfg_bts_gprs_nsvc_lport_cmd);
install_element(BTS_NODE, &cfg_bts_gprs_nsvc_rport_cmd);
install_element(BTS_NODE, &cfg_bts_gprs_nsvc_rip_cmd);
install_element(BTS_NODE, &cfg_bts_pag_free_cmd);
install_element(BTS_NODE, &cfg_trx_cmd);
install_node(&trx_node, dummy_config_write);

View File

@@ -58,7 +58,7 @@ static int dummy_config_write(struct vty *v)
static struct buffer *argv_to_buffer(int argc, const char *argv[], int base)
{
struct buffer *b = buffer_new(1024);
struct buffer *b = buffer_new(NULL, 1024);
int i;
if (!b)

View File

@@ -96,6 +96,12 @@ static const u_int8_t connnection_it[] = {
0x00, 0x00, 0x00, 0x00,
};
/* error in both directions */
static const u_int8_t proto_error[] = {
0x00, 0x05, 0xfd,
0x0f, 0x22, 0x33, 0x44, 0x00,
};
/* MGCP wrap... */
static const u_int8_t mgcp_msg[] = {
0x00, 0x03, 0xfc,
@@ -176,6 +182,19 @@ static const struct filter_result results[] = {
.dir = DIR_MSC,
.result = 0,
},
{
.data = proto_error,
.length = ARRAY_SIZE(proto_error),
.dir = DIR_BSC,
.result = 0,
},
{
.data = proto_error,
.length = ARRAY_SIZE(proto_error),
.dir = DIR_MSC,
.result = 0,
},
};
static void test_filter(void)
@@ -248,7 +267,7 @@ static void test_contrack()
/* 1.) create a connection */
copy_to_msg(msg, bsc_cr, sizeof(bsc_cr));
parsed = bsc_nat_parse(msg);
con_found = patch_sccp_src_ref_to_msc(msg, parsed, nat);
con_found = patch_sccp_src_ref_to_msc(msg, parsed, con);
if (con_found != NULL) {
fprintf(stderr, "Con should not exist %p\n", con_found);
abort();
@@ -258,7 +277,7 @@ static void test_contrack()
fprintf(stderr, "Failed to create a ref\n");
abort();
}
con_found = patch_sccp_src_ref_to_msc(msg, parsed, nat);
con_found = patch_sccp_src_ref_to_msc(msg, parsed, con);
if (!con_found || con_found->bsc != con) {
fprintf(stderr, "Failed to find the con: %p\n", con_found);
abort();
@@ -282,7 +301,7 @@ static void test_contrack()
/* 3.) send some data */
copy_to_msg(msg, bsc_dtap, sizeof(bsc_dtap));
parsed = bsc_nat_parse(msg);
con_found = patch_sccp_src_ref_to_msc(msg, parsed, nat);
con_found = patch_sccp_src_ref_to_msc(msg, parsed, con);
VERIFY(con_found, con, msg, bsc_dtap_patched, "BSC DTAP");
/* 4.) receive some data */
@@ -300,7 +319,7 @@ static void test_contrack()
/* 6.) confirm the connection close */
copy_to_msg(msg, bsc_rlc, sizeof(bsc_rlc));
parsed = bsc_nat_parse(msg);
con_found = patch_sccp_src_ref_to_msc(msg, parsed, nat);
con_found = patch_sccp_src_ref_to_msc(msg, parsed, con);
if (!con_found || con_found->bsc != con) {
fprintf(stderr, "Failed to find the con: %p\n", con_found);
abort();
@@ -314,7 +333,7 @@ static void test_contrack()
copy_to_msg(msg, bsc_rlc, sizeof(bsc_rlc));
parsed = bsc_nat_parse(msg);
con_found = patch_sccp_src_ref_to_msc(msg, parsed, nat);
con_found = patch_sccp_src_ref_to_msc(msg, parsed, con);
/* verify that it is gone */
if (con_found != NULL) {
@@ -376,6 +395,8 @@ static void test_paging(void)
static void test_mgcp_ass_tracking(void)
{
struct bsc_connection *bsc;
struct bsc_nat *nat;
struct sccp_connections con;
struct bsc_nat_parsed *parsed;
struct msgb *msg;
@@ -383,6 +404,14 @@ static void test_mgcp_ass_tracking(void)
fprintf(stderr, "Testing MGCP.\n");
memset(&con, 0, sizeof(con));
nat = bsc_nat_alloc();
nat->bsc_endpoints = talloc_zero_array(nat,
struct bsc_endpoint,
33);
bsc = bsc_connection_alloc(nat);
bsc->cfg = bsc_config_alloc(nat, "foo", 2323);
con.bsc = bsc;
msg = msgb_alloc(4096, "foo");
copy_to_msg(msg, ass_cmd, sizeof(ass_cmd));
parsed = bsc_nat_parse(msg);
@@ -402,11 +431,13 @@ static void test_mgcp_ass_tracking(void)
}
talloc_free(parsed);
bsc_mgcp_clear(&con);
bsc_mgcp_dlcx(&con);
if (con.bsc_timeslot != -1 || con.msc_timeslot != -1) {
fprintf(stderr, "Clearing should remove the mapping.\n");
abort();
}
talloc_free(nat);
}
/* test the code to find a given connection */

View File

@@ -264,6 +264,10 @@ static const u_int8_t it_test[] = {
0x10, 0x01, 0x07,
0x94, 0x01, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00 };
static const u_int8_t proto_err[] = {
0x0f, 0x0c, 0x04, 0x00, 0x00,
};
static const struct sccp_parse_header_result parse_result[] = {
{
.msg_type = SCCP_MSG_TYPE_IT,
@@ -287,6 +291,21 @@ static const struct sccp_parse_header_result parse_result[] = {
.input = it_test,
.input_len = sizeof(it_test),
},
{
.msg_type = SCCP_MSG_TYPE_ERR,
.wanted_len = 0,
.src_ssn = -1,
.dst_ssn = -1,
.has_src_ref = 0,
.has_dst_ref = 1,
.dst_ref = {
.octet1 = 0x0c,
.octet2 = 0x04,
.octet3 = 0x00,
},
.input = proto_err,
.input_len = sizeof(proto_err),
},
};
@@ -777,7 +796,7 @@ static void test_sccp_parsing(void)
memset(&result, 0, sizeof(result));
if (sccp_parse_header(msg, &result) != 0) {
fprintf(stderr, "Failed to parse test: %d\n", current_test);
fprintf(stderr, "Failed to sccp parse test: %d\n", current_test);
} else {
if (parse_result[current_test].wanted_len != result.data_len) {
fprintf(stderr, "Unexpected data length.\n");