Compare commits

..

89 Commits

Author SHA1 Message Date
Holger Hans Peter Freyther
6d17dd1314 Increase the version. 2010-04-19 17:06:17 +08:00
Holger Hans Peter Freyther
7cb6867ea3 [vty] Count pending paging requests for the vty
Implement a method to count the number of pending paging requests
per bts and print it on the VTY. This helps to see how big the
backlog of requests is for a given BTS.
2010-04-19 16:20:28 +08:00
Holger Hans Peter Freyther
d8138c43a1 nat: Make sccp/bsc show connections more Cisco like...
Second attempt to use a syntax more comparable to 'Cisco',
I have never used such a system... let us see how this is
going.
2010-04-19 16:06:43 +08:00
Holger Hans Peter Freyther
46d9b94477 [vty] Allow to allocate TCH/H and TCH/F too for testing purposes. 2010-04-19 16:01:14 +08:00
Holger Hans Peter Freyther
4f705b9f99 [vty] Add a test command to allocate all SDCCH 2010-04-19 16:01:14 +08:00
Holger Hans Peter Freyther
c592e697ce [alloc] Assign a TCH for LU when all SDCCHs are occupied.
When the cell becomes visible we will be bombed with location
updating requests and to reduce the load on the network we should
assign as many channels for it as possible. During load peek it
is even more important than to have a spare voice channel and in
general the LU procedure is pretty fast.
2010-04-19 16:01:07 +08:00
Holger Hans Peter Freyther
ebb6b99c63 nat: Do not use 0/0 for mux/timeslot by default
0 is a valid timeslot and we should not use it... use
a negative value to be save.
2010-04-18 03:07:22 +08:00
Holger Hans Peter Freyther
e08253a3f7 nat: Clear the connection on a DLCX
We can forget about the timeslot/multiplex when getting
the DLCX. This way we make room for the next connection
that might need to reuse this address.
2010-04-18 03:05:27 +08:00
Holger Hans Peter Freyther
5e86095364 nat: Always initialize the out pointer...
Always initialize the pointer to a invalid value in case
we encounter a parsing error or such.
2010-04-18 02:41:20 +08:00
Holger Hans Peter Freyther
a7c144888d nat: Fix the test case by allocating a config.
For the statistics we do need to have an allocated config,
otherwise we will nicely crash.
2010-04-18 02:40:33 +08:00
Holger Hans Peter Freyther
7897c4446b nat: Return the SCCP Connection again...
We will reset the multiplex in a DLCX message and then
we can reset the multiplex as well...even if the MGCP
connection is staying open. or at least this is a theory.

The MSC likes to leave a connection open during CallControl
when hanging up early enough in the process.
2010-04-18 02:40:33 +08:00
Holger Hans Peter Freyther
ff9e09b2bc nat: Return the newest SCCP connection...
In case we have a stale SCCP connection with an Endpoint that
we want to reassign...use the newest (last) occurence of that
as it is most likely the one we want to handle.
2010-04-18 02:40:32 +08:00
Holger Hans Peter Freyther
ecf5cc294d bsc_msc_ip: Print a small status on active connections
This needs to be improved to print TS of the lchan, when
the connection was created, when we received the last IT.
2010-04-18 02:40:32 +08:00
Holger Hans Peter Freyther
82126763a7 nat: Increase the right counter on calls. 2010-04-18 02:40:31 +08:00
Holger Hans Peter Freyther
a380c89a9c nat: Add new connections to the end of the list
By adding them to the end the VTY interface will only append
connections and not change the order on each invocation.
2010-04-18 02:40:31 +08:00
Holger Hans Peter Freyther
bedaf5da64 bssap: Move parsing of paging into the paging section... 2010-04-18 02:40:30 +08:00
Holger Freyther
2b08aa35a6 nat: Remove the SHOW_STR from none show commands. 2010-04-18 02:40:30 +08:00
Holger Hans Peter Freyther
c24632930a bsc_msc_ip: Allow to put the MSC address into the network config 2010-04-17 09:07:24 +02:00
Holger Hans Peter Freyther
f140348eff nat: Print the LAC that was searched for and not found. 2010-04-17 08:07:19 +02:00
Holger Hans Peter Freyther
b5de1b0781 nat: Mention when we do not find a BSC for a given token.
This might help to identify what is wrong with the config
of the BSC. Also using the result of TLVP_VAL as a char
pointer looks suspicious...
2010-04-17 08:07:03 +02:00
Holger Hans Peter Freyther
b022cc3b8e nat: Print the IP address of the BSC that does not respond to the query. 2010-04-17 07:58:17 +02:00
Holger Hans Peter Freyther
e8396c9663 nat: Make the MSC configurable. 2010-04-17 07:48:45 +02:00
Holger Hans Peter Freyther
941839b300 nat: Move MSC ip address into the config..
The address can still be specified on the cli and it will
overwrite the config in the config file.
2010-04-17 07:31:08 +02:00
Holger Hans Peter Freyther
23a0e46f11 Add rf_locked to the configuration writing. 2010-04-17 07:31:08 +02:00
Holger Hans Peter Freyther
cb8fd6e99e Use osmocore tlv definition for GSM0808. 2010-04-17 07:31:03 +02:00
Holger Hans Peter Freyther
e66bea8ad7 [mgcp] Fix vty file generation for the BSC nat and other cases
The current setting was not properly written out, this commit is
fixing it. This includes indention, empty bts ip, wrong command
for endpoints and the wrong number (+1 as zero is allocated but
unused).
2010-04-16 16:59:48 +02:00
Holger Hans Peter Freyther
e8a9f471ef nat: Two fixes for the write memory case...
Add new BSCs to the tail so we keep the sort order when writing
them out to the vty, fix the LAC command.
2010-04-16 16:52:20 +02:00
Holger Hans Peter Freyther
c2d66bdf5a Increase the version 2010-04-14 11:28:55 +02:00
Holger Hans Peter Freyther
80b584bbe7 [bsc_msc_ip] Implement a simple RF lock command interface
Right now this is using unix domain sockets and it only
supports query, on and off as commands. In the future we
want to have a vty<->snmp bridge or at least more status
exposed via snmp.
2010-04-14 11:19:07 +02:00
Holger Hans Peter Freyther
15c21e8eec bsc_msc_ip.c: Create the GSM network earlier, send the reset on each connection
Create the GSM network at the end of the init, send the
GSM reset on each reconnection and close a small window
when we would send a SCCP msg before being authenticated.

For that we have introduced an authenticated into the bsc_msc
struct and will manage it inside the bsc_msc_ip.c
2010-04-14 08:49:15 +02:00
Holger Hans Peter Freyther
c0a1fff064 bsc_msc_ip.c: Set the signal handler earlier..
We should set this before starting any network operation.
2010-04-14 08:46:29 +02:00
Holger Hans Peter Freyther
77fa4d2386 bsc_msc_ip.c: Fix the source comment...
This file is the bsc_msc_ip process to communicate with a MSC
and to implement the GSM 08.08 spec.
2010-04-14 08:34:24 +02:00
Holger Hans Peter Freyther
9be8752541 [bsc_msc_ip] Fix the name of the process. 2010-04-13 11:28:13 +02:00
Holger Hans Peter Freyther
2b57b3cea4 [bsc_msc_ip] Remove the possible dangerous -P option for the BSC
We always want to handle the CRCX the way we want to without
allocating a BSC proxy process. The default value of 1 is fine
for the bsc_msc_ip and we should not allow to set it.
2010-04-13 11:27:17 +02:00
Holger Hans Peter Freyther
00c531709a nat: Add config option to filter/handle certain imsi'es. 2010-04-13 09:50:38 +02:00
Holger Hans Peter Freyther
a094108f84 [statistics] Count the times we lost the connection to the MSC. 2010-04-13 09:47:22 +02:00
Holger Hans Peter Freyther
61e73eec3f [nat] Add show statistics to the nat 2010-04-13 09:47:22 +02:00
Holger Hans Peter Freyther
1aa2798919 [statistics] Provide basic statistics for the NAT
Count number of SCCP connections, number of BSC reconnects,
number of calls. For most of them we have a per BSC and a
global count.

Right now all structs using the counters survive until the
end of the application so we do not need to free them.
2010-04-13 09:47:22 +02:00
Holger Hans Peter Freyther
b829eac9bc [statistics] Keep track of OML/RSL failures of the BTS. 2010-04-13 09:47:22 +02:00
Holger Hans Peter Freyther
7b1719327d [statistics] Keep track of rf failures and rll release failures
Add two new counters to count the RF Failures and the RLL Release
failure and make them available via the vty interface.
2010-04-13 09:47:22 +02:00
Holger Hans Peter Freyther
493645eda9 bsc_msc_ip: Install BSC specific show statistics command. 2010-04-13 09:47:21 +02:00
Holger Hans Peter Freyther
8614cd0be7 [mgcp] Only write audio_name/payload when it is actually set. 2010-04-13 09:47:21 +02:00
Holger Hans Peter Freyther
19bd74d093 [vty] Separate BSC and MSC statistics. Make it easy to print them.
Move the statistics command into the MSC part and move the
BSC statistics printing into a subroutine.
2010-04-13 09:27:13 +02:00
Holger Hans Peter Freyther
4821b5a847 [nat] Change the command strings
Put the Target/Object first... Apparently this is more what people
that know IOS expect to do.
2010-04-12 07:29:22 +02:00
Holger Hans Peter Freyther
84df56d577 Increase version.. 2010-04-11 19:41:32 +02:00
Holger Hans Peter Freyther
4e23d5f87f [bsc_init] When the RSL/OML connection drops, free all lchan
Free all allocated channels on the TRX that failed, go through
lchan_free to signal higher layers and then force a reset of
the channel. Make the TRX and TS unusable by setting the operational
set to 0 (not really defined).
2010-04-11 19:34:43 +02:00
Holger Hans Peter Freyther
4346424987 [ipa] Fix the reporting of link down...
Now bsc_init.c is able to handle the link down messages.
2010-04-11 18:54:58 +02:00
Holger Hans Peter Freyther
520656e004 [ipa] Handle losing the RSL/OML connection..
This is addressing multiple issues regarding the loss of the
OML/RSL link to the BTS.

1.) When we lose the OML link, close down all RSL connections
on all TRXs (only tested with one TRX) and free the e1inp_line
allocated for the OML connection.
2.) When we lose the RSL link on any TRX and we know to which
lines this connection belongs, we will close down the OML connection
as we have a problem to just reactivate the RSL link.
3.) When we lose the RSL link on any TRX and we do not know
where it belongs to we will free the bfd we have allocated in the
rsl listen/accept method and we properly close the socket (i could
not test this one properly).
4.) When we already have a bts->oml_link we will throw it away
and use the new link.
2010-04-11 18:49:03 +02:00
Holger Hans Peter Freyther
9dac231fe4 e1_input: Stop the timer when deleting the signalling link on the TS
Stop the tx_timer when deleting the link on top of that ts. Otherwise
bad things might happen. E.g. when scheduling a write on OML and then
the OML link vanishes...

This is a slight layering violation as there could be more than
one signalling link on the timeslow (at least in theory) so the
queue and the timer should move to the e1inp_sign_link.
2010-04-11 17:18:02 +02:00
Holger Hans Peter Freyther
2bb518a3bd [e1_input] When destroying a link clear all pending messages 2010-04-11 14:13:10 +02:00
Holger Hans Peter Freyther
476940f747 [vty] First set of fixes for the oml/rsl con dropping
The code had wrong documentation in the VTY, it crashed
when OML or RSL was not up yet. These issues are fixed
right now.
2010-04-11 12:46:45 +02:00
Holger Hans Peter Freyther
8deab8cdee Bump the version.. 2010-04-11 11:36:37 +02:00
Holger Hans Peter Freyther
a54f9e81c8 Revert "ipa: Reduce the throttling of the IPA msges"
Reducing the throttling to this value created a regression with
bringing up RSL on the nanoBTS 900. We do seem to have a bug/issue
in the bsc_init code and might send a command too early without this
longer wait period and then the state transition does not happen.

For now it is agreed that reverting is the best thing to do.

Debugged-by: Sylvain Munaut <246tnt@gmail.com>

This reverts commit f5284ae1cf.
2010-04-11 10:14:39 +02:00
Holger Hans Peter Freyther
ed4390747f bsc_msc_ip.c: Do not directly write but use the write queue..
Use the write queue to write data to the MSC instead of
using a direct write.
2010-04-11 10:08:42 +02:00
Holger Hans Peter Freyther
242d098d32 nat: Update the nat configuration 2010-04-11 10:06:23 +02:00
Holger Hans Peter Freyther
f795164f04 [paging] Start with a smaller paging limit...
The value 20 is just a random number and it really depends
on the number of TRX on a bts to be a sane or insane limit.
2010-04-09 23:20:11 +02:00
Holger Hans Peter Freyther
b6c6d43daa [paging] Move code to use LOGP and print some more information 2010-04-09 23:20:11 +02:00
Holger Hans Peter Freyther
82df124c8e [paging] Simplify the last request and treat llist as a queue
The current code was overly complex. It tried to iterate over
the list in a round robin and we had to keep track of the last
element, see if we remove that one, check if the list becomes
empty... This can all replaced by treating the double linked
list as a queue. We take the item at the front, do something
on it and then and then put it back to the list at the end.
2010-04-09 23:20:04 +02:00
Holger Hans Peter Freyther
189587f428 paging: Fix format compiler warning... 2010-04-09 21:31:16 +02:00
Holger Hans Peter Freyther
45ab581f37 [mgcp] Improve the endpoint display on the vty..
Make sure one understands the two values for number of
incoming packets..
2010-04-09 18:53:24 +02:00
Holger Hans Peter Freyther
f48776ea6a [mgcp] Print the IP addr of the BTS we have detected. 2010-04-09 18:53:01 +02:00
Holger Hans Peter Freyther
7fc17cff64 nat: Set a dummy bts_ip to avoid misdetection of the bts...
It was possible that the nat detected the core network
gateway as the bts just due being the first to send data
to the port. Fix it by setting a dummy bts_ip to force
the mgcp_network code to compare the in_addr.
2010-04-09 18:51:01 +02:00
Holger Hans Peter Freyther
a5a7075fe5 paging: Avoid integer underflow on ipaccess
On the nanoBTS we do not receive any load indication for the
paging channel and we just decrement our available slots and
the unsigned int wraps to the maximum value. Together with a
not yet understood bug this makes us go amock.

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

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

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

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

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

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

This code is untested.
2010-04-08 10:24:57 +02:00
38 changed files with 1461 additions and 337 deletions

View File

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

View File

@@ -6,7 +6,7 @@ noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \
bsc_rll.h mncc.h transaction.h ussd.h gsm_04_80.h \
silent_call.h mgcp.h meas_rep.h rest_octets.h \
system_information.h handover.h mgcp_internal.h \
vty.h bssap.h bsc_msc.h bsc_nat.h
vty.h bssap.h bsc_msc.h bsc_nat.h bsc_msc_rf.h
openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h
openbscdir = $(includedir)/openbsc

View File

@@ -70,10 +70,12 @@ u_int64_t str_to_imsi(const char *imsi_str);
u_int8_t lchan2chan_nr(const struct gsm_lchan *lchan);
int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id, u_int8_t release_reason);
int rsl_lchan_set_state(struct gsm_lchan *lchan, int);
/* to be provided by external code */
int abis_rsl_sendmsg(struct msgb *msg);
int rsl_deact_sacch(struct gsm_lchan *lchan);
int rsl_chan_release(struct gsm_lchan *lchan);
int rsl_lchan_rll_release(struct gsm_lchan *lchan, u_int8_t link_id);
/* BCCH related code */
int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf);

View File

@@ -29,6 +29,7 @@
struct bsc_msc_connection {
struct write_queue write_queue;
int is_connected;
int is_authenticated;
const char *ip;
int port;

View File

@@ -0,0 +1,20 @@
#ifndef BSC_MSC_RF
#define BSC_MSC_RF
#include <osmocore/write_queue.h>
struct gsm_network;
struct bsc_msc_rf {
struct bsc_fd listen;
struct gsm_network *gsm_network;
};
struct bsc_msc_rf_conn {
struct write_queue queue;
struct gsm_network *gsm_network;
};
struct bsc_msc_rf *bsc_msc_rf_create(const char *path, struct gsm_network *net);
#endif

View File

@@ -31,6 +31,9 @@
#include <osmocore/msgb.h>
#include <osmocore/timer.h>
#include <osmocore/write_queue.h>
#include <osmocore/statistics.h>
#include <regex.h>
#define DIR_BSC 1
#define DIR_MSC 2
@@ -113,6 +116,20 @@ struct sccp_connections {
int bsc_timeslot;
};
/**
* Stats per BSC
*/
struct bsc_config_stats {
struct {
struct counter *conn;
struct counter *calls;
} sccp;
struct {
struct counter *reconn;
} net;
};
/**
* One BSC entry in the config
*/
@@ -123,7 +140,16 @@ struct bsc_config {
unsigned int lac;
int nr;
/* imsi white and blacklist */
char *imsi_allow;
regex_t imsi_allow_re;
char *imsi_deny;
regex_t imsi_deny_re;
/* backpointer */
struct bsc_nat *nat;
struct bsc_config_stats stats;
};
/**
@@ -138,6 +164,25 @@ struct bsc_endpoint {
int pending_delete;
};
/**
* Statistic for the nat.
*/
struct bsc_nat_statistics {
struct {
struct counter *conn;
struct counter *calls;
} sccp;
struct {
struct counter *reconn;
struct counter *auth_fail;
} bsc;
struct {
struct counter *reconn;
} msc;
};
/**
* the structure of the "nat" network
*/
@@ -159,9 +204,20 @@ struct bsc_nat {
int mgcp_length;
/* msc things */
char *msc_ip;
int msc_port;
int first_contact;
struct bsc_endpoint *bsc_endpoints;
/* filter */
char *imsi_allow;
regex_t imsi_allow_re;
char *imsi_deny;
regex_t imsi_deny_re;
/* statistics */
struct bsc_nat_statistics stats;
};
/* create and init the structures */
@@ -169,6 +225,7 @@ struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token, unsi
struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num);
struct bsc_nat *bsc_nat_alloc(void);
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 *);
@@ -182,7 +239,7 @@ struct bsc_nat_parsed *bsc_nat_parse(struct msgb *msg);
*/
int bsc_nat_filter_ipa(int direction, struct msgb *msg, struct bsc_nat_parsed *parsed);
int bsc_nat_vty_init(struct bsc_nat *nat);
struct bsc_connection *bsc_nat_find_bsc(struct bsc_nat *nat, struct msgb *msg);
struct bsc_connection *bsc_nat_find_bsc(struct bsc_nat *nat, struct msgb *msg, int *_lac);
/**
* SCCP patching and handling
@@ -196,7 +253,6 @@ struct sccp_connections *patch_sccp_src_ref_to_msc(struct msgb *, struct bsc_nat
/**
* MGCP/Audio handling
*/
int bsc_write_mgcp_msg(struct bsc_connection *bsc, struct msgb *msg);
int bsc_write_mgcp(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length);
int bsc_mgcp_assign(struct sccp_connections *, struct msgb *msg);
void bsc_mgcp_clear(struct sccp_connections *);
@@ -204,7 +260,7 @@ void bsc_mgcp_free_endpoint(struct bsc_nat *nat, int);
void bsc_mgcp_free_endpoints(struct bsc_nat *nat);
int bsc_mgcp_init(struct bsc_nat *nat);
struct bsc_connection *bsc_mgcp_find_con(struct bsc_nat *, int endpoint_number);
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);
void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg);
@@ -212,4 +268,7 @@ void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc);
int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60]);
int bsc_mgcp_extract_ci(const char *resp);
int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int id);
#endif

