Compare commits

...

95 Commits

Author SHA1 Message Date
Holger Hans Peter Freyther
0c8af75c94 Increase the version number. 2010-05-12 22:25:40 +08:00
Holger Hans Peter Freyther
e4b33be6fc chan: After sending the GSM04.08 RR Release, reset the subscriber and wait
After we send the SACH DEACTIVATE the BTS will get back to us with a
Release Indication which will trigger the RF Channel Release handling. This
is why we can return here, but we need to put the subscriber reference to
make sure to not end in a infinite loop.

This and the previous change fix the USSD issue for me.
2010-05-12 22:09:24 +08:00
Holger Hans Peter Freyther
cc7461cefc bsc_msc_ip: Assign a dummy gsm_subscriber to send a SACH DEACTIVATE
This is part of fixing USSD delivered to the MS. Currently only MT
services would end up with a GSM Subscriber assigned. The LCHAN code
is using the GSM Subscriber to figure out if a SACH DEACTIVATE should
be send to the MS. Add code to always assign a GSM Subscriber.
2010-05-12 22:09:16 +08:00
Holger Hans Peter Freyther
e174061d17 bssap: Use libosmocore for message creation. 2010-05-12 18:34:20 +08:00
Holger Hans Peter Freyther
6e1c3412ae bssap: Use libosmocore to create GSM0808 Reset 2010-05-12 18:33:15 +08:00
Holger Hans Peter Freyther
bff54b3e00 bssap: Start to libosmocore for gsm0808 message creation. 2010-05-12 18:31:13 +08:00
Holger Hans Peter Freyther
e75eb4ca25 ipaccess: Wait for the BASEBAND_TRANSCEIVER and then bootstrap OML
Currently we are connecting to the BTS and once the OML is established
we are bootstrapping the OML. This does not work for a multi TRX setup
as we will need to use a trx_nr != 0 for it.

Change the code to wait for a message (in this case NM OC_BASEBAND_TRANSC)
to detect the trx_nr used by the BTS and then use that TRX to bootstrap
the network.

I have tested setting the unit id on a single and multi trx system for
the first and second trx.
2010-05-12 17:16:18 +08:00
Holger Hans Peter Freyther
566737a4b8 abis: Pass the abis_om_obj_inst in the nm_state_event.. 2010-05-12 17:16:18 +08:00
Holger Hans Peter Freyther
2b7350240d nat: Have a recycle timer that removes unconfirmed SCCP connections.
The MSC does not respond to a SCCP CR with Paging Response as GSM
payload, when the response comes in 'too late'. Prevent the MUX having
stale connections and start removing old connections every 20 minutes.
2010-05-12 00:58:08 +08:00
Holger Hans Peter Freyther
d76b53c00e nat: When we fail to reallocate... also close down the MGCP part
Give the BSC a chanche to close down MGCP ports as well.
2010-05-12 00:35:07 +08:00
Holger Hans Peter Freyther
9c9ef7796a nat: Store the creation time of a sccp connection.
Generate it when creating the connection but also when
reusing an existing connection.
2010-05-12 00:33:38 +08:00
Holger Hans Peter Freyther
49fcc8fc90 bsc_msc_ip: Use constants for ?/0/1. 2010-05-11 22:54:29 +08:00
Holger Hans Peter Freyther
51a4bcc96a Increase the version... as we have new commands 2010-05-11 20:02:36 +08:00
Holger Hans Peter Freyther
d6238120dd bsc_msc_ip: Add an extra command to show the MSC status. 2010-05-11 20:00:22 +08:00
Holger Hans Peter Freyther
7407aec921 bsc_msc_ip: Move the MSC connection into the structure 2010-05-11 20:00:22 +08:00
Holger Hans Peter Freyther
e575ce69ce nat: Print the MSC status with a new vty command. 2010-05-11 20:00:16 +08:00
Holger Hans Peter Freyther
c1ca0ff091 misc: Make sure PACKAGE_VERSION is getting defined with a useful content.
PACKAGE_VERSION is used by the copyright message.
2010-05-11 19:08:10 +08:00
Holger Hans Peter Freyther
661e68b78f bsc_msc_ip: Add a test mode to send messages to the MSC.
Check if the MSC likes paging responses when it has not
recently send out a paging request.
2010-05-11 19:08:10 +08:00
Holger Hans Peter Freyther
376e146cfb gsm0408: Use counter_inc to increment the counter. 2010-05-11 19:08:10 +08:00
Holger Hans Peter Freyther
eb3ab2f85b bsc_msc: Add a connection timeout for the MSC.
When no one is listening our connection would get stuck
in the SYN_SENT state and we would be there forever.
2010-05-05 22:48:56 +08:00
Holger Hans Peter Freyther
ebc38e4f26 Version bump for testing it on the target 2010-05-05 20:43:11 +08:00
Holger Hans Peter Freyther
e2ab44a439 nat: Using the right fd can be a good idea as well 2010-05-05 20:42:14 +08:00
Holger Hans Peter Freyther
8b3cced773 Another version... another try 2010-05-05 20:37:10 +08:00
Holger Hans Peter Freyther
3d1b0770f4 nat: Fix bad bug, make sure the fd is not overwritten..
The adding of the innocent looking code was actually overwrote
the fd and then stupid things happened. Rename variables to avoid
that. rc,ret should be scratch variables...
2010-05-05 20:33:34 +08:00
Holger Hans Peter Freyther
99743fb7ec Bump the version for TCP_NODELAY. 2010-05-05 19:01:23 +08:00
Holger Hans Peter Freyther
a2a42a7561 bsc_msc_ip: Attempt to disable nagle
Use TCP_NODELAY on the connection to the MSC. We want small
messages to be send immediately.
2010-05-05 19:00:38 +08:00
Holger Hans Peter Freyther
ebd57da87d nat: Use TCP_NODELAY for the connection to the BSC.
We do not want to use NAGLE for the BSC connection.
2010-05-05 18:59:54 +08:00
Holger Hans Peter Freyther
b0ee082bb0 Bump version
Configurable timeout.
2010-05-05 17:52:40 +08:00
Holger Hans Peter Freyther
81f6a4c0bf bsc_msc_ip: Add VTY code for ping/pong timeout. 2010-05-05 17:46:08 +08:00
Holger Hans Peter Freyther
3978de52c1 bsc_msc_ip: Do not send a ping when the timeout is negative 2010-05-05 17:42:32 +08:00
Holger Hans Peter Freyther
7faf692cb7 bsc_msc_ip: Make the ping/pong timeouts configurable
Take the timeouts from the struct.
2010-05-05 17:39:22 +08:00
Holger Hans Peter Freyther
0cf25d5154 nat: Improve log messages. Refer to ip and fd. 2010-05-05 17:03:44 +08:00
Holger Hans Peter Freyther
08db178271 nat: Make ping/pong timeout configurable. 2010-05-05 16:57:38 +08:00
Holger Hans Peter Freyther
936d8c1b64 Work with later libosmocore. 2010-05-03 19:38:01 +08:00
Harald Welte
3170305e56 move gsm48_construct_ra() to libosmocore 2010-05-03 19:36:58 +08:00
Harald Welte
0f3490dd03 'struct gprs_ra_id' is now defined in libosmocore 2010-05-03 19:36:41 +08:00
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
42 changed files with 997 additions and 379 deletions