View File

@@ -326,11 +326,8 @@ void bsc_queue_connection_write(struct sccp_connection *conn, struct msgb *msg);
void bsc_free_queued(struct sccp_connection *conn);
void bsc_send_queued(struct sccp_connection *conn);
void bts_queue_send(struct msgb *msg, int link_id);
void bts_send_queued(struct bss_sccp_connection_data*);
void bts_free_queued(struct bss_sccp_connection_data*);
void bts_unblock_queue(struct bss_sccp_connection_data*);
const struct tlv_definition *gsm0808_att_tlvdef();
#endif

View File

@@ -63,10 +63,11 @@ struct gsm_lchan *lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr)
struct gsm_lchan *lchan_for_subscr(struct gsm_subscriber *subscr);
/* Allocate a logical channel (SDCCH, TCH, ...) */
struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type);
struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type, int allow_bigger);
/* Free a logical channel (SDCCH, TCH, ...) */
void lchan_free(struct gsm_lchan *lchan);
void lchan_reset(struct gsm_lchan *lchan);
/* internal.. do not use */
int _lchan_release(struct gsm_lchan *lchan, u_int8_t release_reason);

View File

@@ -198,6 +198,7 @@ enum gsm_lchan_state {
LCHAN_S_ACT_REQ, /* channel activatin requested */
LCHAN_S_ACTIVE, /* channel is active and operational */
LCHAN_S_REL_REQ, /* channel release has been requested */
LCHAN_S_REL_ERR, /* channel is in an error state */
LCHAN_S_INACTIVE, /* channel is set inactive */
};
@@ -246,6 +247,8 @@ struct gsm_lchan {
} encr;
struct timer_list T3101;
struct timer_list T3111;
struct timer_list error_timer;
/* AMR bits */
struct gsm48_multi_rate_conf mr_conf;
@@ -278,6 +281,9 @@ struct gsm_lchan {
} abis_ip;
struct gsm_subscriber_connection conn;
/* release reason */
u_int8_t release_reason;
};
struct gsm_e1_subslot {
@@ -390,7 +396,6 @@ struct gsm_paging_request {
struct gsm_bts_paging_state {
/* pending requests */
struct llist_head pending_requests;
struct gsm_paging_request *last_request;
struct gsm_bts *bts;
struct timer_list work_timer;
@@ -557,6 +562,14 @@ struct gsmnet_stats {
struct counter *alerted; /* we alerted the other end */
struct counter *connected;/* how many calls were accepted */
} call;
struct {
struct counter *rf_fail;
struct counter *rll_err;
} chan;
struct {
struct counter *oml_fail;
struct counter *rsl_fail;
} bts;
};
enum gsm_auth_policy {
@@ -648,6 +661,8 @@ struct gsm_network {
/* a simple token for this network... */
char *bsc_token;
char *msc_ip;
int msc_port;
};
#define SMS_HDR_SIZE 128

View File

@@ -53,6 +53,8 @@ int ipaccess_send_id_req(int fd);
int ipaccess_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len);
int ipaccess_drop_oml(struct gsm_bts *bts);
int ipaccess_drop_rsl(struct gsm_bts_trx *trx);
/*
* Firmware specific header

View File

@@ -43,4 +43,7 @@ void paging_request_stop(struct gsm_bts *bts, struct gsm_subscriber *subscr,
/* update paging load */
void paging_update_buffer_space(struct gsm_bts *bts, u_int16_t);
/* pending paging requests */
unsigned int paging_pending_requests_nr(struct gsm_bts *bts);
#endif

View File

@@ -1,6 +1,10 @@
#ifndef OPENBSC_VTY_H
#define OPENBSC_VTY_H
struct gsm_network;
struct vty;
void openbsc_vty_add_cmds(void);
void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *);
#endif

View File

@@ -35,7 +35,7 @@ bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT)
bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c debug.c \
rs232.c bts_siemens_bs11.c
bsc_msc_ip_SOURCES = bssap.c bsc_msc_ip.c bsc_init.c vty_interface.c vty_interface_bsc.c \
bsc_msc.c
bsc_msc.c bsc_msc_rf.c
bsc_msc_ip_LDADD = libbsc.a libvty.a libsccp.a

View File

@@ -568,12 +568,33 @@ int rsl_deact_sacch(struct gsm_lchan *lchan)
return abis_rsl_sendmsg(msg);
}
static void error_timeout_cb(void *data)
{
struct gsm_lchan *lchan = data;
if (lchan->state != LCHAN_S_REL_ERR) {
LOGP(DRSL, LOGL_ERROR, "%s error timeout but not in error state: %d\n",
gsm_lchan_name(lchan), lchan->state);
return;
}
/* go back to the none state */
LOGP(DRSL, LOGL_NOTICE, "%s is back in operation.\n", gsm_lchan_name(lchan));
rsl_lchan_set_state(lchan, LCHAN_S_NONE);
}
/* Chapter 8.4.14 / 4.7: Tell BTS to release the radio channel */
int rsl_rf_chan_release(struct gsm_lchan *lchan)
static int rsl_rf_chan_release(struct gsm_lchan *lchan, int error)
{
struct abis_rsl_dchan_hdr *dh;
struct msgb *msg = rsl_msgb_alloc();
struct msgb *msg;
if (lchan->state == LCHAN_S_REL_ERR) {
LOGP(DRSL, LOGL_NOTICE, "%s is in error state not sending release.\n",
gsm_lchan_name(lchan));
return -1;
}
msg = rsl_msgb_alloc();
dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
init_dchan_hdr(dh, RSL_MT_RF_CHAN_REL);
dh->chan_nr = lchan2chan_nr(lchan);
@@ -581,7 +602,20 @@ int rsl_rf_chan_release(struct gsm_lchan *lchan)
msg->lchan = lchan;
msg->trx = lchan->ts->trx;
DEBUGP(DRSL, "%s RF Channel Release CMD\n", gsm_lchan_name(lchan));
DEBUGP(DRSL, "%s RF Channel Release CMD due error %d\n", gsm_lchan_name(lchan), error);
if (error) {
/*
* the nanoBTS sends RLL release indications after the channel release. This can
* be a problem when we have reassigned the channel to someone else and then can
* not figure out who used this channel.
*/
rsl_lchan_set_state(lchan, LCHAN_S_REL_ERR);
lchan->error_timer.data = lchan;
lchan->error_timer.cb = error_timeout_cb;
bsc_schedule_timer(&lchan->error_timer,
msg->trx->bts->network->T3111 + 2, 0);
}
/* BTS will respond by RF CHAN REL ACK */
return abis_rsl_sendmsg(msg);
@@ -728,7 +762,6 @@ int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id, u_int8_t reas
/* 0 is normal release, 1 is local end */
msgb_tv_put(msg, RSL_IE_RELEASE_MODE, reason);
lchan->state = LCHAN_S_REL_REQ;
/* FIXME: start some timer in case we don't receive a REL ACK ? */
msg->trx = lchan->ts->trx;
@@ -736,6 +769,12 @@ int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id, u_int8_t reas
return abis_rsl_sendmsg(msg);
}
int rsl_lchan_set_state(struct gsm_lchan *lchan, int state)
{
lchan->state = state;
return 0;
}
/* Chapter 8.4.2: Channel Activate Acknowledge */
static int rsl_rx_chan_act_ack(struct msgb *msg)
{
@@ -750,7 +789,7 @@ static int rsl_rx_chan_act_ack(struct msgb *msg)
LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK, but state %s\n",
gsm_lchan_name(msg->lchan),
gsm_lchans_name(msg->lchan->state));
msg->lchan->state = LCHAN_S_ACTIVE;
rsl_lchan_set_state(msg->lchan, LCHAN_S_ACTIVE);
dispatch_signal(SS_LCHAN, S_LCHAN_ACTIVATE_ACK, msg->lchan);
@@ -776,9 +815,9 @@ static int rsl_rx_chan_act_nack(struct msgb *msg)
print_rsl_cause(LOGL_ERROR, cause,
TLVP_LEN(&tp, RSL_IE_CAUSE));
if (*cause != RSL_ERR_RCH_ALR_ACTV_ALLOC)
msg->lchan->state = LCHAN_S_NONE;
rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
} else
msg->lchan->state = LCHAN_S_NONE;
rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
LOGPC(DRSL, LOGL_ERROR, "\n");
@@ -806,7 +845,8 @@ static int rsl_rx_conn_fail(struct msgb *msg)
LOGPC(DRSL, LOGL_NOTICE, "\n");
/* FIXME: only free it after channel release ACK */
return rsl_rf_chan_release(msg->lchan);
counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rf_fail);
return rsl_rf_chan_release(msg->lchan, 1);
}
static void print_meas_rep_uni(struct gsm_meas_rep_unidir *mru,
@@ -978,11 +1018,14 @@ static int abis_rsl_rx_dchan(struct msgb *msg)
break;
case RSL_MT_RF_CHAN_REL_ACK:
DEBUGP(DRSL, "%s RF CHANNEL RELEASE ACK\n", ts_name);
if (msg->lchan->state != LCHAN_S_REL_REQ)
if (msg->lchan->state != LCHAN_S_REL_REQ && msg->lchan->state != LCHAN_S_REL_ERR)
LOGP(DRSL, LOGL_NOTICE, "%s CHAN REL ACK but state %s\n",
gsm_lchan_name(msg->lchan),
gsm_lchans_name(msg->lchan->state));
msg->lchan->state = LCHAN_S_NONE;
bsc_del_timer(&msg->lchan->T3111);
/* we have an error timer pending to release that */
if (msg->lchan->state != LCHAN_S_REL_ERR)
rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
lchan_free(msg->lchan);
break;
case RSL_MT_MODE_MODIFY_ACK:
@@ -1074,7 +1117,15 @@ static void t3101_expired(void *data)
{
struct gsm_lchan *lchan = data;
rsl_rf_chan_release(lchan);
rsl_rf_chan_release(lchan, 1);
}
/* If T3111 expires, we will send the RF Channel Request */
static void t3111_expired(void *data)
{
struct gsm_lchan *lchan = data;
rsl_rf_chan_release(lchan, 0);
}
/* MS has requested a channel on the RACH */
@@ -1089,6 +1140,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
struct gsm_lchan *lchan;
u_int8_t rqd_ta;
int ret;
int is_lu;
u_int16_t arfcn;
u_int8_t ts_number, subch;
@@ -1111,8 +1163,14 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
counter_inc(bts->network->stats.chreq.total);
/*
* We want LOCATION UPDATES to succeed and will assign a TCH
* if we have no SDCCH available.
*/
is_lu = !!(chreq_reason == GSM_CHREQ_REASON_LOCATION_UPD);
/* check availability / allocate channel */
lchan = lchan_alloc(bts, lctype);
lchan = lchan_alloc(bts, lctype, is_lu);
if (!lchan) {
LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for %s 0x%x\n",
msg->lchan->ts->trx->bts->nr, gsm_lchant_name(lctype), rqd_ref->ra);
@@ -1125,7 +1183,7 @@ static int rsl_rx_chan_rqd(struct msgb *msg)
LOGP(DRSL, LOGL_NOTICE, "%s lchan_alloc() returned channel "
"in state %s\n", gsm_lchan_name(lchan),
gsm_lchans_name(lchan->state));
lchan->state = LCHAN_S_ACT_REQ;
rsl_lchan_set_state(lchan, LCHAN_S_ACT_REQ);
ts_number = lchan->ts->nr;
arfcn = lchan->ts->trx->arfcn;
@@ -1241,12 +1299,40 @@ static int rsl_rx_rll_err_ind(struct msgb *msg)
rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND);
if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED)
return rsl_rf_chan_release(msg->lchan);
if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED) {
counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rll_err);
return rsl_rf_chan_release(msg->lchan, 1);
}
return 0;
}
static void rsl_handle_release(struct gsm_lchan *lchan)
{
int sapi;
struct gsm_bts *bts;
/* maybe we have only brought down one RLL */
if (lchan->state != LCHAN_S_REL_REQ)
return;
for (sapi = 0; sapi < ARRAY_SIZE(lchan->sapis); ++sapi) {
if (lchan->sapis[sapi] == LCHAN_SAPI_UNUSED)
continue;
LOGP(DRSL, LOGL_NOTICE, "%s waiting for SAPI=%d to be released.\n",
gsm_lchan_name(lchan), sapi);
return;
}
/* wait a bit to send the RF Channel Release */
lchan->T3111.cb = t3111_expired;
lchan->T3111.data = lchan;
bts = lchan->ts->trx->bts;
bsc_schedule_timer(&lchan->T3111, bts->network->T3111, 0);
}
/* ESTABLISH INDICATION, LOCATION AREA UPDATE REQUEST
0x02, 0x06,
0x01, 0x20,
@@ -1298,20 +1384,16 @@ static int abis_rsl_rx_rll(struct msgb *msg)
msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_UNUSED;
rll_indication(msg->lchan, rllh->link_id,
BSC_RLLR_IND_REL_IND);
/* we can now releae the channel on the BTS/Abis side */
/* FIXME: officially we need to start T3111 and wait for
* some grace period */
rsl_rf_chan_release(msg->lchan);
rsl_handle_release(msg->lchan);
rsl_lchan_rll_release(msg->lchan, rllh->link_id);
break;
case RSL_MT_REL_CONF:
/* BTS informs us of having received UA from MS,
* in response to DISC that we've sent earlier */
DEBUGPC(DRLL, "RELEASE CONFIRMATION\n");
msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_UNUSED;
/* we can now releae the channel on the BTS/Abis side */
/* FIXME: officially we need to start T3111 and wait for
* some grace period */
rsl_rf_chan_release(msg->lchan);
rsl_handle_release(msg->lchan);
rsl_lchan_rll_release(msg->lchan, rllh->link_id);
break;
case RSL_MT_ERROR_IND:
rc = rsl_rx_rll_err_ind(msg);

View File

@@ -7,6 +7,7 @@ line vty
no login
!
nat
msc ip 10.0.0.23
bsc 0
token zecke
location_area_code 3
@@ -15,7 +16,7 @@ nat
location_area_code 4
mgcp
local ip 10.0.0.23
bts ip 0.0.0.0
! bts ip 0.0.0.0
bind ip 127.0.0.1
bind port 2427
bind early 1

View File

@@ -31,6 +31,7 @@
#include <openbsc/system_information.h>
#include <openbsc/paging.h>
#include <openbsc/signal.h>
#include <openbsc/chan_alloc.h>
#include <osmocore/talloc.h>
/* global pointer to the gsm network data structure */
@@ -901,6 +902,8 @@ static void bootstrap_rsl(struct gsm_bts_trx *trx)
void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
{
int ts_no, lchan_no;
switch (event) {
case EVT_E1_TEI_UP:
switch (type) {
@@ -915,8 +918,35 @@ void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
}
break;
case EVT_E1_TEI_DN:
LOGP(DMI, LOGL_NOTICE, "Lost some E1 TEI link\n");
/* FIXME: deal with TEI or L1 link loss */
LOGP(DMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", type, trx);
if (type == E1INP_SIGN_OML)
counter_inc(trx->bts->network->stats.bts.oml_fail);
else if (type == E1INP_SIGN_RSL)
counter_inc(trx->bts->network->stats.bts.rsl_fail);
/*
* free all allocated channels. change the nm_state so the
* trx and trx_ts becomes unusable and chan_alloc.c can not
* allocate from it.
*/
for (ts_no = 0; ts_no < ARRAY_SIZE(trx->ts); ++ts_no) {
struct gsm_bts_trx_ts *ts = &trx->ts[ts_no];
for (lchan_no = 0; lchan_no < ARRAY_SIZE(ts->lchan); ++lchan_no) {
if (ts->lchan[lchan_no].state != GSM_LCHAN_NONE)
lchan_free(&ts->lchan[lchan_no]);
lchan_reset(&ts->lchan[lchan_no]);
}
ts->nm_state.operational = 0;
ts->nm_state.availability = 0;
}
trx->nm_state.operational = 0;
trx->nm_state.availability = 0;
trx->bb_transc.nm_state.operational = 0;
trx->bb_transc.nm_state.availability = 0;
break;
default:
break;

View File

@@ -49,6 +49,20 @@ static void connection_loss(struct bsc_msc_connection *con)
con->connection_loss(con);
}
static int bsc_msc_except(struct bsc_fd *bfd)
{
struct write_queue *wrt;
struct bsc_msc_connection *con;
LOGP(DMSC, LOGL_ERROR, "Exception on the BFD. Closing down.\n");
wrt = container_of(bfd, struct write_queue, bfd);
con = container_of(wrt, struct bsc_msc_connection, write_queue);
connection_loss(con);
return 0;
}
/* called in the case of a non blocking connect */
static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
{
@@ -81,7 +95,7 @@ static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
/* go to full operation */
fd->cb = write_queue_bfd_cb;
fd->when = BSC_FD_READ;
fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
con->is_connected = 1;
LOGP(DMSC, LOGL_NOTICE, "(Re)Connected to the MSC.\n");
@@ -156,7 +170,7 @@ int bsc_msc_connect(struct bsc_msc_connection *con)
connection_loss(con);
return ret;
} else {
fd->when = BSC_FD_READ;
fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
fd->cb = write_queue_bfd_cb;
con->is_connected = 1;
if (con->connected)
@@ -187,6 +201,7 @@ struct bsc_msc_connection *bsc_msc_create(const char *ip, int port)
con->ip = ip;
con->port = port;
write_queue_init(&con->write_queue, 100);
con->write_queue.except_cb = bsc_msc_except;
return con;
}

View File

@@ -1,4 +1,4 @@
/* A hackish minimal BSC (+MSC +HLR) implementation */
/* The BSC Process to handle GSM08.08 (A-Interface) */
/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
@@ -44,6 +44,7 @@
#include <openbsc/chan_alloc.h>
#include <openbsc/bsc_msc.h>
#include <openbsc/bsc_nat.h>
#include <openbsc/bsc_msc_rf.h>
#include <osmocore/select.h>
#include <osmocore/talloc.h>
@@ -58,16 +59,23 @@
static struct log_target *stderr_target;
struct gsm_network *bsc_gsmnet = 0;
static const char *config_file = "openbsc.cfg";
static char *msc_address = "127.0.0.1";
static char *msc_address = NULL;
static struct bsc_msc_connection *msc_con;
static struct in_addr local_addr;
static LLIST_HEAD(active_connections);
static struct write_queue mgcp_agent;
static const char *rf_ctl = NULL;
extern int ipacc_rtp_direct;
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);
struct llist_head *bsc_sccp_connections()
{
return &active_connections;
}
struct bss_sccp_connection_data *bss_sccp_create_data()
{
struct bss_sccp_connection_data *data;
@@ -114,7 +122,7 @@ struct gsm_subscriber *find_subscriber(u_int8_t type, const char *mi_string)
if (type == GSM_MI_TYPE_TMSI) {
tmsi = tmsi_from_string(mi_string);
if (tmsi == GSM_RESERVED_TMSI) {
DEBUGP(DMSC, "The TMSI is the reserved one.\n");
LOGP(DMSC, LOGL_ERROR, "The TMSI is the reserved one.\n");
return NULL;
}
}
@@ -127,7 +135,7 @@ struct gsm_subscriber *find_subscriber(u_int8_t type, const char *mi_string)
}
}
DEBUGP(DMSC, "No subscriber has been found.\n");
LOGP(DMSC, LOGL_ERROR, "No subscriber has been found.\n");
return NULL;
}
@@ -136,35 +144,49 @@ struct gsm_subscriber *find_subscriber(u_int8_t type, const char *mi_string)
/* SCCP handling */
void msc_outgoing_sccp_data(struct sccp_connection *conn, struct msgb *msg, unsigned int len)
{
struct gsm_lchan *lchan;
struct bssmap_header *bs;
if (len < 1) {
DEBUGP(DMSC, "The header is too short.\n");
LOGP(DMSC, LOGL_ERROR, "The header is too short.\n");
return;
}
lchan = sccp_get_lchan(conn->data_ctx);
if (!lchan) {
LOGP(DMSC, LOGL_ERROR, "SCCP data without lchan for type: 0x%x\n", msg->l3h[0]);
return;
}
/* that is bad */
if (!lchan->msc_data) {
LOGP(DMSC, LOGL_ERROR, "SCCP data for lchan without msc data type: 0x%x\n",
msg->l3h[0]);
return;
}
switch (msg->l3h[0]) {
case BSSAP_MSG_BSS_MANAGEMENT:
msg->l4h = &msg->l3h[sizeof(*bs)];
msg->lchan = sccp_get_lchan(conn->data_ctx);
msg->lchan = lchan;
bssmap_rcvmsg_dt1(conn, msg, len - sizeof(*bs));
break;
case BSSAP_MSG_DTAP:
dtap_rcvmsg(sccp_get_lchan(conn->data_ctx), msg, len);
dtap_rcvmsg(lchan, msg, len);
break;
default:
DEBUGPC(DMSC, "Unimplemented msg type: %d\n", msg->l3h[0]);
LOGP(DMSC, LOGL_DEBUG, "Unimplemented msg type: %d\n", msg->l3h[0]);
}
}
void msc_outgoing_sccp_state(struct sccp_connection *conn, int old_state)
{
if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) {
DEBUGP(DMSC, "Freeing sccp conn: %p state: %d\n", conn, conn->connection_state);
LOGP(DMSC, LOGL_DEBUG, "Freeing sccp conn: %p state: %d\n", conn, conn->connection_state);
if (sccp_get_lchan(conn->data_ctx) != NULL) {
struct gsm_lchan *lchan = sccp_get_lchan(conn->data_ctx);
DEBUGP(DMSC, "ERROR: The lchan is still associated\n.");
LOGP(DMSC, LOGL_ERROR, "ERROR: The lchan is still associated\n.");
lchan->msc_data = NULL;
put_subscr_con(&lchan->conn, 0);
@@ -176,7 +198,7 @@ void msc_outgoing_sccp_state(struct sccp_connection *conn, int old_state)
} else if (conn->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED) {
struct bss_sccp_connection_data *con_data;
DEBUGP(DMSC, "Connection established: %p\n", conn);
LOGP(DMSC, LOGL_DEBUG, "Connection established: %p\n", conn);
/* start the inactivity test timer */
con_data = (struct bss_sccp_connection_data *) conn->data_ctx;
@@ -203,30 +225,30 @@ 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_connected) {
if (!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);
return -1;
}
DEBUGP(DMSC, "Opening new layer3 connection\n");
LOGP(DMSC, LOGL_DEBUG, "Opening new layer3 connection\n");
sccp_connection = sccp_connection_socket();
if (!sccp_connection) {
DEBUGP(DMSC, "Failed to allocate memory.\n");
LOGP(DMSC, LOGL_ERROR, "Failed to allocate memory.\n");
return -ENOMEM;
}
data = bssmap_create_layer3(layer3);
if (!data) {
DEBUGP(DMSC, "Failed to allocate complete layer3.\n");
LOGP(DMSC, LOGL_ERROR, "Failed to allocate complete layer3.\n");
sccp_connection_free(sccp_connection);
return -ENOMEM;
}
con_data = bss_sccp_create_data();
if (!con_data) {
DEBUGP(DMSC, "Failed to allocate bss<->msc data.\n");
LOGP(DMSC, LOGL_ERROR, "Failed to allocate bss<->msc data.\n");
sccp_connection_free(sccp_connection);
msgb_free(data);
return -ENOMEM;
@@ -255,7 +277,7 @@ static int send_dtap_or_open_connection(struct msgb *msg)
if (msg->lchan->msc_data) {
struct msgb *dtap = dtap_create_msg(msg, 0);
if (!dtap) {
DEBUGP(DMSC, "Creating a DTAP message failed.\n");
LOGP(DMSC, LOGL_ERROR, "Creating a DTAP message failed.\n");
return -1;
}
@@ -274,7 +296,7 @@ static int handle_paging_response(struct msgb *msg)
u_int8_t mi_type;
gsm48_paging_extract_mi(msg, mi_string, &mi_type);
DEBUGP(DMSC, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
LOGP(DMSC, LOGL_DEBUG, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
mi_type, mi_string);
subscr = find_subscriber(mi_type, mi_string);
@@ -284,7 +306,7 @@ static int handle_paging_response(struct msgb *msg)
/* force the paging to stop at every bts */
subscr->lac = GSM_LAC_RESERVED_ALL_BTS;
if (gsm48_handle_paging_resp(msg, subscr) != 0) {
DEBUGP(DMSC, "Paging failed.\n");
LOGP(DMSC, LOGL_ERROR, "Paging failed.\n");
return -1;
}
@@ -302,10 +324,10 @@ static int handle_cipher_m_complete(struct msgb *msg)
return -1;
}
DEBUGP(DMSC, "CIPHER MODE COMPLETE from MS, forwarding to MSC\n");
LOGP(DMSC, LOGL_DEBUG, "CIPHER MODE COMPLETE from MS, forwarding to MSC\n");
resp = bssmap_create_cipher_complete(msg);
if (!resp) {
DEBUGP(DMSC, "Creating MSC response failed.\n");
LOGP(DMSC, LOGL_ERROR, "Creating MSC response failed.\n");
return -1;
}
@@ -322,7 +344,7 @@ static int handle_ass_compl(struct msgb *msg)
struct gsm_lchan *old_chan;
struct gsm48_hdr *gh = msgb_l3(msg);
DEBUGP(DMSC, "ASSIGNMENT COMPLETE from MS, forwarding to MSC\n");
LOGP(DMSC, LOGL_DEBUG, "ASSIGNMENT COMPLETE from MS, forwarding to MSC\n");
if (!msg->lchan->msc_data) {
LOGP(DMSC, LOGL_ERROR, "No MSC data\n");
@@ -331,13 +353,13 @@ static int handle_ass_compl(struct msgb *msg)
}
if (msg->lchan->msc_data->secondary_lchan != msg->lchan) {
LOGP(DMSC, LOGL_NOTICE, "Wrong assignment complete.\n");
LOGP(DMSC, LOGL_ERROR, "Wrong assignment complete.\n");
put_subscr_con(&msg->lchan->conn, 0);
return -1;
}
if (msgb_l3len(msg) - sizeof(*gh) != 1) {
DEBUGP(DMSC, "assignment failure invalid: %d\n",
LOGP(DMSC, LOGL_ERROR, "assignment compl invalid: %d\n",
msgb_l3len(msg) - sizeof(*gh));
put_subscr_con(&msg->lchan->conn, 0);
return -1;
@@ -368,30 +390,36 @@ static int handle_ass_compl(struct msgb *msg)
*/
static int handle_ass_fail(struct msgb *msg)
{
u_int8_t *rr_cause;
struct gsm48_hdr *gh = msgb_l3(msg);
DEBUGP(DMSC, "ASSIGNMENT FAILURE from MS, forwarding to MSC\n");
LOGP(DMSC, LOGL_ERROR, "ASSIGNMENT FAILURE from MS, forwarding to MSC\n");
if (!msg->lchan->msc_data) {
LOGP(DMSC, LOGL_ERROR, "No MSC data\n");
put_subscr_con(&msg->lchan->conn, 0);
return -1;
}
if (msg->lchan->msc_data->secondary_lchan != msg->lchan) {
LOGP(DMSC, LOGL_NOTICE, "Wrong assignment complete.\n");
/* assignment failure comes on the old link */
if (msg->lchan->msc_data->lchan != msg->lchan) {
LOGP(DMSC, LOGL_NOTICE, "Failure should come on the old link.\n");
msg->lchan->msc_data = NULL;
put_subscr_con(&msg->lchan->conn, 0);
return -1;
}
/* Giving up the secondary will happen in bssap */
if (msgb_l3len(msg) - sizeof(*gh) != 1) {
DEBUGP(DMSC, "assignment failure invalid: %d\n",
LOGP(DMSC, LOGL_ERROR, "assignment failure invalid: %d\n",
msgb_l3len(msg) - sizeof(*gh));
put_subscr_con(&msg->lchan->conn, 0);
return -1;
rr_cause = NULL;
} else {
rr_cause = &gh->data[0];
}
/* this will also free the secondary channel */
gsm0808_send_assignment_failure(msg->lchan,
GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE, &gh->data[0]);
GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE, rr_cause);
return 1;
}
@@ -496,7 +524,7 @@ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
if (rc == 0 && msg->lchan->msc_data && lchan_get_sccp(msg->lchan)) {
struct msgb *dtap = dtap_create_msg(msg, link_id);
if (!dtap) {
DEBUGP(DMSC, "Creating a DTAP message failed.\n");
LOGP(DMSC, LOGL_ERROR, "Creating a DTAP message failed.\n");
return -1;
}
@@ -523,7 +551,7 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
case S_ABISIP_CRCX_ACK:
/* we can ask it to connect now */
if (lchan->msc_data) {
DEBUGP(DMSC, "Connecting BTS to port: %d conn: %d\n",
LOGP(DMSC, LOGL_DEBUG, "Connecting BTS to port: %d conn: %d\n",
lchan->msc_data->rtp_port, lchan->abis_ip.conn_id);
int rtp_payload = ts->trx->bts->network->rtp_payload;
@@ -534,7 +562,7 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
lchan->msc_data->rtp_port,
rtp_payload);
if (rc < 0) {
DEBUGP(DMSC, "Failed to send connect: %d\n", rc);
LOGP(DMSC, LOGL_ERROR, "Failed to send connect: %d\n", rc);
return rc;
}
}
@@ -548,7 +576,7 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
static void print_usage()
{
printf("Usage: bsc_hack\n");
printf("Usage: bsc_msc_ip\n");
}
/*
@@ -570,8 +598,8 @@ static int msc_sccp_do_write(struct bsc_fd *fd, struct msgb *msg)
{
int ret;
DEBUGP(DMSC, "Sending SCCP to MSC: %u\n", msgb_l2len(msg));
DEBUGP(DMI, "MSC TX %s\n", hexdump(msg->l2h, msgb_l2len(msg)));
LOGP(DMSC, LOGL_DEBUG, "Sending SCCP to MSC: %u\n", msgb_l2len(msg));
LOGP(DMI, LOGL_DEBUG, "MSC TX %s\n", hexdump(msg->l2h, msgb_l2len(msg)));
ret = write(msc_con->write_queue.bfd.fd, msg->data, msg->len);
if (ret < msg->len)
@@ -612,7 +640,7 @@ static int mgcp_do_read(struct bsc_fd *fd)
return -1;
}
ret = read(fd->fd, mgcp->data, mgcp->data_len);
ret = read(fd->fd, mgcp->data, 4096 - 128);
if (ret <= 0) {
LOGP(DMGCP, LOGL_ERROR, "Failed to read: %d/%s\n", errno, strerror(errno));
msgb_free(mgcp);
@@ -705,7 +733,7 @@ static int mgcp_create_port(void)
static int msc_sccp_accept(struct sccp_connection *connection, void *data)
{
DEBUGP(DMSC, "Rejecting incoming SCCP connection.\n");
LOGP(DMSC, LOGL_DEBUG, "Rejecting incoming SCCP connection.\n");
return -1;
}
@@ -713,10 +741,10 @@ static int msc_sccp_read(struct msgb *msgb, unsigned int length, void *data)
{
struct bssmap_header *bs;
DEBUGP(DMSC, "Incoming SCCP message ftom MSC: %s\n", hexdump(msgb->l3h, length));
LOGP(DMSC, LOGL_DEBUG, "Incoming SCCP message ftom MSC: %s\n", hexdump(msgb->l3h, length));
if (length < sizeof(*bs)) {
DEBUGP(DMSC, "The header is too short.\n");
LOGP(DMSC, LOGL_ERROR, "The header is too short.\n");
return -1;
}
@@ -730,7 +758,7 @@ static int msc_sccp_read(struct msgb *msgb, unsigned int length, void *data)
bssmap_rcvmsg_udt(bsc_gsmnet, msgb, length - sizeof(*bs));
break;
default:
DEBUGPC(DMSC, "Unimplemented msg type: %d\n", bs->type);
LOGP(DMSC, LOGL_ERROR, "Unimplemented msg type: %d\n", bs->type);
}
return 0;
@@ -742,27 +770,20 @@ static int msc_sccp_read(struct msgb *msgb, unsigned int length, void *data)
*/
static void initialize_if_needed(void)
{
if (!bsc_gsmnet) {
int rc;
struct msgb *msg;
fprintf(stderr, "Bootstraping the network. Sending GSM08.08 reset.\n");
rc = bsc_bootstrap_network(NULL, config_file);
if (rc < 0) {
fprintf(stderr, "Bootstrapping the network failed. exiting.\n");
exit(1);
}
struct msgb *msg;
if (!msc_con->is_authenticated) {
/* send a gsm 08.08 reset message from here */
msg = bssmap_create_reset();
if (!msg) {
DEBUGP(DMSC, "Failed to create the reset message.\n");
LOGP(DMSC, LOGL_ERROR, "Failed to create the reset message.\n");
return;
}
sccp_write(msg, &sccp_ssn_bssap, &sccp_ssn_bssap, 0);
msgb_free(msg);
msc_con->is_authenticated = 1;
}
}
@@ -784,13 +805,7 @@ static void send_id_get_response(int fd)
msg->l2h = msgb_v_put(msg, IPAC_MSGT_ID_RESP);
msgb_l16tv_put(msg, strlen(bsc_gsmnet->bsc_token) + 1,
IPAC_IDTAG_UNITNAME, (u_int8_t *) bsc_gsmnet->bsc_token);
ipaccess_prepend_header(msg, IPAC_PROTO_IPACCESS);
if (write(fd, msg->data, msg->len) != msg->len) {
LOGP(DMSC, LOGL_ERROR, "Short write.\n");
}
msgb_free(msg);
msc_queue_write(msg, IPAC_PROTO_IPACCESS);
}
/*
@@ -825,6 +840,7 @@ static void msc_connection_was_lost(struct bsc_msc_connection *msc)
bss_sccp_free_data(bss);
}
msc->is_authenticated = 0;
bsc_msc_schedule_connect(msc);
}
@@ -848,7 +864,7 @@ static int ipaccess_a_fd_cb(struct bsc_fd *bfd)
return -1;
}
DEBUGP(DMSC, "From MSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
LOGP(DMSC, LOGL_DEBUG, "From MSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
/* handle base message handling */
hh = (struct ipaccess_head *) msg->data;
@@ -877,10 +893,12 @@ static void print_help()
printf(" -h --help this text\n");
printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n");
printf(" -s --disable-color\n");
printf(" -T --timestamp. Print a timestamp in the debug output.\n");
printf(" -c --config-file filename The config file to use.\n");
printf(" -m --msc=IP. The address of the MSC.\n");
printf(" -l --local=IP. The local address of the MGCP.\n");
printf(" -e --log-level number. Set a global loglevel.\n");
printf(" -r --rf-ctl NAME. A unix domain socket to listen for cmds.\n");
}
static void handle_options(int argc, char** argv)
@@ -893,14 +911,14 @@ static void handle_options(int argc, char** argv)
{"config-file", 1, 0, 'c'},
{"disable-color", 0, 0, 's'},
{"timestamp", 0, 0, 'T'},
{"rtp-proxy", 0, 0, 'P'},
{"msc", 1, 0, 'm'},
{"local", 1, 0, 'l'},
{"log-level", 1, 0, 'e'},
{"rf-ctl", 1, 0, 'r'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, "hd:sTPc:m:l:e:",
c = getopt_long(argc, argv, "hd:sTc:m:l:e:r:",
long_options, &option_index);
if (c == -1)
break;
@@ -926,7 +944,7 @@ static void handle_options(int argc, char** argv)
ipacc_rtp_direct = 0;
break;
case 'm':
msc_address = strdup(optarg);
msc_address = optarg;
break;
case 'l':
inet_aton(optarg, &local_addr);
@@ -934,6 +952,9 @@ static void handle_options(int argc, char** argv)
case 'e':
log_set_log_level(stderr_target, atoi(optarg));
break;
case 'r':
rf_ctl = optarg;
break;
default:
/* ignore */
break;
@@ -947,8 +968,10 @@ static void signal_handler(int signal)
switch (signal) {
case SIGINT:
bsc_shutdown_net(bsc_gsmnet);
sleep(3);
if (bsc_gsmnet) {
bsc_shutdown_net(bsc_gsmnet);
sleep(3);
}
exit(0);
break;
case SIGABRT:
@@ -958,7 +981,7 @@ static void signal_handler(int signal)
talloc_report_full(tall_bsc_ctx, stderr);
break;
case SIGUSR2:
if (!msc_con->is_connected)
if (!msc_con || !msc_con->is_connected)
return;
bsc_msc_lost(msc_con);
break;
@@ -1013,6 +1036,9 @@ extern int bts_model_nanobts_init(void);
int main(int argc, char **argv)
{
char *msc;
int rc;
log_init(&log_info);
tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
stderr_target = log_target_create_stderr();
@@ -1031,6 +1057,12 @@ int main(int argc, char **argv)
/* seed the PRNG */
srand(time(NULL));
signal(SIGINT, &signal_handler);
signal(SIGABRT, &signal_handler);
signal(SIGUSR1, &signal_handler);
signal(SIGUSR2, &signal_handler);
signal(SIGPIPE, SIG_IGN);
/* attempt to register the local mgcp forward */
if (mgcp_create_port() != 0) {
fprintf(stderr, "Failed to bind local MGCP port\n");
@@ -1045,9 +1077,28 @@ int main(int argc, char **argv)
/* initialize ipaccess handling */
register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL);
fprintf(stderr, "Bootstraping the network. Sending GSM08.08 reset.\n");
rc = bsc_bootstrap_network(NULL, config_file);
if (rc < 0) {
fprintf(stderr, "Bootstrapping the network failed. exiting.\n");
exit(1);
}
if (rf_ctl) {
struct bsc_msc_rf *rf;
rf = bsc_msc_rf_create(rf_ctl, bsc_gsmnet);
if (!rf) {
fprintf(stderr, "Failed to create the RF service.\n");
exit(1);
}
}
/* setup MSC Connection handling */
msc_con = bsc_msc_create(msc_address, 5000);
msc = bsc_gsmnet->msc_ip;
if (msc_address)
msc = msc_address;
msc_con = bsc_msc_create(msc, bsc_gsmnet->msc_port);
if (!msc_con) {
fprintf(stderr, "Creating a bsc_msc_connection failed.\n");
exit(1);
@@ -1059,11 +1110,6 @@ int main(int argc, char **argv)
bsc_msc_connect(msc_con);
signal(SIGINT, &signal_handler);
signal(SIGABRT, &signal_handler);
signal(SIGUSR1, &signal_handler);
signal(SIGUSR2, &signal_handler);
signal(SIGPIPE, SIG_IGN);
while (1) {
bsc_select_main(0);

249
openbsc/src/bsc_msc_rf.c Normal file
View File

@@ -0,0 +1,249 @@
/* RF Ctl handling socket */
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <openbsc/bsc_msc_rf.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <osmocore/talloc.h>
#include <osmocore/protocol/gsm_12_21.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <unistd.h>
#define RF_CMD_QUERY '?'
#define RF_CMD_OFF '0'
#define RF_CMD_ON '1'
static int lock_each_trx(struct gsm_network *net, int lock)
{
struct gsm_bts *bts;
llist_for_each_entry(bts, &net->bts_list, list) {
struct gsm_bts_trx *trx;
llist_for_each_entry(trx, &bts->trx_list, list) {
gsm_trx_lock_rf(trx, lock);
}
}
return 0;
}
/*
* Send a '1' when one TRX is online, otherwise send 0
*/
static void handle_query(struct bsc_msc_rf_conn *conn)
{
struct msgb *msg;
struct gsm_bts *bts;
char send = '0';
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';
break;
}
}
}
msg = msgb_alloc(10, "RF Query");
if (!msg) {
LOGP(DINP, LOGL_ERROR, "Failed to allocate response msg.\n");
return;
}
msg->l2h = msgb_put(msg, 1);
msg->l2h[0] = send;
if (write_queue_enqueue(&conn->queue, msg) != 0) {
LOGP(DINP, LOGL_ERROR, "Failed to enqueue the answer.\n");
msgb_free(msg);
return;
}
return;
}
static int rf_read_cmd(struct bsc_fd *fd)
{
struct bsc_msc_rf_conn *conn = fd->data;
char buf[1];
int rc;
rc = read(fd->fd, buf, sizeof(buf));
if (rc != sizeof(buf)) {
LOGP(DINP, LOGL_ERROR, "Short read %d/%s\n", errno, strerror(errno));
bsc_unregister_fd(fd);
close(fd->fd);
write_queue_clear(&conn->queue);
talloc_free(conn);
return -1;
}
switch (buf[0]) {
case RF_CMD_QUERY:
handle_query(conn);
break;
case RF_CMD_OFF:
lock_each_trx(conn->gsm_network, 1);
break;
case RF_CMD_ON:
lock_each_trx(conn->gsm_network, 0);
break;
default:
LOGP(DINP, LOGL_ERROR, "Unknown command %d\n", buf[0]);
break;
}
return 0;
}
static int rf_write_cmd(struct bsc_fd *fd, struct msgb *msg)
{
int rc;
rc = write(fd->fd, msg->data, msg->len);
if (rc != msg->len) {
LOGP(DINP, LOGL_ERROR, "Short write %d/%s\n", errno, strerror(errno));
return -1;
}
return 0;
}
static int rf_ctl_accept(struct bsc_fd *bfd, unsigned int what)
{
struct bsc_msc_rf_conn *conn;
struct bsc_msc_rf *rf = bfd->data;
struct sockaddr_un addr;
socklen_t len = sizeof(addr);
int fd;
fd = accept(bfd->fd, (struct sockaddr *) &addr, &len);
if (fd < 0) {
LOGP(DINP, LOGL_ERROR, "Failed to accept. errno: %d/%s\n",
errno, strerror(errno));
return -1;
}
conn = talloc_zero(rf, struct bsc_msc_rf_conn);
if (!conn) {
LOGP(DINP, LOGL_ERROR, "Failed to allocate mem.\n");
close(fd);
return -1;
}
write_queue_init(&conn->queue, 10);
conn->queue.bfd.data = conn;
conn->queue.bfd.fd = fd;
conn->queue.bfd.when = BSC_FD_READ | BSC_FD_WRITE;
conn->queue.read_cb = rf_read_cmd;
conn->queue.write_cb = rf_write_cmd;
conn->gsm_network = rf->gsm_network;
if (bsc_register_fd(&conn->queue.bfd) != 0) {
close(fd);
talloc_free(conn);
return -1;
}
return 0;
}
struct bsc_msc_rf *bsc_msc_rf_create(const char *path, struct gsm_network *net)
{
unsigned int namelen;
struct sockaddr_un local;
struct bsc_fd *bfd;
struct bsc_msc_rf *rf;
int rc;
rf = talloc_zero(NULL, struct bsc_msc_rf);
if (!rf) {
LOGP(DINP, LOGL_ERROR, "Failed to create bsc_msc_rf.\n");
return NULL;
}
bfd = &rf->listen;
bfd->fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (bfd->fd < 0) {
LOGP(DINP, LOGL_ERROR, "Can not create socket. %d/%s\n",
errno, strerror(errno));
return NULL;
}
local.sun_family = AF_UNIX;
strncpy(local.sun_path, path, sizeof(local.sun_path));
local.sun_path[sizeof(local.sun_path) - 1] = '\0';
unlink(local.sun_path);
/* we use the same magic that X11 uses in Xtranssock.c for
* calculating the proper length of the sockaddr */
#if defined(BSD44SOCKETS) || defined(__UNIXWARE__)
local.sun_len = strlen(local.sun_path);
#endif
#if defined(BSD44SOCKETS) || defined(SUN_LEN)
namelen = SUN_LEN(&local);
#else
namelen = strlen(local.sun_path) +
offsetof(struct sockaddr_un, sun_path);
#endif
rc = bind(bfd->fd, (struct sockaddr *) &local, namelen);
if (rc != 0) {
LOGP(DINP, LOGL_ERROR, "Failed to bind '%s' errno: %d/%s\n",
local.sun_path, errno, strerror(errno));
close(bfd->fd);
talloc_free(rf);
return NULL;
}
if (listen(bfd->fd, 0) != 0) {
LOGP(DINP, LOGL_ERROR, "Failed to listen: %d/%s\n", errno, strerror(errno));
close(bfd->fd);
talloc_free(rf);
return NULL;
}
bfd->when = BSC_FD_READ;
bfd->cb = rf_ctl_accept;
bfd->data = rf;
if (bsc_register_fd(bfd) != 0) {
LOGP(DINP, LOGL_ERROR, "Failed to register bfd.\n");
close(bfd->fd);
talloc_free(rf);
return NULL;
}
rf->gsm_network = net;
return rf;
}

View File

@@ -29,7 +29,7 @@
#include <openbsc/paging.h>
#include <openbsc/chan_alloc.h>
#include <osmocore/tlv.h>
#include <osmocore/gsm0808.h>
#include <sccp/sccp.h>
@@ -40,34 +40,9 @@
#define BSSMAP_MSG_SIZE 512
#define BSSMAP_MSG_HEADROOM 128
static void bts_queue_send(struct msgb *msg, int link_id);
static void bssmap_free_secondary(struct bss_sccp_connection_data *data);
static const struct tlv_definition bss_att_tlvdef = {
.def = {
[GSM0808_IE_IMSI] = { TLV_TYPE_TLV },
[GSM0808_IE_TMSI] = { TLV_TYPE_TLV },
[GSM0808_IE_CELL_IDENTIFIER_LIST] = { TLV_TYPE_TLV },
[GSM0808_IE_CHANNEL_NEEDED] = { TLV_TYPE_TV },
[GSM0808_IE_EMLPP_PRIORITY] = { TLV_TYPE_TV },
[GSM0808_IE_CHANNEL_TYPE] = { TLV_TYPE_TLV },
[GSM0808_IE_PRIORITY] = { TLV_TYPE_TLV },
[GSM0808_IE_CIRCUIT_IDENTITY_CODE] = { TLV_TYPE_TV },
[GSM0808_IE_DOWNLINK_DTX_FLAG] = { TLV_TYPE_TV },
[GSM0808_IE_INTERFERENCE_BAND_TO_USE] = { TLV_TYPE_TV },
[GSM0808_IE_CLASSMARK_INFORMATION_T2] = { TLV_TYPE_TLV },
[GSM0808_IE_GROUP_CALL_REFERENCE] = { TLV_TYPE_TLV },
[GSM0808_IE_TALKER_FLAG] = { TLV_TYPE_T },
[GSM0808_IE_CONFIG_EVO_INDI] = { TLV_TYPE_TV },
[GSM0808_IE_LSA_ACCESS_CTRL_SUPPR] = { TLV_TYPE_TV },
[GSM0808_IE_SERVICE_HANDOVER] = { TLV_TYPE_TV},
[GSM0808_IE_ENCRYPTION_INFORMATION] = { TLV_TYPE_TLV },
[GSM0808_IE_CIPHER_RESPONSE_MODE] = { TLV_TYPE_TV },
},
};
const struct tlv_definition *gsm0808_att_tlvdef()
{
return &bss_att_tlvdef;
}
static u_int16_t get_network_code_for_msc(struct gsm_network *net)
{
@@ -85,7 +60,7 @@ static u_int16_t get_country_code_for_msc(struct gsm_network *net)
static int bssmap_paging_cb(unsigned int hooknum, unsigned int event, struct msgb *msg, void *data, void *param)
{
LOGP(DMSC, LOGL_DEBUG, "Paging is complete.\n");
LOGP(DPAG, LOGL_DEBUG, "Paging is complete.\n");
return 0;
}
@@ -109,7 +84,7 @@ static int bssmap_handle_paging(struct gsm_network *net, struct msgb *msg, unsig
u_int8_t chan_needed = RSL_CHANNEED_ANY;
int paged;
tlv_parse(&tp, &bss_att_tlvdef, msg->l4h + 1, payload_length - 1, 0, 0);
tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, payload_length - 1, 0, 0);
if (!TLVP_PRESENT(&tp, GSM0808_IE_IMSI)) {
LOGP(DMSC, LOGL_ERROR, "Mandantory IMSI not present.\n");
@@ -170,7 +145,7 @@ static int bssmap_handle_paging(struct gsm_network *net, struct msgb *msg, unsig
subscr->tmsi = tmsi;
subscr->lac = lac;
paged = paging_request(net, subscr, chan_needed, bssmap_paging_cb, subscr);
LOGP(DMSC, LOGL_DEBUG, "Paged IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x on #bts: %d\n", mi_string, tmsi, tmsi, lac, paged);
LOGP(DPAG, LOGL_DEBUG, "Paged IMSI: '%s' TMSI: '0x%x/%u' LAC: 0x%x on #bts: %d\n", mi_string, tmsi, tmsi, lac, paged);
subscr_put(subscr);
return -1;
@@ -190,8 +165,7 @@ static int bssmap_handle_clear_command(struct sccp_connection *conn,
msg->lchan->msc_data->lchan = NULL;
/* we might got killed during an assignment */
if (msg->lchan->msc_data->secondary_lchan)
put_subscr_con(&msg->lchan->msc_data->secondary_lchan->conn, 0);
bssmap_free_secondary(msg->lchan->msc_data);
msg->lchan->msc_data = NULL;
put_subscr_con(&msg->lchan->conn, 0);
@@ -240,7 +214,7 @@ static int bssmap_handle_cipher_mode(struct sccp_connection *conn,
msg->lchan->msc_data->ciphering_handled = 1;
msg->lchan->msc_data->block_gsm = 1;
tlv_parse(&tp, &bss_att_tlvdef, msg->l4h + 1, payload_length - 1, 0, 0);
tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, payload_length - 1, 0, 0);
if (!TLVP_PRESENT(&tp, GSM0808_IE_ENCRYPTION_INFORMATION)) {
LOGP(DMSC, LOGL_ERROR, "IE Encryption Information missing.\n");
goto reject;
@@ -292,15 +266,49 @@ reject:
return -1;
}
/*
* handle network failures... and free the secondary lchan
*/
static void bssmap_free_secondary(struct bss_sccp_connection_data *data)
{
struct gsm_lchan *lchan;
if (!data || !data->secondary_lchan)
return;
lchan = data->secondary_lchan;
if (lchan->msc_data != data) {
LOGP(DMSC, LOGL_ERROR, "MSC data does not match on lchan and cb.\n");
data->secondary_lchan = NULL;
}
/* give up additional data */
lchan->msc_data->secondary_lchan = NULL;
if (lchan->msc_data->lchan == lchan)
lchan->msc_data->lchan = NULL;
lchan->msc_data = NULL;
/* give up the new channel to not do a SACCH deactivate */
subscr_put(lchan->conn.subscr);
lchan->conn.subscr = NULL;
put_subscr_con(&lchan->conn, 1);
}
/*
* Handle the network configurable T10 parameter
*/
static void bssmap_t10_fired(void *_conn)
{
struct bss_sccp_connection_data *msc_data;
struct sccp_connection *conn = (struct sccp_connection *) _conn;
struct msgb *resp;
LOGP(DMSC, LOGL_ERROR, "T10 fired, assignment failed: %p\n", conn);
/* free the secondary channel if we have one */
msc_data = conn->data_ctx;
bssmap_free_secondary(msc_data);
resp = bssmap_create_assignment_failure(
GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
if (!resp) {
@@ -395,7 +403,7 @@ static int handle_new_assignment(struct msgb *msg, int full_rate, int chan_mode)
bts = msg->lchan->ts->trx->bts;
chan_type = full_rate ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H;
new_lchan = lchan_alloc(bts, chan_type);
new_lchan = lchan_alloc(bts, chan_type, 0);
if (!new_lchan) {
LOGP(DMSC, LOGL_NOTICE, "No free channel.\n");
@@ -426,6 +434,7 @@ static int handle_new_assignment(struct msgb *msg, int full_rate, int chan_mode)
return -1;
}
rsl_lchan_set_state(new_lchan, LCHAN_S_ACT_REQ);
msc_data->secondary_lchan = new_lchan;
new_lchan->msc_data = msc_data;
return 0;
@@ -444,6 +453,7 @@ static void continue_new_assignment(struct gsm_lchan *new_lchan)
if (new_lchan->msc_data->secondary_lchan != new_lchan) {
LOGP(DMSC, LOGL_ERROR, "This is not the secondary channel?\n");
new_lchan->msc_data = NULL;
put_subscr_con(&new_lchan->conn, 0);
return;
}
@@ -477,7 +487,7 @@ static int bssmap_handle_assignm_req(struct sccp_connection *conn,
msc_data = msg->lchan->msc_data;
network = msg->lchan->ts->trx->bts->network;
tlv_parse(&tp, &bss_att_tlvdef, msg->l4h + 1, length - 1, 0, 0);
tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, length - 1, 0, 0);
if (!TLVP_PRESENT(&tp, GSM0808_IE_CHANNEL_TYPE)) {
LOGP(DMSC, LOGL_ERROR, "Mandantory channel type not present.\n");
@@ -1064,8 +1074,14 @@ static int bssap_handle_lchan_signal(unsigned int subsys, unsigned int signal,
switch (signal) {
case S_LCHAN_UNEXPECTED_RELEASE:
/* handle this through the T10 timeout */
if (lchan->msc_data->lchan != lchan)
if (lchan->msc_data->lchan != lchan) {
if (lchan->msc_data->secondary_lchan == lchan) {
LOGP(DMSC, LOGL_NOTICE, "Setting secondary to NULL.\n");
lchan->msc_data->secondary_lchan = NULL;
lchan->msc_data = NULL;
}
return 0;
}
bsc_del_timer(&lchan->msc_data->T10);
conn = lchan->msc_data->sccp;
@@ -1202,9 +1218,17 @@ static void rll_ind_cb(struct gsm_lchan *lchan, u_int8_t link_id,
}
/* decide if we need to queue because of SAPI != 0 */
void bts_queue_send(struct msgb *msg, int link_id)
static void bts_queue_send(struct msgb *msg, int link_id)
{
struct bss_sccp_connection_data *data = msg->lchan->msc_data;
struct bss_sccp_connection_data *data;
if (!msg->lchan || !msg->lchan->msc_data) {
LOGP(DMSC, LOGL_ERROR, "BAD: Wrongly configured lchan: %p\n", msg->lchan);
msgb_free(msg);
}
data = msg->lchan->msc_data;
if (!data->block_gsm && data->gsm_queue_size == 0) {
if (msg->lchan->sapis[link_id & 0x7] != LCHAN_SAPI_UNUSED) {
@@ -1221,6 +1245,7 @@ void bts_queue_send(struct msgb *msg, int link_id)
}
} else if (data->gsm_queue_size == 10) {
LOGP(DMSC, LOGL_ERROR, "Queue full on %p. Dropping GSM0408.\n", data->sccp);
msgb_free(msg);
} else {
LOGP(DMSC, LOGL_DEBUG, "Queueing GSM0408 message on %p. Queue size: %d\n",
data->sccp, data->gsm_queue_size + 1);
@@ -1282,6 +1307,7 @@ void gsm0808_send_assignment_failure(struct gsm_lchan *lchan, u_int8_t cause, u_
struct msgb *resp;
bsc_del_timer(&lchan->msc_data->T10);
bssmap_free_secondary(lchan->msc_data);
resp = bssmap_create_assignment_failure(cause, rr_value);
if (!resp) {
LOGP(DMSC, LOGL_ERROR, "Allocation failure: %p\n", lchan_get_sccp(lchan));

View File

@@ -223,7 +223,8 @@ _lc_find_bts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan)
}
/* Allocate a logical channel */
struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type)
struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type,
int allow_bigger)
{
struct gsm_lchan *lchan = NULL;
enum gsm_phys_chan_config first, second;
@@ -241,6 +242,19 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type)
lchan = _lc_find_bts(bts, first);
if (lchan == NULL)
lchan = _lc_find_bts(bts, second);
/* allow to assign bigger channels */
if (allow_bigger) {
if (lchan == NULL) {
lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_H);
type = GSM_LCHAN_TCH_H;
}
if (lchan == NULL) {
lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F);
type = GSM_LCHAN_TCH_F;
}
}
break;
case GSM_LCHAN_TCH_F:
lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F);
@@ -322,14 +336,46 @@ void lchan_free(struct gsm_lchan *lchan)
* channel using it */
}
/* Consider releasing the channel now */
int _lchan_release(struct gsm_lchan *lchan, u_int8_t release_reason)
/*
* There was an error with the TRX and we need to forget
* any state so that a lchan can be allocated again after
* the trx is fully usable.
*/
void lchan_reset(struct gsm_lchan *lchan)
{
if (lchan->conn.use_count > 0) {
DEBUGP(DRLL, "BUG: _lchan_release called without zero use_count.\n");
bsc_del_timer(&lchan->T3101);
bsc_del_timer(&lchan->T3111);
bsc_del_timer(&lchan->error_timer);
lchan->type = GSM_LCHAN_NONE;
lchan->state = LCHAN_S_NONE;
}
static int _lchan_release_next_sapi(struct gsm_lchan *lchan)
{
int sapi;
for (sapi = 1; sapi < ARRAY_SIZE(lchan->sapis); ++sapi) {
u_int8_t link_id;
if (lchan->sapis[sapi] == LCHAN_SAPI_UNUSED)
continue;
link_id = sapi;
if (lchan->type == GSM_LCHAN_TCH_F || lchan->type == GSM_LCHAN_TCH_H)
link_id |= 0x40;
rsl_release_request(lchan, link_id, lchan->release_reason);
return 0;
}
return 1;
}
static void _lchan_handle_release(struct gsm_lchan *lchan)
{
/* Ask for SAPI != 0 to be freed first and stop if we need to wait */
if (_lchan_release_next_sapi(lchan) == 0)
return;
/* Assume we have GSM04.08 running and send a release */
if (lchan->conn.subscr) {
++lchan->conn.use_count;
@@ -342,8 +388,42 @@ int _lchan_release(struct gsm_lchan *lchan, u_int8_t release_reason)
LOGP(DRLL, LOGL_ERROR, "Channel count is negative: %d\n",
lchan->conn.use_count);
rsl_release_request(lchan, 0, lchan->release_reason);
}
/* called from abis rsl */
int rsl_lchan_rll_release(struct gsm_lchan *lchan, u_int8_t link_id)
{
if (lchan->state != LCHAN_S_REL_REQ)
return -1;
if ((link_id & 0x7) != 0)
_lchan_handle_release(lchan);
return 0;
}
/*
* Start the channel release procedure now. We will start by shutting
* down SAPI!=0, then we will deactivate the SACCH and finish by releasing
* the last SAPI at which point the RSL code will send the channel release
* for us. We should guard the whole shutdown by T3109 or similiar and then
* update the fixme inside gsm_04_08_utils.c
* When we request to release the RLL and we don't get an answer within T200
* the BTS will send us an Error indication which we will handle by closing
* the channel and be done.
*/
int _lchan_release(struct gsm_lchan *lchan, u_int8_t release_reason)
{
if (lchan->conn.use_count > 0) {
DEBUGP(DRLL, "BUG: _lchan_release called without zero use_count.\n");
return 0;
}
DEBUGP(DRLL, "%s Recycling Channel\n", gsm_lchan_name(lchan));
rsl_release_request(lchan, 0, release_reason);
rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ);
lchan->release_reason = release_reason;
_lchan_handle_release(lchan);
return 1;
}

View File

@@ -420,7 +420,17 @@ e1inp_sign_link_create(struct e1inp_ts *ts, enum e1inp_sign_type type,
void e1inp_sign_link_destroy(struct e1inp_sign_link *link)
{
struct msgb *msg;
llist_del(&link->list);
while (!llist_empty(&link->tx_list)) {
msg = msgb_dequeue(&link->tx_list);
msgb_free(msg);
}
if (link->ts->type == E1INP_TS_TYPE_SIGN)
bsc_del_timer(&link->ts->sign.tx_timer);
talloc_free(link);
}

View File

@@ -88,6 +88,7 @@ static const struct value_string lchan_s_names[] = {
{ LCHAN_S_ACTIVE, "ACTIVE" },
{ LCHAN_S_INACTIVE, "INACTIVE" },
{ LCHAN_S_REL_REQ, "RELEASE REQUESTED" },
{ LCHAN_S_REL_ERR, "RELEASE DUE ERROR" },
{ 0, NULL }
};
@@ -280,6 +281,10 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c
net->stats.call.dialled = counter_alloc("net.call.dialled");
net->stats.call.alerted = counter_alloc("net.call.alerted");
net->stats.call.connected = counter_alloc("net.call.connected");
net->stats.chan.rf_fail = counter_alloc("net.chan.rf_fail");
net->stats.chan.rll_err = counter_alloc("net.chan.rll_err");
net->stats.bts.oml_fail = counter_alloc("net.bts.oml_fail");
net->stats.bts.rsl_fail = counter_alloc("net.bts.rsl_fail");
net->mncc_recv = mncc_recv;
@@ -289,6 +294,9 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c
net->core_network_code = -1;
net->rtp_base_port = 4000;
net->msc_ip = talloc_strdup(net, "127.0.0.1");
net->msc_port = 5000;
return net;
}

View File

@@ -99,7 +99,7 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts)
counter_inc(bts->network->stats.handover.attempted);
new_lchan = lchan_alloc(bts, old_lchan->type);
new_lchan = lchan_alloc(bts, old_lchan->type, 0);
if (!new_lchan) {
LOGP(DHO, LOGL_NOTICE, "No free channel\n");
counter_inc(bts->network->stats.handover.no_channel);
@@ -134,6 +134,7 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts)
return rc;
}
rsl_lchan_set_state(new_lchan, LCHAN_S_ACT_REQ);
llist_add(&ho->list, &bsc_handovers);
/* we continue in the SS_LCHAN handler / ho_chan_activ_ack */

View File

@@ -1,6 +1,8 @@
/* OpenBSC Abis input driver for ip.access */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2010 by Holger Hans Peter Freyther
* (C) 2010 by On-Waves
*
* All Rights Reserved
*
@@ -234,6 +236,8 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg,
}
DEBUGP(DINP, "Identified BTS %u/%u/%u\n", site_id, bts_id, trx_id);
if (bfd->priv_nr == PRIV_OML) {
/* drop any old oml connection */
ipaccess_drop_oml(bts);
bts->oml_link = e1inp_sign_link_create(&line->ts[PRIV_OML - 1],
E1INP_SIGN_OML, bts->c0,
bts->oml_tei, 0);
@@ -241,7 +245,18 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg,
struct e1inp_ts *e1i_ts;
struct bsc_fd *newbfd;
struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, trx_id);
/* drop any old rsl connection */
ipaccess_drop_rsl(trx);
if (!bts->oml_link) {
bsc_unregister_fd(bfd);
close(bfd->fd);
bfd->fd = -1;
talloc_free(bfd);
return 0;
}
bfd->data = line = bts->oml_link->ts->line;
e1i_ts = &line->ts[PRIV_RSL + trx_id - 1];
newbfd = &e1i_ts->driver.ipaccess.fd;
@@ -251,19 +266,13 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg,
E1INP_SIGN_RSL, trx,
trx->rsl_tei, 0);
if (newbfd->fd >= 0) {
LOGP(DINP, LOGL_ERROR, "BTS is still registered. Closing old connection.\n");
bsc_unregister_fd(newbfd);
close(newbfd->fd);
newbfd->fd = -1;
}
/* get rid of our old temporary bfd */
memcpy(newbfd, bfd, sizeof(*newbfd));
newbfd->priv_nr = PRIV_RSL + trx_id;
bsc_unregister_fd(bfd);
bsc_register_fd(newbfd);
bfd->fd = -1;
talloc_free(bfd);
bsc_register_fd(newbfd);
}
break;
}
@@ -328,6 +337,103 @@ struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error)
return msg;
}
int ipaccess_drop_oml(struct gsm_bts *bts)
{
struct gsm_bts_trx *trx;
struct e1inp_ts *ts;
struct e1inp_line *line;
struct bsc_fd *bfd;
if (!bts || !bts->oml_link)
return -1;
/* send OML down */
ts = bts->oml_link->ts;
line = ts->line;
e1inp_event(ts, EVT_E1_TEI_DN, bts->oml_link->tei, bts->oml_link->sapi);
bfd = &ts->driver.ipaccess.fd;
bsc_unregister_fd(bfd);
close(bfd->fd);
bfd->fd = -1;
/* clean up OML and RSL */
e1inp_sign_link_destroy(bts->oml_link);
bts->oml_link = NULL;
bts->ip_access.flags = 0;
/* drop all RSL connections too */
llist_for_each_entry(trx, &bts->trx_list, list)
ipaccess_drop_rsl(trx);
/* kill the E1 line now... as we have no one left to use it */
talloc_free(line);
return -1;
}
static int ipaccess_drop(struct e1inp_ts *ts, struct bsc_fd *bfd)
{
struct e1inp_sign_link *link;
int bts_nr;
if (!ts) {
/*
* If we don't have a TS this means that this is a RSL
* connection but we are not past the authentication
* handling yet. So we can safely delete this bfd and
* wait for a reconnect.
*/
bsc_unregister_fd(bfd);
close(bfd->fd);
bfd->fd = -1;
talloc_free(bfd);
return -1;
}
/* attempt to find a signalling link */
if (ts->type == E1INP_TS_TYPE_SIGN) {
llist_for_each_entry(link, &ts->sign.sign_links, list) {
bts_nr = link->trx->bts->bts_nr;
/* we have issues just reconnecting RLS so we drop OML */
ipaccess_drop_oml(link->trx->bts);
return bts_nr;
}
}
/* error case */
LOGP(DINP, LOGL_ERROR, "Failed to find a signalling link for ts: %p\n", ts);
bsc_unregister_fd(bfd);
close(bfd->fd);
bfd->fd = -1;
return -1;
}
int ipaccess_drop_rsl(struct gsm_bts_trx *trx)
{
struct bsc_fd *bfd;
struct e1inp_ts *ts;
if (!trx || !trx->rsl_link)
return -1;
/* send RSL down */
ts = trx->rsl_link->ts;
e1inp_event(ts, EVT_E1_TEI_DN, trx->rsl_link->tei, trx->rsl_link->sapi);
/* close the socket */
bfd = &ts->driver.ipaccess.fd;
bsc_unregister_fd(bfd);
close(bfd->fd);
bfd->fd = -1;
/* destroy */
e1inp_sign_link_destroy(trx->rsl_link);
trx->rsl_link = NULL;
return -1;
}
static int handle_ts1_read(struct bsc_fd *bfd)
{
struct e1inp_line *line = bfd->data;
@@ -341,18 +447,12 @@ static int handle_ts1_read(struct bsc_fd *bfd)
msg = ipaccess_read_msg(bfd, &error);
if (!msg) {
if (error == 0) {
link = e1inp_lookup_sign_link(e1i_ts, IPAC_PROTO_OML, 0);
if (link) {
link->trx->bts->ip_access.flags = 0;
int ret = ipaccess_drop(e1i_ts, bfd);
if (ret >= 0)
LOGP(DINP, LOGL_NOTICE, "BTS %u disappeared, dead socket\n",
link->trx->bts->nr);
} else
ret);
else
LOGP(DINP, LOGL_NOTICE, "unknown BTS disappeared, dead socket\n");
e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_RSL);
e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_OML);
bsc_unregister_fd(bfd);
close(bfd->fd);
bfd->fd = -1;
}
return error;
}
@@ -362,13 +462,8 @@ static int handle_ts1_read(struct bsc_fd *bfd)
hh = (struct ipaccess_head *) msg->data;
if (hh->proto == IPAC_PROTO_IPACCESS) {
ret = ipaccess_rcvmsg(line, msg, bfd);
if (ret < 0) {
e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_RSL);
e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_OML);
bsc_unregister_fd(bfd);
close(bfd->fd);
bfd->fd = -1;
}
if (ret < 0)
ipaccess_drop(e1i_ts, bfd);
msgb_free(msg);
return ret;
}
@@ -475,7 +570,9 @@ 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, 100);
/* Reducing this might break the nanoBTS 900 init. */
bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, 100000);
return ret;
}