View File

@@ -1,7 +1,6 @@
dnl Process this file with autoconf to produce a configure script
AC_INIT
AM_INIT_AUTOMAKE(openbsc, 0.3.99onwaves)
AC_INIT(openbsc, 0.3.99.10onwaves)
AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
dnl kernel style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])

View File

@@ -164,7 +164,8 @@ enum nm_evt {
EVT_STATECHG_ADM,
};
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state);
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
struct abis_om_obj_inst *obj_inst);
const char *nm_opstate_name(u_int8_t os);
const char *nm_avail_name(u_int8_t avail);

View File

@@ -36,6 +36,7 @@ struct bsc_msc_connection {
void (*connection_loss) (struct bsc_msc_connection *);
void (*connected) (struct bsc_msc_connection *);
struct timer_list reconnect_timer;
struct timer_list timeout_timer;
};
struct bsc_msc_connection *bsc_msc_create(const char *ip, int port);

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,10 +114,15 @@ 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;
/* timeout handling */
struct timespec creation_time;
};
/**
@@ -146,6 +155,8 @@ struct bsc_config {
char *imsi_deny;
regex_t imsi_deny_re;
int forbid_paging;
/* backpointer */
struct bsc_nat *nat;
@@ -160,8 +171,6 @@ struct bsc_endpoint {
char *transaction_id;
/* the bsc we are talking to */
struct bsc_connection *bsc;
/* pending delete */
int pending_delete;
};
/**
@@ -207,6 +216,12 @@ struct bsc_nat {
char *msc_ip;
int msc_port;
int first_contact;
struct bsc_msc_connection *msc_con;
/* timeouts */
int auth_timeout;
int ping_timeout;
int pong_timeout;
struct bsc_endpoint *bsc_endpoints;
@@ -228,6 +243,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 +264,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

@@ -3,6 +3,8 @@
#include <sys/types.h>
struct bsc_msc_connection;
enum gsm_phys_chan_config {
GSM_PCHAN_NONE,
GSM_PCHAN_CCCH,
@@ -85,11 +87,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 +129,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 */
@@ -677,6 +675,9 @@ struct gsm_network {
char *bsc_token;
char *msc_ip;
int msc_port;
struct bsc_msc_connection *msc_con;
int ping_timeout;
int pong_timeout;
};
#define SMS_HDR_SIZE 128
@@ -778,14 +779,6 @@ const char *bts_gprs_mode_name(enum bts_gprs_mode mode);
void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked);
/* A parsed GPRS routing area */
struct gprs_ra_id {
u_int16_t mnc;
u_int16_t mcc;
u_int16_t lac;
u_int8_t rac;
};
int gsm48_ra_id_by_bts(u_int8_t *buf, struct gsm_bts *bts);
void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts);
struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan);

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

@@ -56,4 +56,4 @@ bsc_nat_SOURCES = nat/bsc_nat.c nat/bsc_filter.c nat/bsc_sccp.c \
nat/bsc_nat_utils.c nat/bsc_nat_vty.c nat/bsc_mgcp_utils.c \
mgcp/mgcp_protocol.c mgcp/mgcp_network.c mgcp/mgcp_vty.c \
bsc_msc.c bssap.c
bsc_nat_LDADD = libvty.a libbsc.a libsccp.a
bsc_nat_LDADD = libvty.a libbsc.a libsccp.a -lrt

View File

@@ -678,7 +678,7 @@ static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
new_state = *nm_state;
new_state.administrative = adm_state;
rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state);
rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state, obj_inst);
nm_state->administrative = adm_state;
@@ -732,7 +732,7 @@ static int abis_nm_rx_statechg_rep(struct msgb *mb)
/* Update the operational state of a given object in our in-memory data
* structures and send an event to the higher layer */
void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state);
rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state, &foh->obj_inst);
nm_state->operational = new_state.operational;
nm_state->availability = new_state.availability;
if (nm_state->administrative == 0)

View File

@@ -697,7 +697,8 @@ int handle_serial_msg(struct msgb *rx_msg)
}
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
struct abis_om_obj_inst *obj_ins)
{
return 0;
}

View File

@@ -401,7 +401,8 @@ static unsigned char nanobts_attr_nsvc0[] = {
/* Callback function to be called whenever we get a GSM 12.21 state change event */
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
struct abis_om_obj_inst *obj_inst)
{
struct gsm_bts *bts;
struct gsm_bts_trx *trx;
@@ -418,16 +419,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 +441,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 +456,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 +465,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 +479,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));

View File

@@ -49,6 +49,14 @@ static void connection_loss(struct bsc_msc_connection *con)
con->connection_loss(con);
}
static void msc_con_timeout(void *_con)
{
struct bsc_msc_connection *con = _con;
LOGP(DMSC, LOGL_ERROR, "MSC Connection timeout.\n");
bsc_msc_lost(con);
}
static int bsc_msc_except(struct bsc_fd *bfd)
{
struct write_queue *wrt;
@@ -98,6 +106,7 @@ static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
con->is_connected = 1;
bsc_del_timer(&con->timeout_timer);
LOGP(DMSC, LOGL_NOTICE, "(Re)Connected to the MSC.\n");
if (con->connected)
con->connected(con);
@@ -165,6 +174,9 @@ int bsc_msc_connect(struct bsc_msc_connection *con)
LOGP(DMSC, LOGL_ERROR, "MSC Connection in progress\n");
fd->when = BSC_FD_WRITE;
fd->cb = msc_connection_connect;
con->timeout_timer.cb = msc_con_timeout;
con->timeout_timer.data = con;
bsc_schedule_timer(&con->timeout_timer, 20, 0);
} else if (ret < 0) {
perror("Connection failed");
connection_loss(con);

View File

@@ -30,6 +30,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#define _GNU_SOURCE
@@ -46,9 +47,12 @@
#include <openbsc/bsc_nat.h>
#include <openbsc/bsc_msc_rf.h>
#include <vty/command.h>
#include <osmocore/select.h>
#include <osmocore/talloc.h>
#include <osmocore/write_queue.h>
#include <osmocore/gsm0808.h>
#include <sccp/sccp.h>
@@ -60,22 +64,41 @@ 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;
static int testmode = 0;
extern int ipacc_rtp_direct;
/* msc handling */
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);
static void install_extra_commands();
struct llist_head *bsc_sccp_connections()
{
return &active_connections;
}
/*
* Having a subscriber in the lchan is used to indicate that a SACH DEACTIVATE
* should be send. We will just introduce a fake subscriber and bind it to the
* lchan.
*/
static void assign_dummy_subscr(struct gsm_lchan *lchan)
{
if (!lchan->conn.subscr) {
lchan->conn.subscr = subscr_get_or_create(bsc_gsmnet, "2323");
lchan->conn.subscr->lac = 2323;
}
}
struct bss_sccp_connection_data *bss_sccp_create_data()
{
struct bss_sccp_connection_data *data;
@@ -95,6 +118,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 +136,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 +259,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);
@@ -225,7 +288,7 @@ static int open_sccp_connection(struct msgb *layer3)
struct msgb *data;
/* When not connected to a MSC. We will simply close things down. */
if (!msc_con->is_authenticated) {
if (!bsc_gsmnet->msc_con->is_authenticated) {
LOGP(DMSC, LOGL_ERROR, "Not connected to a MSC. Not forwarding data.\n");
use_subscr_con(&layer3->lchan->conn);
put_subscr_con(&layer3->lchan->conn, 0);
@@ -263,7 +326,14 @@ 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 */
/* assign a dummy subscriber */
assign_dummy_subscr(layer3->lchan);
use_subscr_con(&layer3->lchan->conn);
sccp_connection_connect(sccp_connection, &sccp_ssn_bssap, data);
msgb_free(data);
@@ -371,6 +441,9 @@ static int handle_ass_compl(struct msgb *msg)
msg->lchan->msc_data->secondary_lchan = NULL;
old_chan->msc_data = NULL;
/* assign a dummy subscriber */
assign_dummy_subscr(msg->lchan);
/* give up the old channel to not do a SACCH deactivate */
if (old_chan->conn.subscr)
subscr_put(old_chan->conn.subscr);
@@ -586,7 +659,7 @@ static void print_usage()
static int msc_queue_write(struct msgb *msg, int proto)
{
ipaccess_prepend_header(msg, proto);
if (write_queue_enqueue(&msc_con->write_queue, msg) != 0) {
if (write_queue_enqueue(&bsc_gsmnet->msc_con->write_queue, msg) != 0) {
LOGP(DMSC, LOGL_FATAL, "Failed to queue IPA/%d\n", proto);
msgb_free(msg);
return -1;
@@ -602,7 +675,7 @@ static int msc_sccp_do_write(struct bsc_fd *fd, struct msgb *msg)
LOGP(DMSC, LOGL_DEBUG, "Sending SCCP to MSC: %u\n", msgb_l2len(msg));
LOGP(DMI, LOGL_DEBUG, "MSC TX %s\n", hexdump(msg->l2h, msgb_l2len(msg)));
ret = write(msc_con->write_queue.bfd.fd, msg->data, msg->len);
ret = write(bsc_gsmnet->msc_con->write_queue.bfd.fd, msg->data, msg->len);
if (ret < msg->len)
perror("MSC: Failed to send SCCP");
@@ -774,9 +847,9 @@ static void initialize_if_needed(void)
struct msgb *msg;
if (!msc_con->is_authenticated) {
if (!bsc_gsmnet->msc_con->is_authenticated) {
/* send a gsm 08.08 reset message from here */
msg = bssmap_create_reset();
msg = gsm0808_create_reset();
if (!msg) {
LOGP(DMSC, LOGL_ERROR, "Failed to create the reset message.\n");
return;
@@ -784,7 +857,7 @@ static void initialize_if_needed(void)
sccp_write(msg, &sccp_ssn_bssap, &sccp_ssn_bssap, 0);
msgb_free(msg);
msc_con->is_authenticated = 1;
bsc_gsmnet->msc_con->is_authenticated = 1;
}
}
@@ -809,6 +882,32 @@ static void send_id_get_response(int fd)
msc_queue_write(msg, IPAC_PROTO_IPACCESS);
}
/*
* Send some packets to test the MSC.
*/
static void test_msc()
{
struct msgb *msg;
if (!testmode)
return;
static const uint8_t pag_resp[] = {
0x01, 0xf3, 0x26, 0x09, 0x02, 0x02, 0x04, 0x02, 0x42,
0xfe, 0x0f, 0x1f, 0x00, 0x1d, 0x57, 0x05, 0x08, 0x00,
0x72, 0xf4, 0x80, 0x10, 0x1c, 0x9c, 0x40, 0x17, 0x10,
0x06, 0x27, 0x02, 0x03, 0x30, 0x18, 0xa0, 0x08, 0x59,
0x51, 0x30, 0x10, 0x30, 0x32, 0x80, 0x06, 0x00
};
msg = msgb_alloc_headroom(4096, 128, "paging response");
if (!msg)
return;
msg->l2h = msgb_put(msg, sizeof(pag_resp));
memcpy(msg->l2h, pag_resp, sizeof(pag_resp));
msc_queue_write(msg, IPAC_PROTO_SCCP);
}
/*
* The connection to the MSC was lost and we will need to free all
* resources and then attempt to reconnect.
@@ -820,31 +919,63 @@ 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(bsc_gsmnet->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)
{
if (bsc_gsmnet->ping_timeout < 0)
return;
send_ping();
/* send another ping in 20 seconds */
bsc_schedule_timer(&msc_ping_timeout, bsc_gsmnet->ping_timeout, 0);
/* also start a pong timer */
bsc_schedule_timer(&msc_pong_timeout, bsc_gsmnet->pong_timeout, 0);
}
static void msc_connection_connected(struct bsc_msc_connection *con)
{
int ret, on;
on = 1;
ret = setsockopt(con->write_queue.bfd.fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
if (ret != 0)
LOGP(DMSC, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
msc_ping_timeout_cb(con);
}
/*
* callback with IP access data
*/
@@ -857,7 +988,7 @@ static int ipaccess_a_fd_cb(struct bsc_fd *bfd)
if (!msg) {
if (error == 0) {
LOGP(DMSC, LOGL_ERROR, "The connection to the MSC was lost.\n");
bsc_msc_lost(msc_con);
bsc_msc_lost(bsc_gsmnet->msc_con);
return -1;
}
@@ -877,6 +1008,9 @@ 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);
test_msc();
} 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);
@@ -900,6 +1034,7 @@ static void print_help()
printf(" -l --local=IP. The local address of the MGCP.\n");
printf(" -e --log-level number. Set a global loglevel.\n");
printf(" -r --rf-ctl NAME. A unix domain socket to listen for cmds.\n");
printf(" -t --testmode. A special mode to provoke failures at the MSC.\n");
}
static void handle_options(int argc, char** argv)
@@ -916,10 +1051,11 @@ static void handle_options(int argc, char** argv)
{"local", 1, 0, 'l'},
{"log-level", 1, 0, 'e'},
{"rf-ctl", 1, 0, 'r'},
{"testmode", 0, 0, 't'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, "hd:sTc:m:l:e:r:",
c = getopt_long(argc, argv, "hd:sTc:m:l:e:r:t",
long_options, &option_index);
if (c == -1)
break;
@@ -956,6 +1092,9 @@ static void handle_options(int argc, char** argv)
case 'r':
rf_ctl = optarg;
break;
case 't':
testmode = 1;
break;
default:
/* ignore */
break;
@@ -982,9 +1121,9 @@ static void signal_handler(int signal)
talloc_report_full(tall_bsc_ctx, stderr);
break;
case SIGUSR2:
if (!msc_con || !msc_con->is_connected)
if (!bsc_gsmnet->msc_con || !bsc_gsmnet->msc_con->is_connected)
return;
bsc_msc_lost(msc_con);
bsc_msc_lost(bsc_gsmnet->msc_con);
break;
default:
break;
@@ -1099,16 +1238,22 @@ int main(int argc, char **argv)
if (msc_address)
msc = msc_address;
msc_con = bsc_msc_create(msc, bsc_gsmnet->msc_port);
if (!msc_con) {
bsc_gsmnet->msc_con = bsc_msc_create(msc, bsc_gsmnet->msc_port);
if (!bsc_gsmnet->msc_con) {
fprintf(stderr, "Creating a bsc_msc_connection failed.\n");
exit(1);
}
msc_con->connection_loss = msc_connection_was_lost;
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);
install_extra_commands();
msc_ping_timeout.cb = msc_ping_timeout_cb;
msc_pong_timeout.cb = msc_pong_timeout_cb;
bsc_gsmnet->msc_con->connection_loss = msc_connection_was_lost;
bsc_gsmnet->msc_con->connected = msc_connection_connected;
bsc_gsmnet->msc_con->write_queue.read_cb = ipaccess_a_fd_cb;
bsc_gsmnet->msc_con->write_queue.write_cb = msc_sccp_do_write;
bsc_msc_connect(bsc_gsmnet->msc_con);
@@ -1116,3 +1261,25 @@ int main(int argc, char **argv)
bsc_select_main(0);
}
}
DEFUN(show_msc,
show_msc_cmd,
"show msc connection",
SHOW_STR "Show the status of the MSC connection.")
{
if (!bsc_gsmnet->msc_con) {
vty_out(vty, "The MSC is not yet configured.\n");
return CMD_WARNING;
}
vty_out(vty, "MSC on %s:%d is connected: %d%s\n",
bsc_gsmnet->msc_con->ip, bsc_gsmnet->msc_con->port,
bsc_gsmnet->msc_con->is_connected, VTY_NEWLINE);
return CMD_SUCCESS;
}
static void install_extra_commands()
{
install_element(VIEW_NODE, &show_msc_cmd);
}

View File

@@ -59,14 +59,14 @@ static void handle_query(struct bsc_msc_rf_conn *conn)
{
struct msgb *msg;
struct gsm_bts *bts;
char send = '0';
char send = RF_CMD_OFF;
llist_for_each_entry(bts, &conn->gsm_network->bts_list, list) {
struct gsm_bts_trx *trx;
llist_for_each_entry(trx, &bts->trx_list, list) {
if (trx->nm_state.availability == NM_AVSTATE_OK &&
trx->nm_state.operational != NM_STATE_LOCKED) {
send = '1';
send = RF_CMD_ON;
break;
}
}

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);
@@ -172,7 +174,7 @@ static int bssmap_handle_clear_command(struct sccp_connection *conn,
}
/* send the clear complete message */
resp = bssmap_create_clear_complete();
resp = gsm0808_create_clear_complete();
if (!resp) {
LOGP(DMSC, LOGL_ERROR, "Sending clear complete failed.\n");
return -1;
@@ -310,7 +312,7 @@ static void bssmap_t10_fired(void *_conn)
msc_data = conn->data_ctx;
bssmap_free_secondary(msc_data);
resp = bssmap_create_assignment_failure(
resp = gsm0808_create_assignment_failure(
GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
if (!resp) {
LOGP(DMSC, LOGL_ERROR, "Allocation failure: %p\n", conn);
@@ -763,36 +765,6 @@ struct msgb *bssmap_create_layer3(struct msgb *msg_l3)
return msg;
}
struct msgb *bssmap_create_reset(void)
{
struct msgb *msg = msgb_alloc(30, "bssmap: reset");
if (!msg)
return NULL;
msg->l3h = msgb_put(msg, 6);
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
msg->l3h[1] = 0x04;
msg->l3h[2] = 0x30;
msg->l3h[3] = 0x04;
msg->l3h[4] = 0x01;
msg->l3h[5] = 0x20;
return msg;
}
struct msgb *bssmap_create_clear_complete(void)
{
struct msgb *msg = msgb_alloc(30, "bssmap: clear complete");
if (!msg)
return NULL;
msg->l3h = msgb_put(msg, 3);
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
msg->l3h[1] = 1;
msg->l3h[2] = BSS_MAP_MSG_CLEAR_COMPLETE;
return msg;
}
struct msgb *bssmap_create_cipher_complete(struct msgb *layer3)
{
struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
@@ -1003,36 +975,6 @@ struct msgb *bssmap_create_assignment_completed(struct gsm_lchan *lchan, u_int8_
return msg;
}
struct msgb *bssmap_create_assignment_failure(u_int8_t cause, u_int8_t *rr_cause)
{
u_int8_t *data;
struct msgb *msg = msgb_alloc(35, "bssmap: ass fail");
if (!msg)
return NULL;
msg->l3h = msgb_put(msg, 6);
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
msg->l3h[1] = 0xff;
msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_FAILURE;
msg->l3h[3] = GSM0808_IE_CAUSE;
msg->l3h[4] = 1;
msg->l3h[5] = cause;
/* RR cause 3.2.2.22 */
if (rr_cause) {
data = msgb_put(msg, 2);
data[0] = GSM0808_IE_RR_CAUSE;
data[1] = *rr_cause;
}
/* Circuit pool 3.22.45 */
/* Circuit pool list 3.2.2.46 */
/* update the size */
msg->l3h[1] = msgb_l3len(msg) - 2;
return msg;
}
struct msgb *dtap_create_msg(struct msgb *msg_l3, u_int8_t link_id)
{
struct dtap_header *header;
@@ -1236,7 +1178,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 +1194,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 +1220,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 +1242,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]);
}
}
@@ -1310,7 +1252,7 @@ void gsm0808_send_assignment_failure(struct gsm_lchan *lchan, u_int8_t cause, u_
bsc_del_timer(&lchan->msc_data->T10);
bssmap_free_secondary(lchan->msc_data);
resp = bssmap_create_assignment_failure(cause, rr_value);
resp = gsm0808_create_assignment_failure(cause, rr_value);
if (!resp) {
LOGP(DMSC, LOGL_ERROR, "Allocation failure: %p\n", lchan_get_sccp(lchan));
return;

View File

@@ -381,6 +381,11 @@ static void _lchan_handle_release(struct gsm_lchan *lchan)
++lchan->conn.use_count;
gsm48_send_rr_release(lchan);
--lchan->conn.use_count;
/* avoid reentrancy */
subscr_put(lchan->conn.subscr);
lchan->conn.subscr = NULL;
return;
}
/* spoofed? message */

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

@@ -321,7 +321,7 @@ int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr)
sig_data.bts = msg->lchan->ts->trx->bts;
sig_data.lchan = msg->lchan;
bts->network->stats.paging.completed++;
counter_inc(bts->network->stats.paging.completed);
dispatch_signal(SS_PAGING, S_PAGING_SUCCEEDED, &sig_data);

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

@@ -300,6 +300,8 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c
net->msc_ip = talloc_strdup(net, "127.0.0.1");
net->msc_port = 5000;
net->ping_timeout = 20;
net->pong_timeout = 5;
return net;
}
@@ -454,33 +456,6 @@ const char *gsm_auth_policy_name(enum gsm_auth_policy policy)
return get_value_string(auth_policy_names, policy);
}
/* this should not be here but in gsm_04_08... but that creates
in turn a dependency nightmare (abis_nm depending on 04_08, ...) */
static int gsm48_construct_ra(u_int8_t *buf, const struct gprs_ra_id *raid)
{
u_int16_t mcc = raid->mcc;
u_int16_t mnc = raid->mnc;
buf[0] = ((mcc / 100) % 10) | (((mcc / 10) % 10) << 4);
buf[1] = (mcc % 10);
/* I wonder who came up with the stupidity of encoding the MNC
* differently depending on how many digits its decimal number has! */
if (mnc < 100) {
buf[1] |= 0xf0;
buf[2] = ((mnc / 10) % 10) | ((mnc % 10) << 4);
} else {
buf[1] |= (mnc % 10) << 4;
buf[2] = ((mnc / 100) % 10) | (((mcc / 10) % 10) << 4);
}
*(u_int16_t *)(buf+3) = htons(raid->lac);
buf[5] = raid->rac;
return 6;
}
void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts)
{
raid->mcc = bts->network->country_code;

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

@@ -1,8 +1,8 @@
/* ip.access nanoBTS configuration tool */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2009 by Holger Hans Peter Freyther
* (C) 2009 by On Waves
* (C) 2009,2010 by Holger Hans Peter Freyther
* (C) 2009,2010 by On Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -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 found_trx = 0;
struct sw_load {
u_int8_t file_id[255];
@@ -298,13 +299,14 @@ static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg,
return 0;
}
static void bootstrap_om(struct gsm_bts *bts)
static void bootstrap_om(struct gsm_bts_trx *trx)
{
int len;
static u_int8_t buf[1024];
u_int8_t *cur = buf;
struct gsm_bts *bts = trx->bts;
printf("OML link established\n");
printf("OML link established using TRX %d\n", trx->nr);
if (unit_id) {
len = strlen(unit_id);
@@ -316,7 +318,7 @@ 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(trx, buf, 3+len+1);
}
if (prim_oml_ip) {
struct in_addr ia;
@@ -354,7 +356,7 @@ 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(trx, buf, 3+len);
}
if (restart && !prim_oml_ip && !software) {
@@ -370,7 +372,6 @@ void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
case EVT_E1_TEI_UP:
switch (type) {
case E1INP_SIGN_OML:
bootstrap_om(trx->bts);
break;
case E1INP_SIGN_RSL:
/* FIXME */
@@ -389,9 +390,16 @@ void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
}
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
struct abis_om_obj_inst *obj_inst)
{
if (evt == EVT_STATECHG_OPER &&
if (obj_class == NM_OC_BASEB_TRANSC) {
if (!found_trx && obj_inst->trx_nr != 0xff) {
struct gsm_bts_trx *trx = container_of(obj, struct gsm_bts_trx, bb_transc);
bootstrap_om(trx);
found_trx = 1;
}
} else if (evt == EVT_STATECHG_OPER &&
obj_class == NM_OC_RADIO_CARRIER &&
new_state->availability == 3) {
struct gsm_bts_trx *trx = obj;
@@ -639,6 +647,7 @@ int main(int argc, char **argv)
{ "software", 1, 0, 'd' },
{ "firmware", 1, 0, 'f' },
{ "write-firmware", 0, 0, 'w' },
{ 0, 0, 0, 0 },
};
c = getopt_long(argc, argv, "u:o:rn:l:hs:d:f:w", long_options,
@@ -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

@@ -23,6 +23,7 @@
*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <errno.h>
@@ -49,17 +50,19 @@
#include <sccp/sccp.h>
#define SCCP_CLOSE_TIME 20
#define SCCP_CLOSE_TIME_TIMEOUT 19
struct log_target *stderr_target;
static const char *config_file = "bsc-nat.cfg";
static struct in_addr local_addr;
static struct bsc_msc_connection *msc_con;
static struct bsc_fd bsc_listen;
static const char *msc_ip = NULL;
static struct timer_list sccp_close;
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)
@@ -77,7 +80,8 @@ struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num)
* below are stubs we need to link
*/
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
struct abis_om_obj_inst *obj_ins)
{
return -1;
}
@@ -90,6 +94,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(&nat->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 +113,58 @@ 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;
if (bsc->nat->ping_timeout < 0)
return;
send_ping(bsc);
/* send another ping in 20 seconds */
bsc_schedule_timer(&bsc->ping_timeout, bsc->nat->ping_timeout, 0);
/* also start a pong timer */
bsc_schedule_timer(&bsc->pong_timeout, bsc->nat->pong_timeout, 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 +211,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(nat->msc_con, msg);
}
static void nat_send_rlc(struct sccp_source_reference *src,
@@ -173,10 +234,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(nat->msc_con, msg);
}
static void send_mgcp_reset(struct bsc_connection *bsc)
@@ -199,7 +257,7 @@ static void initialize_msc_if_needed()
return;
nat->first_contact = 1;
msc_send_reset(msc_con);
msc_send_reset(nat->msc_con);
}
/*
@@ -311,7 +369,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 +400,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 +427,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(nat->msc_con, msg);
LOGP(DMSC, LOGL_NOTICE, "Scheduled GSM0808 reset msg for the MSC.\n");
}
@@ -382,13 +439,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(nat->msc_con);
return -1;
}
@@ -432,29 +488,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 +528,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,18 +536,27 @@ 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);
bsc->authenticated = 1;
bsc->cfg = conf;
bsc_del_timer(&bsc->id_timeout);
LOGP(DNAT, LOGL_NOTICE, "Authenticated bsc nr: %d lac: %d\n", conf->nr, conf->lac);
LOGP(DNAT, LOGL_NOTICE, "Authenticated bsc nr: %d lac: %d on fd %d\n",
conf->nr, conf->lac, bsc->write_queue.bfd.fd);
start_ping_pong(bsc);
return;
}
}
LOGP(DNAT, LOGL_ERROR, "No bsc found for token %s.\n", token);
LOGP(DNAT, LOGL_ERROR, "No bsc found for token %s on fd: %d.\n", token,
bsc->write_queue.bfd.fd);
}
static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
@@ -524,17 +593,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 +625,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(nat->msc_con, msg);
talloc_free(parsed);
return 0;
@@ -598,14 +665,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 +685,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);
@@ -634,17 +721,17 @@ static int ipaccess_bsc_write_cb(struct bsc_fd *bfd, struct msgb *msg)
static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what)
{
struct bsc_connection *bsc;
int ret;
int fd, rc, on;
struct sockaddr_in sa;
socklen_t sa_len = sizeof(sa);
if (!(what & BSC_FD_READ))
return 0;
ret = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len);
if (ret < 0) {
fd = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len);
if (fd < 0) {
perror("accept");
return ret;
return fd;
}
/* count the reconnect */
@@ -653,12 +740,17 @@ static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what)
/*
* if we are not connected to a msc... just close the socket
*/
if (!msc_con->is_connected) {
if (!nat->msc_con->is_connected) {
LOGP(DNAT, LOGL_NOTICE, "Disconnecting BSC due lack of MSC connection.\n");
close(ret);
close(fd);
return 0;
}
on = 1;
rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
if (rc != 0)
LOGP(DNAT, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
/* todo... do something with the connection */
/* todo... use GNUtls to see if we want to trust this as a BTS */
@@ -668,24 +760,24 @@ static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what)
bsc = bsc_connection_alloc(nat);
if (!bsc) {
LOGP(DNAT, LOGL_ERROR, "Failed to allocate BSC struct.\n");
close(ret);
close(fd);
return -1;
}
write_queue_init(&bsc->write_queue, 100);
bsc->write_queue.bfd.data = bsc;
bsc->write_queue.bfd.fd = ret;
bsc->write_queue.bfd.fd = fd;
bsc->write_queue.read_cb = ipaccess_bsc_read_cb;
bsc->write_queue.write_cb = ipaccess_bsc_write_cb;
bsc->write_queue.bfd.when = BSC_FD_READ;
if (bsc_register_fd(&bsc->write_queue.bfd) < 0) {
LOGP(DNAT, LOGL_ERROR, "Failed to register BSC fd.\n");
close(ret);
close(fd);
talloc_free(bsc);
return -2;
}
LOGP(DNAT, LOGL_NOTICE, "Registered new BSC\n");
LOGP(DNAT, LOGL_NOTICE, "BSC connection on %d with IP: %s\n",
fd, inet_ntoa(sa.sin_addr));
llist_add(&bsc->list_entry, &nat->bsc_connections);
send_id_ack(bsc);
send_id_req(bsc);
@@ -696,7 +788,7 @@ static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what)
*/
bsc->id_timeout.data = bsc;
bsc->id_timeout.cb = ipaccess_close_bsc;
bsc_schedule_timer(&bsc->id_timeout, 2, 0);
bsc_schedule_timer(&bsc->id_timeout, nat->auth_timeout, 0);
return 0;
}
@@ -817,9 +909,43 @@ static void signal_handler(int signal)
}
}
static void sccp_close_unconfirmed(void *_data)
{
struct sccp_connections *conn, *tmp1;
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
llist_for_each_entry_safe(conn, tmp1, &nat->sccp_connections, list_entry) {
if (conn->has_remote_ref)
continue;
int diff = (now.tv_sec - conn->creation_time.tv_sec) / 60;
if (diff < SCCP_CLOSE_TIME_TIMEOUT)
continue;
LOGP(DNAT, LOGL_ERROR, "SCCP connection 0x%x/0x%x was never confirmed.\n",
sccp_src_ref_to_int(&conn->real_ref),
sccp_src_ref_to_int(&conn->patched_ref));
sccp_connection_destroy(conn);
}
bsc_schedule_timer(&sccp_close, SCCP_CLOSE_TIME, 0);
}
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,20 +984,20 @@ 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 */
msc_con = bsc_msc_create(nat->msc_ip, nat->msc_port);
if (!msc_con) {
nat->msc_con = bsc_msc_create(nat->msc_ip, nat->msc_port);
if (!nat->msc_con) {
fprintf(stderr, "Creating a bsc_msc_connection failed.\n");
exit(1);
}
msc_con->connection_loss = msc_connection_was_lost;
msc_con->write_queue.read_cb = ipaccess_msc_read_cb;
msc_con->write_queue.write_cb = ipaccess_msc_write_cb;;
bsc_msc_connect(msc_con);
nat->msc_con->connection_loss = msc_connection_was_lost;
nat->msc_con->write_queue.read_cb = ipaccess_msc_read_cb;
nat->msc_con->write_queue.write_cb = ipaccess_msc_write_cb;;
bsc_msc_connect(nat->msc_con);
/* wait for the BSC */
if (listen_for_bsc(&bsc_listen, &local_addr, 5000) < 0) {
@@ -883,6 +1009,11 @@ int main(int argc, char** argv)
signal(SIGUSR1, &signal_handler);
signal(SIGPIPE, SIG_IGN);
/* recycle timer */
sccp_close.cb = sccp_close_unconfirmed;
sccp_close.data = NULL;
bsc_schedule_timer(&sccp_close, SCCP_CLOSE_TIME, 0);
while (1) {
bsc_select_main(0);
}

View File

@@ -53,6 +53,9 @@ struct bsc_nat *bsc_nat_alloc(void)
nat->stats.msc.reconn = counter_alloc("nat.msc.conn");
nat->msc_ip = talloc_strdup(nat, "127.0.0.1");
nat->msc_port = 5000;
nat->auth_timeout = 2;
nat->ping_timeout = 20;
nat->pong_timeout = 5;
return nat;
}
@@ -70,6 +73,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 +103,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 +131,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

@@ -24,6 +24,7 @@
#include <vty/vty.h>
#include <openbsc/bsc_nat.h>
#include <openbsc/bsc_msc.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/mgcp.h>
#include <openbsc/vty.h>
@@ -57,6 +58,9 @@ static int config_write_nat(struct vty *vty)
vty_out(vty, " insi deny %s%s", _nat->imsi_deny, VTY_NEWLINE);
vty_out(vty, " msc ip %s%s", _nat->msc_ip, VTY_NEWLINE);
vty_out(vty, " msc port %d%s", _nat->msc_port, VTY_NEWLINE);
vty_out(vty, " timeout auth %d%s", _nat->auth_timeout, VTY_NEWLINE);
vty_out(vty, " timeout ping %d%s", _nat->ping_timeout, VTY_NEWLINE);
vty_out(vty, " timeout pong %d%s", _nat->pong_timeout, VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -69,6 +73,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 +90,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 +116,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 +126,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 +137,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 +146,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 +167,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 +182,40 @@ DEFUN(show_stats,
return CMD_SUCCESS;
}
DEFUN(show_msc,
show_msc_cmd,
"show msc connection",
SHOW_STR "Show the status of the MSC connection.")
{
if (!_nat->msc_con) {
vty_out(vty, "The MSC is not yet configured.\n");
return CMD_WARNING;
}
vty_out(vty, "MSC on %s:%d is connected: %d%s\n",
_nat->msc_con->ip, _nat->msc_con->port,
_nat->msc_con->is_connected, VTY_NEWLINE);
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;
@@ -223,8 +276,35 @@ DEFUN(cfg_nat_msc_port,
return CMD_SUCCESS;
}
DEFUN(cfg_nat_auth_time,
cfg_nat_auth_time_cmd,
"timeout auth <1-256>",
"The time to wait for an auth response.")
{
_nat->auth_timeout = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_nat_ping_time,
cfg_nat_ping_time_cmd,
"timeout ping NR",
"Send a ping every NR seconds. Negative to disable.")
{
_nat->ping_timeout = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_nat_pong_time,
cfg_nat_pong_time_cmd,
"timeout pong NR",
"Wait NR seconds for the PONG response. Should be smaller than ping.")
{
_nat->pong_timeout = atoi(argv[0]);
return CMD_SUCCESS;
}
/* 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 +339,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 +395,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 +422,8 @@ 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);
install_element(VIEW_NODE, &show_msc_cmd);
openbsc_vty_add_cmds();
@@ -338,6 +435,9 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
install_element(NAT_NODE, &cfg_nat_imsi_deny_cmd);
install_element(NAT_NODE, &cfg_nat_msc_ip_cmd);
install_element(NAT_NODE, &cfg_nat_msc_port_cmd);
install_element(NAT_NODE, &cfg_nat_auth_time_cmd);
install_element(NAT_NODE, &cfg_nat_ping_time_cmd);
install_element(NAT_NODE, &cfg_nat_pong_time_cmd);
/* BSC subgroups */
install_element(NAT_NODE, &cfg_bsc_cmd);
@@ -347,6 +447,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

@@ -28,6 +28,7 @@
#include <osmocore/talloc.h>
#include <string.h>
#include <time.h>
static int equal(struct sccp_source_reference *ref1, struct sccp_source_reference *ref2)
{
@@ -85,6 +86,30 @@ 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));
bsc_mgcp_dlcx(conn);
llist_del(&conn->list_entry);
talloc_free(conn);
return -1;
} else {
clock_gettime(CLOCK_MONOTONIC, &conn->creation_time);
bsc_mgcp_dlcx(conn);
return 0;
}
}
conn = talloc_zero(bsc->nat, struct sccp_connections);
if (!conn) {
LOGP(DNAT, LOGL_ERROR, "Memory allocation failure.\n");
@@ -92,6 +117,7 @@ int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc
}
conn->bsc = bsc;
clock_gettime(CLOCK_MONOTONIC, &conn->creation_time);
conn->real_ref = *parsed->src_local_ref;
if (assign_src_local_reference(&conn->patched_ref, bsc->nat) != 0) {
LOGP(DNAT, LOGL_ERROR, "Failed to assign a ref.\n");
@@ -99,7 +125,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 +145,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 +209,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

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

@@ -480,6 +480,8 @@ static int config_write_net(struct vty *vty)
vty_out(vty, " bsc_token %s%s", gsmnet->bsc_token, VTY_NEWLINE);
vty_out(vty, " msc ip %s%s", gsmnet->msc_ip, VTY_NEWLINE);
vty_out(vty, " msc port %d%s", gsmnet->msc_port, VTY_NEWLINE);
vty_out(vty, " timeout ping %d%s", gsmnet->ping_timeout, VTY_NEWLINE);
vty_out(vty, " timeout pong %d%s", gsmnet->pong_timeout, VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -1335,6 +1337,23 @@ DEFUN(cfg_net_msc_port,
return CMD_SUCCESS;
}
DEFUN(cfg_net_ping_time,
cfg_net_ping_time_cmd,
"timeout ping NR",
"Set the PING interval, negative for not sending PING")
{
gsmnet->ping_timeout = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_pong_time,
cfg_net_pong_time_cmd,
"timeout pong NR",
"Set the time to wait for a PONG.")
{
gsmnet->pong_timeout = atoi(argv[0]);
return CMD_SUCCESS;
}
#define DECLARE_TIMER(number, doc) \
DEFUN(cfg_net_T##number, \
@@ -2070,6 +2089,8 @@ int bsc_vty_init(struct gsm_network *net)
install_element(GSMNET_NODE, &cfg_net_pag_any_tch_cmd);
install_element(GSMNET_NODE, &cfg_net_msc_ip_cmd);
install_element(GSMNET_NODE, &cfg_net_msc_port_cmd);
install_element(GSMNET_NODE, &cfg_net_ping_time_cmd);
install_element(GSMNET_NODE, &cfg_net_pong_time_cmd);
install_element(GSMNET_NODE, &cfg_bts_cmd);
install_node(&bts_node, config_write_bts);

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

@@ -13,5 +13,5 @@ bsc_nat_test_SOURCES = bsc_nat_test.c \
$(top_srcdir)/src/mgcp/mgcp_protocol.c \
$(top_srcdir)/src/mgcp/mgcp_network.c \
$(top_srcdir)/src/bssap.c
bsc_nat_test_LDADD = $(top_builddir)/src/libbsc.a $(top_builddir)/src/libsccp.a $(LIBOSMOCORE_LIBS)
bsc_nat_test_LDADD = $(top_builddir)/src/libbsc.a $(top_builddir)/src/libsccp.a $(LIBOSMOCORE_LIBS) -lrt

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