View File

@@ -160,8 +160,9 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
}
endp->bts = addr.sin_addr;
LOGP(DMGCP, LOGL_NOTICE, "Found BTS for endpoint: 0x%x on port: %d/%d\n",
ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp));
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));
}
}

View File

@@ -33,6 +33,8 @@
#include <vty/command.h>
#include <vty/vty.h>
#include <string.h>
static struct mgcp_config *g_cfg = NULL;
/*
@@ -48,23 +50,25 @@ static int config_write_mgcp(struct vty *vty)
{
vty_out(vty, "mgcp%s", VTY_NEWLINE);
if (g_cfg->local_ip)
vty_out(vty, " local ip %s%s", g_cfg->local_ip, VTY_NEWLINE);
if (g_cfg->bts_ip)
vty_out(vty, " local ip %s%s", g_cfg->local_ip, VTY_NEWLINE);
if (g_cfg->bts_ip && strlen(g_cfg->bts_ip) != 0)
vty_out(vty, " bts ip %s%s", g_cfg->bts_ip, VTY_NEWLINE);
vty_out(vty, " bind ip %s%s", g_cfg->source_addr, VTY_NEWLINE);
vty_out(vty, " bind port %u%s", g_cfg->source_port, VTY_NEWLINE);
vty_out(vty, " bind early %u%s", !!g_cfg->early_bind, VTY_NEWLINE);
vty_out(vty, " rtp base %u%s", g_cfg->rtp_base_port, VTY_NEWLINE);
vty_out(vty, " sdp audio payload number %u%s", g_cfg->audio_payload, VTY_NEWLINE);
vty_out(vty, " sdp audio payload name %s%s", g_cfg->audio_name, VTY_NEWLINE);
if (g_cfg->audio_payload != -1)
vty_out(vty, " sdp audio payload number %d%s", g_cfg->audio_payload, VTY_NEWLINE);
if (g_cfg->audio_name)
vty_out(vty, " sdp audio payload name %s%s", g_cfg->audio_name, VTY_NEWLINE);
vty_out(vty, " loop %u%s", !!g_cfg->audio_loop, VTY_NEWLINE);
vty_out(vty, " endpoints %u%s", g_cfg->number_endpoints, VTY_NEWLINE);
vty_out(vty, " number endpoints %u%s", g_cfg->number_endpoints - 1, VTY_NEWLINE);
if (g_cfg->forward_ip)
vty_out(vty, " forward audio ip %s%s", g_cfg->forward_ip, VTY_NEWLINE);
vty_out(vty, " forward audio ip %s%s", g_cfg->forward_ip, VTY_NEWLINE);
if (g_cfg->forward_port != 0)
vty_out(vty, " forward audio port %d%s", g_cfg->forward_port, VTY_NEWLINE);
vty_out(vty, " forward audio port %d%s", g_cfg->forward_port, VTY_NEWLINE);
if (g_cfg->call_agent_addr)
vty_out(vty, " call agent ip %s%s", g_cfg->call_agent_addr, VTY_NEWLINE);
vty_out(vty, " call agent ip %s%s", g_cfg->call_agent_addr, VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -77,7 +81,7 @@ DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp",
vty_out(vty, "MGCP is up and running with %u endpoints:%s", g_cfg->number_endpoints - 1, VTY_NEWLINE);
for (i = 1; i < g_cfg->number_endpoints; ++i) {
struct mgcp_endpoint *endp = &g_cfg->endpoints[i];
vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u on %s traffic in :%u/%u%s",
vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u on %s traffic received bts: %u remote: %u%s",
i, endp->ci,
ntohs(endp->net_rtp), ntohs(endp->net_rtcp),
ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp),

View File

@@ -27,6 +27,7 @@
#include <openbsc/mgcp_internal.h>
#include <osmocore/talloc.h>
#include <osmocore/gsm0808.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -91,8 +92,9 @@ void bsc_mgcp_free_endpoints(struct bsc_nat *nat)
bsc_mgcp_free_endpoint(nat, i);
}
struct bsc_connection *bsc_mgcp_find_con(struct bsc_nat *nat, int endpoint)
struct sccp_connections *bsc_mgcp_find_con(struct bsc_nat *nat, int endpoint)
{
struct sccp_connections *con = NULL;
struct sccp_connections *sccp;
llist_for_each_entry(sccp, &nat->sccp_connections, list_entry) {
@@ -101,9 +103,12 @@ struct bsc_connection *bsc_mgcp_find_con(struct bsc_nat *nat, int endpoint)
if (mgcp_timeslot_to_endpoint(0, sccp->msc_timeslot) != endpoint)
continue;
return sccp->bsc;
con = sccp;
}
if (con)
return con;
LOGP(DMGCP, LOGL_ERROR, "Failed to find the connection.\n");
return NULL;
}
@@ -112,7 +117,7 @@ int bsc_mgcp_policy_cb(struct mgcp_config *cfg, int endpoint, int state, const c
{
struct bsc_nat *nat;
struct bsc_endpoint *bsc_endp;
struct bsc_connection *bsc_con;
struct sccp_connections *sccp;
struct mgcp_endpoint *mgcp_endp;
struct msgb *bsc_msg;
@@ -120,9 +125,9 @@ 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];
bsc_con = bsc_mgcp_find_con(nat, endpoint);
sccp = bsc_mgcp_find_con(nat, endpoint);
if (!bsc_con) {
if (!sccp) {
LOGP(DMGCP, LOGL_ERROR, "Did not find BSC for a new connection on 0x%x for %d\n", endpoint, state);
switch (state) {
@@ -158,14 +163,14 @@ 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 = bsc_con;
bsc_endp->bsc = sccp->bsc;
bsc_endp->pending_delete = 0;
/* we need to update some bits */
if (state == MGCP_ENDP_CRCX) {
struct sockaddr_in sock;
socklen_t len = sizeof(sock);
if (getpeername(bsc_con->write_queue.bfd.fd, (struct sockaddr *) &sock, &len) != 0) {
if (getpeername(sccp->bsc->write_queue.bfd.fd, (struct sockaddr *) &sock, &len) != 0) {
LOGP(DMGCP, LOGL_ERROR, "Can not get the peername...%d/%s\n",
errno, strerror(errno));
} else {
@@ -173,11 +178,12 @@ int bsc_mgcp_policy_cb(struct mgcp_config *cfg, int endpoint, int state, const c
}
} 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_mgcp_msg(bsc_con, bsc_msg);
bsc_write(sccp->bsc, bsc_msg, NAT_IPAC_PROTO_MGCP);
return MGCP_POLICY_DEFER;
}
@@ -458,6 +464,7 @@ int bsc_mgcp_init(struct bsc_nat *nat)
nat->mgcp_cfg->data = nat;
nat->mgcp_cfg->policy_cb = bsc_mgcp_policy_cb;
nat->mgcp_cfg->force_realloc = 1;
nat->mgcp_cfg->bts_ip = "";
nat->bsc_endpoints = talloc_zero_array(nat,
struct bsc_endpoint,
nat->mgcp_cfg->number_endpoints + 1);

View File

@@ -51,14 +51,14 @@
struct log_target *stderr_target;
static const char *config_file = "bsc-nat.cfg";
static char *msc_address = "127.0.0.1";
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 bsc_nat *nat;
static void bsc_send_data(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length);
static void bsc_send_data(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length, int);
static void remove_bsc_connection(struct bsc_connection *connection);
static void msc_send_reset(struct bsc_msc_connection *con);
@@ -93,28 +93,27 @@ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
static void send_reset_ack(struct bsc_connection *bsc)
{
static const u_int8_t gsm_reset_ack[] = {
0x00, 0x13, 0xfd,
0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01,
0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03,
0x00, 0x01, 0x31,
};
bsc_send_data(bsc, gsm_reset_ack, sizeof(gsm_reset_ack));
bsc_send_data(bsc, gsm_reset_ack, sizeof(gsm_reset_ack), IPAC_PROTO_SCCP);
}
static void send_id_ack(struct bsc_connection *bsc)
{
static const u_int8_t id_ack[] = {
0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK
IPAC_MSGT_ID_ACK
};
bsc_send_data(bsc, id_ack, sizeof(id_ack));
bsc_send_data(bsc, id_ack, sizeof(id_ack), IPAC_PROTO_IPACCESS);
}
static void send_id_req(struct bsc_connection *bsc)
{
static const u_int8_t id_req[] = {
0, 17, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_GET,
IPAC_MSGT_ID_GET,
0x01, IPAC_IDTAG_UNIT,
0x01, IPAC_IDTAG_MACADDR,
0x01, IPAC_IDTAG_LOCATION1,
@@ -125,7 +124,7 @@ static void send_id_req(struct bsc_connection *bsc)
0x01, IPAC_IDTAG_SERNR,
};
bsc_send_data(bsc, id_req, sizeof(id_req));
bsc_send_data(bsc, id_req, sizeof(id_req), IPAC_PROTO_IPACCESS);
}
static void nat_send_rlsd(struct sccp_connections *conn)
@@ -154,6 +153,32 @@ static void nat_send_rlsd(struct sccp_connections *conn)
}
}
static void nat_send_rlc(struct sccp_source_reference *src,
struct sccp_source_reference *dst)
{
struct sccp_connection_release_complete *rlc;
struct msgb *msg;
msg = msgb_alloc_headroom(4096, 128, "rlc");
if (!msg) {
LOGP(DNAT, LOGL_ERROR, "Failed to allocate clear command.\n");
return;
}
msg->l2h = msgb_put(msg, sizeof(*rlc));
rlc = (struct sccp_connection_release_complete *) msg->l2h;
rlc->type = SCCP_MSG_TYPE_RLC;
rlc->destination_local_reference = *dst;
rlc->source_local_reference = *src;
ipaccess_prepend_header(msg, IPAC_PROTO_SCCP);
if (write_queue_enqueue(&msc_con->write_queue, msg) != 0) {
LOGP(DINP, LOGL_ERROR, "Failed to enqueue the write.\n");
msgb_free(msg);
}
}
static void send_mgcp_reset(struct bsc_connection *bsc)
{
static const u_int8_t mgcp_reset[] = {
@@ -180,27 +205,25 @@ static void initialize_msc_if_needed()
/*
* Currently we are lacking refcounting so we need to copy each message.
*/
static void bsc_send_data(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length)
static void bsc_send_data(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length, int proto)
{
struct msgb *msg;
if (length > 4096) {
if (length > 4096 - 128) {
LOGP(DINP, LOGL_ERROR, "Can not send message of that size.\n");
return;
}
msg = msgb_alloc(4096, "to-bsc");
msg = msgb_alloc_headroom(4096, 128, "to-bsc");
if (!msg) {
LOGP(DINP, LOGL_ERROR, "Failed to allocate memory for BSC msg.\n");
return;
}
msgb_put(msg, length);
msg->l2h = msgb_put(msg, length);
memcpy(msg->data, data, length);
if (write_queue_enqueue(&bsc->write_queue, msg) != 0) {
LOGP(DINP, LOGL_ERROR, "Failed to enqueue the write.\n");
msgb_free(msg);
}
bsc_write(bsc, msg, proto);
}
static int forward_sccp_to_bts(struct msgb *msg)
@@ -208,6 +231,7 @@ static int forward_sccp_to_bts(struct msgb *msg)
struct sccp_connections *con;
struct bsc_connection *bsc;
struct bsc_nat_parsed *parsed;
int proto;
/* filter, drop, patch the message? */
parsed = bsc_nat_parse(msg);
@@ -219,8 +243,10 @@ static int forward_sccp_to_bts(struct msgb *msg)
if (bsc_nat_filter_ipa(DIR_BSC, msg, parsed))
goto exit;
proto = parsed->ipa_proto;
/* Route and modify the SCCP packet */
if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
if (proto == IPAC_PROTO_SCCP) {
switch (parsed->sccp_type) {
case SCCP_MSG_TYPE_UDT:
/* forward UDT messages to every BSC */
@@ -232,7 +258,10 @@ static int forward_sccp_to_bts(struct msgb *msg)
case SCCP_MSG_TYPE_IT:
con = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
if (parsed->gsm_type == BSS_MAP_MSG_ASSIGMENT_RQST) {
counter_inc(nat->stats.sccp.calls);
if (con) {
counter_inc(con->bsc->cfg->stats.sccp.calls);
if (bsc_mgcp_assign(con, msg) != 0)
LOGP(DNAT, LOGL_ERROR, "Failed to assign...\n");
} else
@@ -254,7 +283,11 @@ static int forward_sccp_to_bts(struct msgb *msg)
goto exit;
}
if (!con)
if (!con && parsed->sccp_type == SCCP_MSG_TYPE_RLSD) {
LOGP(DNAT, LOGL_NOTICE, "Sending fake RLC on RLSD message to network.\n");
/* Exchange src/dest for the reply */
nat_send_rlc(parsed->dest_local_ref, parsed->src_local_ref);
} else if (!con)
LOGP(DNAT, LOGL_ERROR, "Unknown connection for msg type: 0x%x.\n", parsed->sccp_type);
}
@@ -266,7 +299,7 @@ static int forward_sccp_to_bts(struct msgb *msg)
return -1;
}
bsc_send_data(con->bsc, msg->data, msg->len);
bsc_send_data(con->bsc, msg->l2h, msgb_l2len(msg), proto);
return 0;
send_to_all:
@@ -276,11 +309,13 @@ send_to_all:
* message and then send it to the authenticated messages...
*/
if (parsed->ipa_proto == IPAC_PROTO_SCCP && parsed->gsm_type == BSS_MAP_MSG_PAGING) {
bsc = bsc_nat_find_bsc(nat, msg);
int lac;
bsc = bsc_nat_find_bsc(nat, msg, &lac);
if (bsc)
bsc_send_data(bsc, msg->data, msg->len);
bsc_send_data(bsc, msg->l2h, msgb_l2len(msg), parsed->ipa_proto);
else
LOGP(DNAT, LOGL_ERROR, "Could not determine BSC for paging.\n");
LOGP(DNAT, LOGL_ERROR, "Could not determine BSC for paging on lac: %d/0x%x\n",
lac, lac);
goto exit;
}
@@ -289,7 +324,7 @@ send_to_all:
if (!bsc->authenticated)
continue;
bsc_send_data(bsc, msg->data, msg->len);
bsc_send_data(bsc, msg->l2h, msgb_l2len(msg), parsed->ipa_proto);
}
exit:
@@ -301,6 +336,8 @@ static void msc_connection_was_lost(struct bsc_msc_connection *con)
{
struct bsc_connection *bsc, *tmp;
counter_inc(nat->stats.msc.reconn);
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);
@@ -310,7 +347,7 @@ static void msc_connection_was_lost(struct bsc_msc_connection *con)
bsc_msc_schedule_connect(con);
}
static void msc_send_reset(struct bsc_msc_connection *con)
static void msc_send_reset(struct bsc_msc_connection *msc_con)
{
static const u_int8_t reset[] = {
0x00, 0x12, 0xfd,
@@ -330,7 +367,7 @@ static void msc_send_reset(struct bsc_msc_connection *con)
msg->l2h = msgb_put(msg, sizeof(reset));
memcpy(msg->l2h, reset, msgb_l2len(msg));
if (write_queue_enqueue(&con->write_queue, msg) != 0) {
if (write_queue_enqueue(&msc_con->write_queue, msg) != 0) {
LOGP(DMSC, LOGL_ERROR, "Failed to enqueue reset msg.\n");
msgb_free(msg);
}
@@ -423,9 +460,14 @@ static void remove_bsc_connection(struct bsc_connection *connection)
static void ipaccess_close_bsc(void *data)
{
struct sockaddr_in sock;
socklen_t len = sizeof(sock);
struct bsc_connection *conn = data;
LOGP(DNAT, LOGL_ERROR, "BSC didn't respond to identity request. Closing.\n");
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);
}
@@ -436,13 +478,16 @@ static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc
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);
break;
return;
}
}
LOGP(DNAT, LOGL_ERROR, "No bsc found for token %s.\n", token);
}
static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
@@ -602,6 +647,9 @@ static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what)
return ret;
}
/* count the reconnect */
counter_inc(nat->stats.bsc.reconn);
/*
* if we are not connected to a msc... just close the socket
*/
@@ -743,7 +791,7 @@ static void handle_options(int argc, char** argv)
log_set_print_timestamp(stderr_target, 1);
break;
case 'm':
msc_address = strdup(optarg);
msc_ip = optarg;
break;
case 'l':
inet_aton(optarg, &local_addr);
@@ -776,10 +824,6 @@ int main(int argc, char** argv)
log_add_target(stderr_target);
log_set_all_filter(stderr_target, 1);
/* parse options */
local_addr.s_addr = INADDR_ANY;
handle_options(argc, argv);
nat = bsc_nat_alloc();
if (!nat) {
fprintf(stderr, "Failed to allocate the BSC nat.\n");
@@ -787,6 +831,14 @@ int main(int argc, char** argv)
}
nat->mgcp_cfg = talloc_zero(nat, struct mgcp_config);
if (!nat->mgcp_cfg) {
fprintf(stderr, "Failed to allocate MGCP cfg.\n");
return -5;
}
/* parse options */
local_addr.s_addr = INADDR_ANY;
handle_options(argc, argv);
/* init vty and parse */
bsc_nat_vty_init(nat);
@@ -796,6 +848,10 @@ int main(int argc, char** argv)
return -3;
}
/* over rule the VTY config */
if (msc_ip)
bsc_nat_set_msc_ip(nat, msc_ip);
/* seed the PRNG */
srand(time(NULL));
@@ -806,7 +862,7 @@ int main(int argc, char** argv)
return -4;
/* connect to the MSC */
msc_con = bsc_msc_create(msc_address, 5000);
msc_con = bsc_msc_create(nat->msc_ip, nat->msc_port);
if (!msc_con) {
fprintf(stderr, "Creating a bsc_msc_connection failed.\n");
exit(1);

View File

@@ -30,6 +30,7 @@
#include <osmocore/linuxlist.h>
#include <osmocore/talloc.h>
#include <osmocore/gsm0808.h>
#include <sccp/sccp.h>
@@ -45,9 +46,23 @@ struct bsc_nat *bsc_nat_alloc(void)
INIT_LLIST_HEAD(&nat->sccp_connections);
INIT_LLIST_HEAD(&nat->bsc_connections);
INIT_LLIST_HEAD(&nat->bsc_configs);
nat->stats.sccp.conn = counter_alloc("nat.sccp.conn");
nat->stats.sccp.calls = counter_alloc("nat.sccp.calls");
nat->stats.bsc.reconn = counter_alloc("nat.bsc.conn");
nat->stats.bsc.auth_fail = counter_alloc("nat.bsc.auth_fail");
nat->stats.msc.reconn = counter_alloc("nat.msc.conn");
nat->msc_ip = talloc_strdup(nat, "127.0.0.1");
nat->msc_port = 5000;
return nat;
}
void bsc_nat_set_msc_ip(struct bsc_nat *nat, const char *ip)
{
if (nat->msc_ip)
talloc_free(nat->msc_ip);
nat->msc_ip = talloc_strdup(nat, ip);
}
struct bsc_connection *bsc_connection_alloc(struct bsc_nat *nat)
{
struct bsc_connection *con = talloc_zero(nat, struct bsc_connection);
@@ -69,9 +84,13 @@ struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token, unsi
conf->nr = nat->num_bsc;
conf->nat = nat;
llist_add(&conf->entry, &nat->bsc_configs);
llist_add_tail(&conf->entry, &nat->bsc_configs);
++nat->num_bsc;
conf->stats.sccp.conn = counter_alloc("nat.bsc.sccp.conn");
conf->stats.sccp.calls = counter_alloc("nat.bsc.sccp.calls");
conf->stats.net.reconn = counter_alloc("nat.bsc.net.reconnects");
return conf;
}
@@ -85,7 +104,7 @@ void sccp_connection_destroy(struct sccp_connections *conn)
talloc_free(conn);
}
struct bsc_connection *bsc_nat_find_bsc(struct bsc_nat *nat, struct msgb *msg)
struct bsc_connection *bsc_nat_find_bsc(struct bsc_nat *nat, struct msgb *msg, int *lac_out)
{
struct bsc_connection *bsc;
int data_length;
@@ -93,6 +112,8 @@ struct bsc_connection *bsc_nat_find_bsc(struct bsc_nat *nat, struct msgb *msg)
struct tlv_parsed tp;
int i = 0;
*lac_out = -1;
if (!msg->l3h || msgb_l3len(msg) < 3) {
LOGP(DNAT, LOGL_ERROR, "Paging message is too short.\n");
return NULL;
@@ -114,6 +135,7 @@ struct bsc_connection *bsc_nat_find_bsc(struct bsc_nat *nat, struct msgb *msg)
/* Currently we only handle one BSC */
for (i = 1; i < data_length - 1; i += 2) {
unsigned int _lac = ntohs(*(unsigned int *) &data[i]);
*lac_out = _lac;
llist_for_each_entry(bsc, &nat->bsc_connections, list_entry) {
if (!bsc->cfg)
continue;
@@ -146,13 +168,13 @@ int bsc_write_mgcp(struct bsc_connection *bsc, const u_int8_t *data, unsigned in
msg->l3h = msgb_put(msg, length);
memcpy(msg->l3h, data, length);
return bsc_write_mgcp_msg(bsc, msg);
return bsc_write(bsc, msg, NAT_IPAC_PROTO_MGCP);
}
int bsc_write_mgcp_msg(struct bsc_connection *bsc, struct msgb *msg)
int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int proto)
{
/* prepend the header */
ipaccess_prepend_header(msg, NAT_IPAC_PROTO_MGCP);
ipaccess_prepend_header(msg, proto);
if (write_queue_enqueue(&bsc->write_queue, msg) != 0) {
LOGP(DINP, LOGL_ERROR, "Failed to enqueue the write.\n");

View File

@@ -51,6 +51,12 @@ static struct cmd_node bsc_node = {
static int config_write_nat(struct vty *vty)
{
vty_out(vty, "nat%s", VTY_NEWLINE);
if (_nat->imsi_allow)
vty_out(vty, " imsi allow %s%s", _nat->imsi_allow, VTY_NEWLINE);
if (_nat->imsi_deny)
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);
return CMD_SUCCESS;
}
@@ -58,7 +64,11 @@ static void config_write_bsc_single(struct vty *vty, struct bsc_config *bsc)
{
vty_out(vty, " bsc %u%s", bsc->nr, VTY_NEWLINE);
vty_out(vty, " token %s%s", bsc->token, VTY_NEWLINE);
vty_out(vty, " lac %u%s", bsc->lac, VTY_NEWLINE);
vty_out(vty, " location_area_code %u%s", bsc->lac, VTY_NEWLINE);
if (bsc->imsi_allow)
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);
}
static int config_write_bsc(struct vty *vty)
@@ -71,7 +81,7 @@ static int config_write_bsc(struct vty *vty)
}
DEFUN(show_sccp, show_sccp_cmd, "show connections sccp",
DEFUN(show_sccp, show_sccp_cmd, "show sccp connections",
SHOW_STR "Display information about current SCCP connections")
{
struct sccp_connections *con;
@@ -88,32 +98,70 @@ DEFUN(show_sccp, show_sccp_cmd, "show connections sccp",
return CMD_SUCCESS;
}
DEFUN(show_bsc, show_bsc_cmd, "show connections bsc",
DEFUN(show_bsc, show_bsc_cmd, "show bsc connections",
SHOW_STR "Display information about current BSCs")
{
struct bsc_connection *con;
struct sockaddr_in sock;
socklen_t len = sizeof(sock);
llist_for_each_entry(con, &_nat->bsc_connections, list_entry) {
vty_out(vty, "BSC lac: %d, %d auth: %d fd: %d%s",
getpeername(con->write_queue.bfd.fd, (struct sockaddr *) &sock, &len);
vty_out(vty, "BSC lac: %d, %d auth: %d fd: %d peername: %s%s",
con->cfg ? con->cfg->nr : -1,
con->cfg ? con->cfg->lac : -1,
con->authenticated, con->write_queue.bfd.fd, VTY_NEWLINE);
con->authenticated, con->write_queue.bfd.fd,
inet_ntoa(sock.sin_addr), VTY_NEWLINE);
}
return CMD_SUCCESS;
}
DEFUN(show_bsc_cfg, show_bsc_cfg_cmd, "show bsc config",
SHOW_STR "Display information about known BSC configs")
DEFUN(show_bsc_cfg, show_bsc_cfg_cmd, "bsc config show",
"Display information about known BSC configs")
{
struct bsc_config *conf;
llist_for_each_entry(conf, &_nat->bsc_configs, entry) {
vty_out(vty, "BSC token: '%s' lac: %u nr: %u%s",
conf->token, conf->lac, conf->nr, VTY_NEWLINE);
vty_out(vty, " imsi_allow: '%s' imsi_deny: '%s'%s",
conf->imsi_allow ? conf->imsi_allow: "any",
conf->imsi_deny ? conf->imsi_deny : "none",
VTY_NEWLINE);
}
return CMD_SUCCESS;
}
DEFUN(show_stats,
show_stats_cmd,
"show statistics",
SHOW_STR "Display network statistics\n")
{
struct bsc_config *conf;
vty_out(vty, "NAT statistics%s", VTY_NEWLINE);
vty_out(vty, " SCCP Connections %lu total, %lu calls%s",
counter_get(_nat->stats.sccp.conn),
counter_get(_nat->stats.sccp.calls), VTY_NEWLINE);
vty_out(vty, " MSC Connections %lu%s",
counter_get(_nat->stats.msc.reconn), VTY_NEWLINE);
vty_out(vty, " BSC Connections %lu total, %lu auth failed.%s",
counter_get(_nat->stats.bsc.reconn),
counter_get(_nat->stats.bsc.auth_fail), VTY_NEWLINE);
llist_for_each_entry(conf, &_nat->bsc_configs, entry) {
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",
counter_get(conf->stats.sccp.conn),
counter_get(conf->stats.sccp.calls), VTY_NEWLINE);
vty_out(vty, " BSC Connections %lu total%s",
counter_get(conf->stats.net.reconn), VTY_NEWLINE);
}
return CMD_SUCCESS;
}
DEFUN(cfg_nat, cfg_nat_cmd, "nat", "Configute the NAT")
{
@@ -123,6 +171,58 @@ DEFUN(cfg_nat, cfg_nat_cmd, "nat", "Configute the NAT")
return CMD_SUCCESS;
}
static void parse_reg(void *ctx, regex_t *reg, char **imsi, int argc, const char **argv)
{
if (*imsi) {
talloc_free(*imsi);
*imsi = NULL;
}
regfree(reg);
if (argc > 0) {
*imsi = talloc_strdup(ctx, argv[0]);
regcomp(reg, argv[0], 0);
}
}
DEFUN(cfg_nat_imsi_allow,
cfg_nat_imsi_allow_cmd,
"imsi allow [REGEXP]",
"Allow matching IMSIs to talk to the MSC. "
"The defualt is to allow everyone.")
{
parse_reg(_nat, &_nat->imsi_allow_re, &_nat->imsi_allow, argc, argv);
return CMD_SUCCESS;
}
DEFUN(cfg_nat_imsi_deny,
cfg_nat_imsi_deny_cmd,
"imsi deny [REGEXP]",
"Deny matching IMSIs to talk to the MSC. "
"The defualt is to not deny.")
{
parse_reg(_nat, &_nat->imsi_deny_re, &_nat->imsi_deny, argc, argv);
return CMD_SUCCESS;
}
DEFUN(cfg_nat_msc_ip,
cfg_nat_msc_ip_cmd,
"msc ip IP",
"Set the IP address of the MSC.")
{
bsc_nat_set_msc_ip(_nat, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_nat_msc_port,
cfg_nat_msc_port_cmd,
"msc port <1-65500>",
"Set the port of the MSC.")
{
_nat->msc_port = atoi(argv[0]);
return CMD_SUCCESS;
}
/* per BSC configuration */
DEFUN(cfg_bsc, cfg_bsc_cmd, "bsc BSC_NR", "Select a BSC to configure\n")
{
@@ -191,6 +291,30 @@ DEFUN(cfg_bsc_lac, cfg_bsc_lac_cmd, "location_area_code <0-65535>",
return CMD_SUCCESS;
}
DEFUN(cfg_bsc_imsi_allow,
cfg_bsc_imsi_allow_cmd,
"imsi allow [REGEXP]",
"Allow IMSIs with the following network to talk to the MSC."
"The default is to allow everyone)")
{
struct bsc_config *conf = vty->index;
parse_reg(conf, &conf->imsi_allow_re, &conf->imsi_allow, argc, argv);
return CMD_SUCCESS;
}
DEFUN(cfg_bsc_imsi_deny,
cfg_bsc_imsi_deny_cmd,
"imsi deny [REGEXP]",
"Deny IMSIs with the following network to talk to the MSC."
"The default is to not deny anyone.)")
{
struct bsc_config *conf = vty->index;
parse_reg(conf, &conf->imsi_deny_re, &conf->imsi_deny, argc, argv);
return CMD_SUCCESS;
}
int bsc_nat_vty_init(struct bsc_nat *nat)
{
_nat = nat;
@@ -202,6 +326,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
install_element(VIEW_NODE, &show_sccp_cmd);
install_element(VIEW_NODE, &show_bsc_cmd);
install_element(VIEW_NODE, &show_bsc_cfg_cmd);
install_element(VIEW_NODE, &show_stats_cmd);
openbsc_vty_add_cmds();
@@ -209,6 +334,10 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
install_element(CONFIG_NODE, &cfg_nat_cmd);
install_node(&nat_node, config_write_nat);
install_default(NAT_NODE);
install_element(NAT_NODE, &cfg_nat_imsi_allow_cmd);
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);
/* BSC subgroups */
install_element(NAT_NODE, &cfg_bsc_cmd);
@@ -216,6 +345,8 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
install_default(BSC_NODE);
install_element(BSC_NODE, &cfg_bsc_token_cmd);
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);
mgcp_vty_init();

View File

@@ -99,7 +99,10 @@ int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc
return -1;
}
llist_add(&conn->list_entry, &bsc->nat->sccp_connections);
bsc_mgcp_clear(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);
LOGP(DNAT, LOGL_DEBUG, "Created 0x%x <-> 0x%x mapping for con %p\n",
sccp_src_ref_to_int(&conn->real_ref),

View File

@@ -70,14 +70,6 @@ static unsigned int calculate_group(struct gsm_bts *bts, struct gsm_subscriber *
static void paging_remove_request(struct gsm_bts_paging_state *paging_bts,
struct gsm_paging_request *to_be_deleted)
{
/* Update the last_request if that is necessary */
if (to_be_deleted == paging_bts->last_request) {
paging_bts->last_request =
(struct gsm_paging_request *)paging_bts->last_request->entry.next;
if (&to_be_deleted->entry == &paging_bts->pending_requests)
paging_bts->last_request = NULL;
}
bsc_del_timer(&to_be_deleted->T3113);
llist_del(&to_be_deleted->entry);
subscr_put(to_be_deleted->subscr);
@@ -90,7 +82,7 @@ static void page_ms(struct gsm_paging_request *request)
unsigned int mi_len;
unsigned int page_group;
DEBUGP(DPAG, "Going to send paging commands: imsi: '%s' tmsi: '0x%x'\n",
LOGP(DPAG, LOGL_INFO, "Going to send paging commands: imsi: '%s' tmsi: '0x%x'\n",
request->subscr->imsi, request->subscr->tmsi);
if (request->subscr->tmsi == GSM_RESERVED_TMSI)
@@ -103,14 +95,6 @@ static void page_ms(struct gsm_paging_request *request)
request->chan_type);
}
static void paging_move_to_next(struct gsm_bts_paging_state *paging_bts)
{
paging_bts->last_request =
(struct gsm_paging_request *)paging_bts->last_request->entry.next;
if (&paging_bts->last_request->entry == &paging_bts->pending_requests)
paging_bts->last_request = NULL;
}
/*
* This is kicked by the periodic PAGING LOAD Indicator
* coming from abis_rsl.c
@@ -128,17 +112,26 @@ static void paging_handle_pending_requests(struct gsm_bts_paging_state *paging_b
* return then.
*/
if (llist_empty(&paging_bts->pending_requests)) {
paging_bts->last_request = NULL;
/* since the list is empty, no need to reschedule the timer */
return;
}
if (!paging_bts->last_request)
paging_bts->last_request =
(struct gsm_paging_request *)paging_bts->pending_requests.next;
/*
* In case the BTS does not provide us with load indication just fill
* up our slots for this round. We should be able to page 20 subscribers
* every two seconds. So we will just give the BTS some extra credit.
* We will have to see how often we run out of this credit, so we might
* need a low watermark and then add credit or give 20 every run when
* the bts sets an option for that.
*/
if (paging_bts->available_slots == 0) {
LOGP(DPAG, LOGL_NOTICE, "No slots available on bts nr %d\n",
paging_bts->bts->nr);
paging_bts->available_slots = 20;
}
assert(paging_bts->last_request);
initial_request = paging_bts->last_request;
initial_request = llist_entry(paging_bts->pending_requests.next,
struct gsm_paging_request, entry);
current_request = initial_request;
do {
@@ -146,17 +139,13 @@ static void paging_handle_pending_requests(struct gsm_bts_paging_state *paging_b
page_ms(current_request);
paging_bts->available_slots--;
/*
* move to the next item. We might wrap around
* this means last_request will be NULL and we just
* call paging_page_to_next again. It it guranteed
* that the list is not empty.
*/
paging_move_to_next(paging_bts);
if (!paging_bts->last_request)
paging_bts->last_request =
(struct gsm_paging_request *)paging_bts->pending_requests.next;
current_request = paging_bts->last_request;
/* take the current and add it to the back */
llist_del(&current_request->entry);
llist_add_tail(&current_request->entry, &paging_bts->pending_requests);
/* take the next request */
current_request = llist_entry(paging_bts->pending_requests.next,
struct gsm_paging_request, entry);
} while (paging_bts->available_slots > 0
&& initial_request != current_request);
@@ -178,7 +167,7 @@ void paging_init(struct gsm_bts *bts)
bts->paging.work_timer.data = &bts->paging;
/* Large number, until we get a proper message */
bts->paging.available_slots = 100;
bts->paging.available_slots = 20;
}
static int paging_pending_request(struct gsm_bts_paging_state *bts,
@@ -200,7 +189,7 @@ static void paging_T3113_expired(void *data)
void *cbfn_param;
gsm_cbfn *cbfn;
DEBUGP(DPAG, "T3113 expired for request %p (%s)\n",
LOGP(DPAG, LOGL_INFO, "T3113 expired for request %p (%s)\n",
req, req->subscr->imsi);
sig_data.subscr = req->subscr;
@@ -208,11 +197,11 @@ static void paging_T3113_expired(void *data)
sig_data.lchan = NULL;
/* must be destroyed before calling cbfn, to prevent double free */
counter_inc(req->bts->network->stats.paging.expired);
cbfn_param = req->cbfn_param;
cbfn = req->cbfn;
paging_remove_request(&req->bts->paging, req);
counter_inc(req->bts->network->stats.paging.expired);
dispatch_signal(SS_PAGING, S_PAGING_EXPIRED, &sig_data);
if (cbfn)
@@ -227,11 +216,11 @@ static int _paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscr,
struct gsm_paging_request *req;
if (paging_pending_request(bts_entry, subscr)) {
DEBUGP(DPAG, "Paging request already pending\n");
LOGP(DPAG, LOGL_INFO, "Paging request already pending for %s\n", subscr->imsi);
return -EEXIST;
}
DEBUGP(DPAG, "Start paging of subscriber %llu on bts %d.\n",
LOGP(DPAG, LOGL_DEBUG, "Start paging of subscriber %llu on bts %d.\n",
subscr->id, bts->nr);
req = talloc_zero(tall_paging_ctx, struct gsm_paging_request);
req->subscr = subscr_get(subscr);
@@ -296,11 +285,11 @@ static void _paging_request_stop(struct gsm_bts *bts, struct gsm_subscriber *sub
entry) {
if (req->subscr == subscr) {
if (lchan && req->cbfn) {
DEBUGP(DPAG, "Stop paging on bts %d, calling cbfn.\n", bts->nr);
LOGP(DPAG, LOGL_DEBUG, "Stop paging on bts %d, calling cbfn.\n", bts->nr);
req->cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_SUCCEEDED,
NULL, lchan, req->cbfn_param);
} else
DEBUGP(DPAG, "Stop paging on bts %d silently.\n", bts->nr);
LOGP(DPAG, LOGL_DEBUG, "Stop paging on bts %d silently.\n", bts->nr);
paging_remove_request(&bts->paging, req);
break;
}
@@ -337,3 +326,15 @@ void paging_update_buffer_space(struct gsm_bts *bts, u_int16_t free_slots)
{
bts->paging.available_slots = free_slots;
}
unsigned int paging_pending_requests_nr(struct gsm_bts *bts)
{
unsigned int requests = 0;
struct gsm_paging_request *req;
llist_for_each_entry(req, &bts->paging.pending_requests, entry)
++requests;
return requests;
}

View File

@@ -39,6 +39,8 @@
#include <osmocore/talloc.h>
#include <openbsc/telnet_interface.h>
#include <openbsc/vty.h>
#include <openbsc/ipaccess.h>
#include <openbsc/paging.h>
static struct gsm_network *gsmnet;
@@ -195,7 +197,8 @@ static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
net_dump_nmstate(vty, &bts->nm_state);
vty_out(vty, " Site Mgr NM State: ");
net_dump_nmstate(vty, &bts->site_mgr.nm_state);
vty_out(vty, " Paging: FIXME pending requests, %u free slots%s",
vty_out(vty, " Paging: %u pending requests, %u free slots%s",
paging_pending_requests_nr(bts),
bts->paging.available_slots, VTY_NEWLINE);
if (!is_ipaccess_bts(bts)) {
vty_out(vty, " E1 Signalling Link:%s", VTY_NEWLINE);
@@ -233,6 +236,36 @@ DEFUN(show_bts, show_bts_cmd, "show bts [number]",
return CMD_SUCCESS;
}
DEFUN(test_bts_lchan_alloc, test_bts_lchan_alloc_cmd, "test bts alloc (sdcch|tch_h|tch_f)",
"Test command to allocate all channels. You will need to restart. To free these channels.\n")
{
struct gsm_network *net = gsmnet;
int bts_nr;
enum gsm_chan_t type = GSM_LCHAN_NONE;
if (strcmp("sdcch", argv[0]) == 0)
type = GSM_LCHAN_SDCCH;
else if (strcmp("tch_h", argv[0]) == 0)
type = GSM_LCHAN_TCH_H;
else if (strcmp("tch_f", argv[0]) == 0)
type = GSM_LCHAN_TCH_F;
else {
vty_out(vty, "Unknown mode for allocation.%s", VTY_NEWLINE);
}
for (bts_nr = 0; bts_nr < net->num_bts; ++bts_nr) {
struct gsm_bts *bts = gsm_bts_num(net, bts_nr);
struct gsm_lchan *lchan;
/* alloc the channel */
while ((lchan = lchan_alloc(bts, type, 0)) != NULL)
rsl_lchan_set_state(lchan, LCHAN_S_REL_ERR);
}
return CMD_SUCCESS;
}
/* utility functions */
static void parse_e1_link(struct gsm_e1_subslot *e1_link, const char *line,
const char *ts, const char *ss)
@@ -275,6 +308,9 @@ static void config_write_trx_single(struct vty *vty, struct gsm_bts_trx *trx)
int i;
vty_out(vty, " trx %u%s", trx->nr, VTY_NEWLINE);
vty_out(vty, " rf_locked %u%s",
trx->nm_state.administrative == NM_STATE_LOCKED ? 1 : 0,
VTY_NEWLINE);
vty_out(vty, " arfcn %u%s", trx->arfcn, VTY_NEWLINE);
vty_out(vty, " nominal power %u%s", trx->nominal_power, VTY_NEWLINE);
vty_out(vty, " max_power_red %u%s", trx->max_power_red, VTY_NEWLINE);
@@ -429,6 +465,8 @@ static int config_write_net(struct vty *vty)
if (gsmnet->bsc_token)
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);
return CMD_SUCCESS;
}
@@ -915,43 +953,47 @@ DEFUN(show_paging,
return CMD_SUCCESS;
}
DEFUN(show_stats,
show_stats_cmd,
"show statistics",
SHOW_STR "Display network statistics\n")
DEFUN(drop_bts,
drop_bts_cmd,
"drop bts connection <0-65535> (oml|rsl)",
"Debug/Simulation command to drop ipaccess BTS\n")
{
struct gsm_network *net = gsmnet;
struct gsm_bts_trx *trx;
struct gsm_bts *bts;
unsigned int bts_nr;
bts_nr = atoi(argv[0]);
if (bts_nr >= gsmnet->num_bts) {
vty_out(vty, "BTS number must be between 0 and %d. It was %d.%s",
gsmnet->num_bts, bts_nr, VTY_NEWLINE);
return CMD_WARNING;
}
bts = gsm_bts_num(gsmnet, bts_nr);
if (!bts) {
vty_out(vty, "BTS Nr. %d could not be found.%s", bts_nr, VTY_NEWLINE);
return CMD_WARNING;
}
if (!is_ipaccess_bts(bts)) {
vty_out(vty, "This command only works for ipaccess.%s", VTY_NEWLINE);
return CMD_WARNING;
}
/* close all connections */
if (strcmp(argv[1], "oml") == 0)
ipaccess_drop_oml(bts);
else if (strcmp(argv[1], "rsl") == 0) {
/* close all rsl connections */
llist_for_each_entry(trx, &bts->trx_list, list) {
ipaccess_drop_rsl(trx);
}
} else {
vty_out(vty, "Argument must be 'oml# or 'rsl'.%s", VTY_NEWLINE);
return CMD_WARNING;
}
vty_out(vty, "Channel Requests : %lu total, %lu no channel%s",
counter_get(net->stats.chreq.total),
counter_get(net->stats.chreq.no_channel), VTY_NEWLINE);
vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s",
counter_get(net->stats.loc_upd_type.attach),
counter_get(net->stats.loc_upd_type.normal),
counter_get(net->stats.loc_upd_type.periodic), VTY_NEWLINE);
vty_out(vty, "IMSI Detach Indications : %lu%s",
counter_get(net->stats.loc_upd_type.detach), VTY_NEWLINE);
vty_out(vty, "Location Update Response: %lu accept, %lu reject%s",
counter_get(net->stats.loc_upd_resp.accept),
counter_get(net->stats.loc_upd_resp.reject), VTY_NEWLINE);
vty_out(vty, "Paging : %lu attempted, %lu complete, %lu expired%s",
counter_get(net->stats.paging.attempted),
counter_get(net->stats.paging.completed),
counter_get(net->stats.paging.expired), VTY_NEWLINE);
vty_out(vty, "Handover : %lu attempted, %lu no_channel, %lu timeout, "
"%lu completed, %lu failed%s",
counter_get(net->stats.handover.attempted),
counter_get(net->stats.handover.no_channel),
counter_get(net->stats.handover.timeout),
counter_get(net->stats.handover.completed),
counter_get(net->stats.handover.failed), VTY_NEWLINE);
vty_out(vty, "SMS MO : %lu submitted, %lu no receiver%s",
counter_get(net->stats.sms.submitted),
counter_get(net->stats.sms.no_receiver), VTY_NEWLINE);
vty_out(vty, "SMS MT : %lu delivered, %lu no memory, %lu other error%s",
counter_get(net->stats.sms.delivered),
counter_get(net->stats.sms.rp_err_mem),
counter_get(net->stats.sms.rp_err_other), VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -1264,6 +1306,27 @@ DEFUN(cfg_net_pag_any_tch,
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_ip,
cfg_net_msc_ip_cmd,
"msc ip IP",
"Set the MSC/MUX IP address.")
{
if (gsmnet->msc_ip)
talloc_free(gsmnet->msc_ip);
gsmnet->msc_ip = talloc_strdup(gsmnet, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_port,
cfg_net_msc_port_cmd,
"msc port <1-65000>",
"Set the MSC/MUX port.")
{
gsmnet->msc_port = atoi(argv[0]);
return CMD_SUCCESS;
}
#define DECLARE_TIMER(number, doc) \
DEFUN(cfg_net_T##number, \
cfg_net_T##number##_cmd, \
@@ -1287,7 +1350,7 @@ DECLARE_TIMER(3103, "Set the timeout value for HANDOVER.")
DECLARE_TIMER(3105, "Currently not used.")
DECLARE_TIMER(3107, "Currently not used.")
DECLARE_TIMER(3109, "Currently not used.")
DECLARE_TIMER(3111, "Currently not used.")
DECLARE_TIMER(3111, "Set the RSL timeout to wait before releasing the RF Channel.")
DECLARE_TIMER(3113, "Set the time to try paging a subscriber.")
DECLARE_TIMER(3115, "Currently not used.")
DECLARE_TIMER(3117, "Currently not used.")
@@ -1920,7 +1983,9 @@ int bsc_vty_init(struct gsm_network *net)
install_element(VIEW_NODE, &show_e1ts_cmd);
install_element(VIEW_NODE, &show_paging_cmd);
install_element(VIEW_NODE, &show_stats_cmd);
install_element(VIEW_NODE, &drop_bts_cmd);
install_element(VIEW_NODE, &test_bts_lchan_alloc_cmd);
openbsc_vty_add_cmds();
@@ -1962,6 +2027,8 @@ int bsc_vty_init(struct gsm_network *net)
install_element(GSMNET_NODE, &cfg_net_T3141_cmd);
install_element(GSMNET_NODE, &cfg_net_bsc_token_cmd);
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_bts_cmd);
install_node(&bts_node, config_write_bts);

View File

@@ -27,13 +27,39 @@
#include <vty/vty.h>
#include <openbsc/gsm_data.h>
#include <openbsc/vty.h>
static struct gsmnet *gsmnet = NULL;
#include <sccp/sccp.h>
static struct gsm_network *gsmnet = NULL;
extern struct llist_head *bsc_sccp_connections();
DEFUN(show_bsc, show_bsc_cmd, "show bsc",
SHOW_STR "Display information about the BSC\n")
{
vty_out(vty, "BSC... not implemented yet%s", VTY_NEWLINE);
struct bss_sccp_connection_data *con;
vty_out(vty, "BSC Information%s", VTY_NEWLINE);
llist_for_each_entry(con, bsc_sccp_connections(), active_connections) {
vty_out(vty, " Connection: LCHAN: %p sec LCHAN: %p SCCP src: %d dest: %d%s",
con->lchan, con->secondary_lchan,
con->sccp ? (int) sccp_src_ref_to_int(&con->sccp->source_local_reference) : -1,
con->sccp ? (int) sccp_src_ref_to_int(&con->sccp->destination_local_reference) : -1,
VTY_NEWLINE);
}
return CMD_SUCCESS;
}
DEFUN(show_stats,
show_stats_cmd,
"show statistics",
SHOW_STR "Display network statistics\n")
{
struct gsm_network *net = gsmnet;
openbsc_vty_print_statistics(vty, net);
return CMD_SUCCESS;
}
@@ -43,6 +69,7 @@ int bsc_vty_init_extra(struct gsm_network *net)
/* get runtime information */
install_element(VIEW_NODE, &show_bsc_cmd);
install_element(VIEW_NODE, &show_stats_cmd);
return 0;
}

View File

@@ -228,6 +228,23 @@ DEFUN(diable_logging,
return CMD_SUCCESS;
}
void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net)
{
vty_out(vty, "Channel Requests : %lu total, %lu no channel%s",
counter_get(net->stats.chreq.total),
counter_get(net->stats.chreq.no_channel), VTY_NEWLINE);
vty_out(vty, "Channel Failures : %lu rf_failures, %lu rll failures%s",
counter_get(net->stats.chan.rf_fail),
counter_get(net->stats.chan.rll_err), VTY_NEWLINE);
vty_out(vty, "Paging : %lu attempted, %lu complete, %lu expired%s",
counter_get(net->stats.paging.attempted),
counter_get(net->stats.paging.completed),
counter_get(net->stats.paging.expired), VTY_NEWLINE);
vty_out(vty, "BTS failures : %lu OML, %lu RSL%s",
counter_get(net->stats.bts.oml_fail),
counter_get(net->stats.bts.rsl_fail), VTY_NEWLINE);
}
void openbsc_vty_add_cmds()
{
install_element(VIEW_NODE, &enable_logging_cmd);

View File

@@ -41,6 +41,7 @@
#include <osmocore/talloc.h>
#include <openbsc/signal.h>
#include <openbsc/debug.h>
#include <openbsc/vty.h>
static struct gsm_network *gsmnet;
@@ -502,6 +503,41 @@ static int scall_cbfn(unsigned int subsys, unsigned int signal,
return 0;
}
DEFUN(show_stats,
show_stats_cmd,
"show statistics",
SHOW_STR "Display network statistics\n")
{
struct gsm_network *net = gsmnet;
openbsc_vty_print_statistics(vty, net);
vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s",
counter_get(net->stats.loc_upd_type.attach),
counter_get(net->stats.loc_upd_type.normal),
counter_get(net->stats.loc_upd_type.periodic), VTY_NEWLINE);
vty_out(vty, "IMSI Detach Indications : %lu%s",
counter_get(net->stats.loc_upd_type.detach), VTY_NEWLINE);
vty_out(vty, "Location Update Response: %lu accept, %lu reject%s",
counter_get(net->stats.loc_upd_resp.accept),
counter_get(net->stats.loc_upd_resp.reject), VTY_NEWLINE);
vty_out(vty, "Handover : %lu attempted, %lu no_channel, %lu timeout, "
"%lu completed, %lu failed%s",
counter_get(net->stats.handover.attempted),
counter_get(net->stats.handover.no_channel),
counter_get(net->stats.handover.timeout),
counter_get(net->stats.handover.completed),
counter_get(net->stats.handover.failed), VTY_NEWLINE);
vty_out(vty, "SMS MO : %lu submitted, %lu no receiver%s",
counter_get(net->stats.sms.submitted),
counter_get(net->stats.sms.no_receiver), VTY_NEWLINE);
vty_out(vty, "SMS MT : %lu delivered, %lu no memory, %lu other error%s",
counter_get(net->stats.sms.delivered),
counter_get(net->stats.sms.rp_err_mem),
counter_get(net->stats.sms.rp_err_other), VTY_NEWLINE);
return CMD_SUCCESS;
}
int bsc_vty_init_extra(struct gsm_network *net)
{
gsmnet = net;
@@ -517,6 +553,7 @@ int bsc_vty_init_extra(struct gsm_network *net)
install_element(VIEW_NODE, &subscriber_silent_sms_cmd);
install_element(VIEW_NODE, &subscriber_silent_call_start_cmd);
install_element(VIEW_NODE, &subscriber_silent_call_stop_cmd);
install_element(VIEW_NODE, &show_stats_cmd);
install_element(CONFIG_NODE, &cfg_subscr_cmd);
install_node(&subscr_node, dummy_config_write);

View File

@@ -242,6 +242,7 @@ static void test_contrack()
fprintf(stderr, "Testing connection tracking.\n");
nat = bsc_nat_alloc();
con = bsc_connection_alloc(nat);
con->cfg = bsc_config_alloc(nat, "foo", 23);
msg = msgb_alloc(4096, "test");
/* 1.) create a connection */
@@ -329,6 +330,7 @@ static void test_contrack()
static void test_paging(void)
{
int lac;
struct bsc_nat *nat;
struct bsc_connection *con;
struct bsc_nat_parsed *parsed;
@@ -347,7 +349,7 @@ static void test_paging(void)
/* Test completely bad input */
copy_to_msg(msg, paging_by_lac_cmd, sizeof(paging_by_lac_cmd));
if (bsc_nat_find_bsc(nat, msg) != 0) {
if (bsc_nat_find_bsc(nat, msg, &lac) != 0) {
fprintf(stderr, "Should have not found anything.\n");
abort();
}
@@ -355,7 +357,7 @@ static void test_paging(void)
/* Test it by not finding it */
copy_to_msg(msg, paging_by_lac_cmd, sizeof(paging_by_lac_cmd));
parsed = bsc_nat_parse(msg);
if (bsc_nat_find_bsc(nat, msg) != 0) {
if (bsc_nat_find_bsc(nat, msg, &lac) != 0) {
fprintf(stderr, "Should have not found aynthing.\n");
abort();
}
@@ -365,7 +367,7 @@ static void test_paging(void)
cfg.lac = 8213;
copy_to_msg(msg, paging_by_lac_cmd, sizeof(paging_by_lac_cmd));
parsed = bsc_nat_parse(msg);
if (bsc_nat_find_bsc(nat, msg) != con) {
if (bsc_nat_find_bsc(nat, msg, &lac) != con) {
fprintf(stderr, "Should have found it.\n");
abort();
}
@@ -431,14 +433,14 @@ static void test_mgcp_find(void)
abort();
}
if (bsc_mgcp_find_con(nat, 12) != con) {
if (bsc_mgcp_find_con(nat, 12) != sccp_con) {
fprintf(stderr, "Didn't find the connection\n");
abort();
}
sccp_con->msc_timeslot = 0;
sccp_con->bsc_timeslot = 0;
if (bsc_mgcp_find_con(nat, 1) != con) {
if (bsc_mgcp_find_con(nat, 1) != sccp_con) {
fprintf(stderr, "Didn't find the connection\n");
abort();
}