Compare commits

...

92 Commits

Author SHA1 Message Date
Holger Hans Peter Freyther
ab46372e2a Bump the configure.in to 0.3on-wave. 2010-02-08 15:39:07 +01:00
Holger Hans Peter Freyther
ff0a562f9a Revert "[bssap] Open a traffic channel for the paging any reason"
This reverts commit 55a0716da7.

Using a TCH/H, TCH/F for paging purpose any will break the MT-SMS
case because this needs a SDCCH to establish SAPI=3. The On Waves
BSC Master branch has support for early assignment now so this hack
is not needed anymore.
2010-01-28 11:59:52 +01:00
Holger Hans Peter Freyther
556008d724 [bsc] Implement early assignment for CC for the MT case.
In case we need to handle speech but we are currently on a SDCCH
we need to assign a new channel and close the old one. This
implementation should have the correct flow of things but we might
need to fix some error situations properly.

It is implemented by keeping a secondary_lchan pointer that will
be swapped into the lchan pointer after the assignment complete
message from the MS. The old lchan will be deactivated (the SACCH
should stay open). We have to manually remove the subscr from the
lchan structure to properly close things down.
2010-01-28 11:59:51 +01:00
Holger Hans Peter Freyther
0094f84f30 [bssap] Use switch/case for the signal handler
Use switch/case, switch/case for the subsys and signal
to prepare to handle more signals in the future.
2010-01-28 11:59:51 +01:00
Holger Hans Peter Freyther
86069143ff [gsm48] Use optional Chan Mode 1 for the assignment command
Specify how we intend to use the assigned channel. This is
needed to make CC with early assignment work properly.
2010-01-28 11:59:51 +01:00
Holger Hans Peter Freyther
44f0be88a3 [gsm48] Allow to send the assignment command on a different lchan
Change the signature to take the lchan were the message is supposed
to be sent and the lchan which is supposed to be assigned.
2010-01-28 11:59:51 +01:00
Holger Hans Peter Freyther
5d88b372d7 [rsl] Send the MultiRateConfig in the RSL Channel Activate msg
If the lchan has AMR as speech codec we also need to send the
multirate config IE in the channel activation. This is already
done for the RSL Channel Modify message.
2010-01-28 04:46:32 +01:00
Holger Hans Peter Freyther
71c7bf5907 [sccp] Separate connection parsing and policy for connection request
The same concept as with the previous patch, make the reject method
work on the source local reference instead of passing it the header.
2010-01-27 12:31:50 +01:00
Holger Hans Peter Freyther
869033148c [sccp] Move the UDT parsing to a new method
Separate SCCP UDT parsing and handling into two methods. This
way the parsing can be reused by the BSC NAT.
2010-01-27 12:31:50 +01:00
Holger Hans Peter Freyther
bc0f7c0988 [sccp] Invent new API to be used by the BSC NAT
I want to reuse the SCCP code for header parsing in the BSC
NAT to identify data and patch the source local reference. To do
this the current handle_* methods will be changed into two parts
one is strictly parsing the other is handling the parsed data.
2010-01-27 12:31:50 +01:00
Holger Hans Peter Freyther
7d06063cfb [paging] Increase the time used to send paging messages to the BTS
Send a Paging Request to the BTS every two seconds. This way it is
unlikely that a phone will try to respond to two paging requests as
it is currently happening.
2010-01-27 12:31:50 +01:00
Holger Hans Peter Freyther
4e42b637fd [bsc_msc] Start the Inactivity Timer only when the connection is established
Start the SCCP IT timer only after the MSC has confirmed the SCCP
connection. It is safe to call bsc_del_timer even if it was never
started. This could happen on a connection refusal.
2010-01-27 12:31:50 +01:00
Holger Hans Peter Freyther
f44de9942b [msc] Fix compilation by adding blocked_gsm to the struct 2010-01-27 12:31:50 +01:00
Holger Hans Peter Freyther
3a110ae60b [msc] Attempt to fix MT SMS with ciphering enabled.
The MSC is asking us to enable ciphering and then immediately
sends a DTAP msg for SAPI=3. We handle this correctly by attempting
to establish SAPI=3 but we never get an establishment confirm
for this SAPI.

Attempt to fix it by not sending any DTAP message when we receive
the Cipher Mode Request and unblock the queue when the ciphering
is confirmed. The unblocking currently works by taking all messages
out of the queue and then submitting them again. This will attempt
to establish the SAPI=3 and such automaticaly.

And the MSC stopped sending me SMS so this needs to be verified at a
later time.
2010-01-27 07:34:34 +01:00
Holger Hans Peter Freyther
bb84adc465 [rest_octets] Change data_len to the sizes of the spec
Is that right?
2010-01-27 06:10:43 +01:00
Holger Hans Peter Freyther
8d123ea3c0 [system_information] Initialize the buffer before moving it
In the case of ipaccess we are doing a ++output but then still
try to write 23 bytes into it and on my system this is leading
to a stack corruption.
2010-01-27 06:09:36 +01:00
Holger Hans Peter Freyther
88ca894df7 [nat] Handle write errors with a warning to make the compiler happy
Make the compiler happy by checking the write error and printing
a message to the console.
2010-01-25 10:01:30 +01:00
Holger Hans Peter Freyther
42b0d6b494 [nat] Add a bsc_filter.c which will carry out the analysis and filtering
The first part is to analyze the IP Access Header and only forward
SCCP messages for now. In the future we might want to do MGCP
signalling through this protocol and connection as well and need to
update this then.
2010-01-21 08:52:40 +01:00
Holger Hans Peter Freyther
82d8b0457b [mgcp] In forward mode we need to rediscover the BTS more often
In plain forward mode we don't have DLCX which will clean
and reset the configuration. We will need to remember the
last GSM BTS port and send data to it.
2010-01-14 08:35:57 +01:00
Holger Hans Peter Freyther
433d6ee1a2 [mgcp] Handle BTS and NET being on the same host
* Do not only check the IP but also the port to figure out
  where to send the data
* Do not memset the endp->remote inside the bind_rtp but from
  inside the crcx as this will be modified by the MDCX
2010-01-14 00:15:44 +01:00
Holger Hans Peter Freyther
203a6eddf8 [mgcp] Warn about unknown messages... 2010-01-13 23:53:59 +01:00
Holger Hans Peter Freyther
56ef6249e3 [mgcp] Allow to forward to a different port 2010-01-13 23:36:53 +01:00
Holger Hans Peter Freyther
b2a96b1be7 [mgcp] Rename rtp and rtcp variables to net_rtp and net_rtcp
Rename the variables to refer to the fact that they are
the ports of the remote.

So we have:
    rtp_port as the local address we are binding to
    net_rtp  for the network rtp
    bsc_rtp  for the bsc rtp
2010-01-13 22:49:55 +01:00
Holger Hans Peter Freyther
d4c29c1574 [mgcp] Make it possible to not specify a bts ip
This way the mgcp will allow anyone to be the BTS..
in the future we might need to communicate things
properly between BSC and MGCP.
2010-01-13 16:38:18 +01:00
Holger Hans Peter Freyther
3d947e6d67 [nat] Use the right len for the packages.. 2010-01-13 15:22:20 +01:00
Holger Hans Peter Freyther
b62c9a19cf [sccp] Add a utility for the nat..
Add a small helper to determine the type of a message
2010-01-13 09:55:43 +01:00
Holger Hans Peter Freyther
ff5957568f [nat] Really forward the data to the BSC 2010-01-13 09:55:20 +01:00
Holger Hans Peter Freyther
7d2e1ca4be [nat] Make sure the ipaccess_bsc_cb will be called.. 2010-01-13 09:52:29 +01:00
Holger Hans Peter Freyther
7ce2e0c8b0 [nat] Unregister the fd before leaving.. 2010-01-13 09:51:23 +01:00
Holger Hans Peter Freyther
78d442420b [nat] First code to simply forward data from the MSC to the real BSC
First code to simply forward the data, no filtering or patching
is in place. This will need to happen soon.
2010-01-13 09:28:12 +01:00
Holger Hans Peter Freyther
8cd2709ebf [ipaccess] Create a method to send the ID ACK messages 2010-01-13 09:06:46 +01:00
Holger Hans Peter Freyther
41a1780102 [nat] Turn off compiler warning... 2010-01-12 21:36:08 +01:00
Holger Hans Peter Freyther
2f84715984 [nat] Security will become important at some point... 2010-01-12 21:35:32 +01:00
Holger Hans Peter Freyther
7253154fc5 [nat] Start to listen for the incoming BTS 2010-01-12 21:34:54 +01:00
Holger Hans Peter Freyther
6c1c76683f [nat] Connect to the MSC like the real BSC
Use the connect_to_msc method to connect to the MSC and
create structure to handle and forward messages to the
real BSC.
2010-01-12 21:15:08 +01:00
Holger Hans Peter Freyther
a92fe9a4ca [bsc_msc] Move the connect to the MSC routine into a new file 2010-01-12 20:40:39 +01:00
Holger Hans Peter Freyther
e83a3f584e [bsc-nat] Start with a simple NAT/MUX for a BSC
Harald actually pointed out that this feature is just NAT. We want
to connect n-real BSCs to one BSC Mux. We will talk the ip.access
protocol and SCCP over of this link.

The mux will drop certain GSM messages (like the reset), it will
replace source local reference (NAT functionality) and it will handle
some GSM08.08 specially.

Get the thing started...
2010-01-11 23:01:16 +01:00
Holger Hans Peter Freyther
118ddebc36 [on-waves] Use a default rtp_base_port, write it out in the config
Currently "write memory" will not store the rtp_base_port of the
network. Fix that by writing it out in write_net. Also set it to
4000 by default in the MGCP and in the BSC.
2010-01-08 15:24:21 +01:00
Holger Hans Peter Freyther
bb53004d47 Tag on-waves 0.2 release 2010-01-07 15:12:23 +01:00
Holger Hans Peter Freyther
6af20842cb [bssap] Return u_int16_t from the get_*_code methods
The LAI generation wants to have 16bit unsigned, just keep
them like this already. This means the int32_t will be truncated
inside the get_*_code methods which is better than doing it
somewhere else.
2010-01-07 14:53:18 +01:00
Holger Hans Peter Freyther
cc41cb07e7 [bssap] More brown paper... Make variables really signed
-1 is assigned in case the variables are not set. This means
it must be a signed type (as the comment says), now really use
a signed type.
2010-01-07 14:52:35 +01:00
Holger Hans Peter Freyther
d6fb23523a [bssap] Fix brown paper bag... Keep the air id ...*sigh*
We want to use the real number on the Um... Using the core
network code is totally wrong in this scope...
2010-01-07 14:36:20 +01:00
Holger Hans Peter Freyther
2aa0b45cc0 [bssap] Allow to use a different country code too
* Be able to have a country code in the air but use a different
  country code when talking to the core network.
* Now both country and network code can be different on air and
  on the MSC communication.
2010-01-07 03:17:01 +01:00
Holger Hans Peter Freyther
619df61ad2 [rsl] Partial revert of the GSM speech mode for the nanoBTS
This is partially reverting 0603c9d9e5,
it is true that the ip.access Wireshark dissectors differentiate
TCH/H from TCH/F but in my test I'm unable to send RTP on to the
BTS. It might be that the RTP payload provided in the MDCX is not
the one it will accept with the 0x05 mode. More work needs to be
done to understand this, that is the reason it is comitted to the
on-waves's branch instead of master.
2010-01-06 11:44:26 +01:00
Holger Hans Peter Freyther
893ea65f38 [bsc_msc_ip] Turn the MNC hack into a config option
* Make it possible to have a different MNC in the RSL traffic
  than in the core network.
* Introduce the "core network code NUMBER" variable. If it is
  set this network code will be used in traffic with the MSC.
* Use the core_network_code number when sending a packet to
  the MSC
* Regenerate the LAI (this is where I could have a bug) when
  sending packets to the BTS.
* Add size checks.

This is not tested, I might got something wrong.
2010-01-05 13:57:45 +01:00
Holger Hans Peter Freyther
64b811f113 [bsc_mgcp] Set the right remote rtp and rtcp port
* It is the same as local endpoint port
2010-01-05 12:35:16 +01:00
Holger Hans Peter Freyther
91fc9bf862 [bsc_mgcp] Fix writing of the config file...
* Add the new forward audio option
2010-01-05 12:29:36 +01:00
Holger Hans Peter Freyther
111a58dd37 [bsc_mgcp] Print a message which mode is configured 2010-01-05 12:25:25 +01:00
Holger Hans Peter Freyther
d1a2563a74 [bsc_mgcp] Add a new forward only mode to the bsc_mgcp
With forward IP in the config and early bind on we will
simply forward RTP data on the endpoints from BTS to the
forward IP address.

This is implemented by disabling MGCP functionality when
a forward IP address was specified, setting the forward IP
in the endp->remote and assigning a ci != CI_UNUSED.

Early bind will make sure the sockets are created, the BSC FD's
are registered and then the normal dispatch code will
do the forwarding.
2010-01-05 12:21:36 +01:00
Holger Hans Peter Freyther
7d3ef919ce [bssap] Set the right GSM08.08 speech version indicator
* For half rate we also need to set the 3rd bit to one
* See GSM08.08 §3.2.2.51 and then §3.2.2.11
2010-01-05 04:18:16 +01:00
Holger Hans Peter Freyther
cba98d87d6 [misc] Move handover into libmsc.a
Handover is a high level decision, it can span multiple BSCs
and belongs mostly into the MSC domain.
2009-12-22 08:03:55 +01:00
Holger Hans Peter Freyther
5c18ad0829 Merge commit 'origin/master' into on-waves/bsc-master
Conflicts:
	openbsc/include/openbsc/Makefile.am
	openbsc/include/openbsc/gsm_data.h
	openbsc/src/Makefile.am
	openbsc/src/abis_rsl.c
	openbsc/src/chan_alloc.c
	openbsc/src/gsm_04_08.c
	openbsc/src/gsm_data.c
	openbsc/src/vty_interface.c

The biggest problem is the moving of the RTP code into
the RSL layer. This may break quite some things...
2009-12-22 08:02:13 +01:00
Holger Hans Peter Freyther
0d9ed87d5c [bsc_hack] Ignore the sigpipe...
We might read or write on the OML link when the BTS is
reset and will get SIGPIPE interrupt and be gone... Just
ignore the SIGPIPE we will get the "exception" on the next
run of bsc_select and kill the (old) OML link.
2009-12-06 04:32:27 +01:00
Harald Welte
ec7be0c969 move RTP socket information from timeslot to lchan
With ip.access, in case of TCH/H, we have one RTP stream for each half-slot
(lchan), not just one per on-air timeslot.  This is quite different from
a classic BTS where the TRAU frames of the two TCH/H channels would be
part of the same 16k sub-slot in a E1 timeslot.
2009-12-06 04:05:31 +01:00
Harald Welte
9be3347601 RSL: catch inconsistent parameters ofr channel_mode_from_lchan() 2009-12-06 04:03:55 +01:00
Harald Welte
3eef7b7d81 Assign default values for T3101 and T3113
Without those default values, old config files will no longer work
after commit 23975e718f
2009-12-06 04:03:23 +01:00
Holger Hans Peter Freyther
9de4a6daa9 Merge branch 'master' into on-waves/bsc-master
Conflicts:
	openbsc/src/abis_nm.c
	openbsc/src/bsc_init.c
	openbsc/src/vty_interface.c
2009-11-24 19:58:01 +01:00
Holger Hans Peter Freyther
851ace9f33 Merge branch 'master' into on-waves/bsc-master
Conflicts:
	openbsc/include/openbsc/Makefile.am
	openbsc/src/Makefile.am
2009-11-20 18:01:37 +01:00
Holger Hans Peter Freyther
d1dd069b48 [configure] Add onwaves to the version tag 2009-11-20 17:43:40 +01:00
Holger Hans Peter Freyther
401db32ca2 HACK patch the network code..
Report to the MSC with the right code and patch
it on the air...
2009-11-20 17:41:05 +01:00
Holger Hans Peter Freyther
17e03d21d2 [vty] Add option to disable RF on a given TRX.
- Make sure that on runtime the Radio Carrier can be
  locked and unlocked. The vty code calls into the
  Abis NM to lock/unlock the channel and the state is
  stored there.

- Make sure that on start the Radio Carries remains
  offline and we are not starting it. On start the
  radio carrier is either locked or unlocked. This means
  the RSL will not connect until the RF is unlocked. It
  will connect then. To see RSL bringup failures one
  needs to parse the RSL nack message.
2009-11-20 17:40:50 +01:00
Holger Hans Peter Freyther
26a9bff201 [bsc_init] Activate the RC and the RSL link from the Software Activated Callback
On cold start the RSL link will not be brought up. Wait for the
Software to be Activated before starting the RSL link. This is
working reliable on the BTS I have tested with.
2009-11-20 17:40:39 +01:00
Holger Hans Peter Freyther
80fb260a60 [lchan] Release the channel ones its' usecount drops to zero
Remove the timer handling from the LCHAN and release the
channel ones the use count is dropping to zero.

Change code that was sending/using the lchan after the
release and change the send data method to warn in case
the lchan is used after it has been freed.
2009-11-20 17:40:28 +01:00
Holger Hans Peter Freyther
55a0716da7 [bssap] Open a traffic channel for the paging any reason
In the case the MS is requesting a channel with the
paging any channel reason, use a TCH. This allows us
to keep using very early assignment and the SDCCHs are
kept free for location updating requests.
2009-11-20 17:40:00 +01:00
Holger Hans Peter Freyther
c88fb75616 [rsl] Speculative crash fix in the RSL rcv message
The theory is that the BTS is almost dead and sends out
a incomplete message and we crash with that. I have not
been able to completely verify that.
2009-11-20 17:38:47 +01:00
Holger Hans Peter Freyther
d55a4dc326 Merge branch 'on-waves/gsm0808' into on-waves/bsc-master 2009-11-20 17:38:02 +01:00
Holger Hans Peter Freyther
a4e6f2e6e1 [bssap] Support multiple multiplexers in the assignment command
When more than one trunk group is allocated to the BSC the
MSC will start to assign channels from the different multiplexer.

We will map them the following way onto MGCP endpoints

Multiplex 0:
   0	->	1
   1	->      signalling
   2	->	2
   ..	->	..
   16	->	signalling (might be 15)
   30	->	30

Multiplex 1:
   0	->	31
   2	->	32
...

Multiplex 3:
..
2009-11-20 17:35:47 +01:00
Holger Hans Peter Freyther
7f71d99cc3 [bsc] Add a rtp base port to the BSC config too
Stop having a global variable... keep it in the
gsm network or the mgcp
2009-11-20 17:35:47 +01:00
Holger Hans Peter Freyther
b92167cf80 [vty] Write out BSC specific network parameters too 2009-11-20 17:35:47 +01:00
Holger Hans Peter Freyther
4b6a6dbe7e [bssap] Cope with weird channel mapping on the network side
The timeslot of the network maps the following way
	0	->	1
	1	->	n/a
	2	->	2
	...	->      ...
	31	->	31
2009-11-20 17:35:47 +01:00
Holger Hans Peter Freyther
763e8c7766 [ipacc] Add a way to override the rtp payload for MDCX 2009-11-20 17:35:46 +01:00
Holger Hans Peter Freyther
823ff16088 [bsc] Send the SCCP IT message in a given interval
Send the message every 60 seconds on every SCCP
connection. The 60 seconds were taken from a protocol
trace obtained on the network.
2009-11-20 17:35:46 +01:00
Holger Hans Peter Freyther
6f93c6a1e0 [bsc] Unref the lchan when the MSC is closing the SCCP connection
Currently we are not sending the Inactivity Test message so the
MSC will close the specific sccp connection but we would keep the
lchan open and then end up with resource issues.

Change the code to close the lchan before closing the SCCP connection..
2009-11-20 17:35:46 +01:00
Holger Hans Peter Freyther
f97e48b0de [bssap] Send multirate config for HR AMR with 5.9k
Send a hardcoded multirate config when usin the
AMR codec. This should be more configurable in
the future.
2009-11-20 17:35:46 +01:00
Holger Hans Peter Freyther
761600b0fd [bsc] Add a test_mode function that can be used to inject packages
This method can be called from the main method to inject
a test message into a "fake" network with sccp connection.
2009-11-20 17:35:46 +01:00
Holger Hans Peter Freyther
8549462bc6 [bssap] Attempt to allow selecting the speech mode from config
It is possible to specify a list of possible speech codecs
and we will try to match the assignment command with the
one from the config file. This is not tested yet and we have
one problem. We assume we can modify the channel to hold
the speech value... this will require more work.
2009-11-20 17:35:46 +01:00
Holger Hans Peter Freyther
436e5c6308 [vty] Add configuration for the preferred speech version
Add network configuration option to specify which audio
codecs are supported by the BTS. This allows the BSC to
pick the audio codec in the GSM0808 Assignment Request.
2009-11-20 17:35:46 +01:00
Holger Hans Peter Freyther
f8b9d844c1 [bssap] Pick the A5/0 vs A5/1 setting from the gsm_network
Follow the configuration of the gsm network. If the Cipher
Mode Request does not allow our preferred format we will
reject it. Otherwise send the cipher mode command to the
mobile station. This code is mostly untested.
2009-11-20 17:35:46 +01:00
Holger Hans Peter Freyther
58ec07d580 [bsc] Add BSC specific config option... currently and empty show is implemented
In the future this should give a list of SCCP connections
and their allocated radio resources/users...
2009-11-20 17:35:46 +01:00
Holger Hans Peter Freyther
71465c21f4 [bssap] Implement generating a classmark update message
Generate a classmark update message from a given payload
this might need to be changed to get the version2 and
version3 parameters
2009-11-20 17:35:46 +01:00
Holger Hans Peter Freyther
16d0a833f8 [bssmap] Fix the chosen encryption in assignment complete
Send the RSL value... it is the right value
2009-11-20 17:35:46 +01:00
Holger Hans Peter Freyther
ea72b62cac [bssmap] Unconditionally include the chosen encryption in cipher mode complete 2009-11-20 17:35:45 +01:00
Holger Hans Peter Freyther
49a84ec6e9 [bssmap] Assignment handling fixes and improvements
- Fix the generation of the assignment failure message
- Parse the permitted indicator of the assignment request message
2009-11-20 17:35:45 +01:00
Holger Hans Peter Freyther
42c636b6c8 [bssap] Fix generation of the failure message 2009-11-20 17:35:45 +01:00
Holger Hans Peter Freyther
a0a55f555e [bssap] Only start establish when the link is not yet established
This is fixing a bug when we try to submit a SMS from the MS to
the network. We send the RLS ESTABLISH REQUEST but as the MS
already established this SAPI we waited for the timeout and failed..
2009-11-20 17:35:45 +01:00
Holger Hans Peter Freyther
23ed00e410 [bssap] Improve log messages... 2009-11-20 17:35:45 +01:00
Holger Hans Peter Freyther
3fe910b9f1 [bssap] First go at implementing channel assignment... 2009-11-20 17:35:45 +01:00
Holger Hans Peter Freyther
097bdeb77d [bssap] First go at implementing ASSIGNMENT REQUEST 2009-11-20 17:35:45 +01:00
Holger Hans Peter Freyther
1b85de02e0 [bssap] Add a "#warning" that cipher mode is not properly handled 2009-11-20 17:35:45 +01:00
Holger Hans Peter Freyther
2281d1835f [bssap] Start to queue messages to the BTS and to the MSC
For the MSC we need to queue GSM04.08 messages until the
SCCP connection is  confirmed to be open and then can send
the stored messages. The queue is limited to 10 messages
at which point new ones will be dropped. Currently the
only messages we get are measurement indication messages
but it is better to be safe than sorry.

The SCCP messages are sent as soon as the connection
is considered established and then no queueing happens
any more. While replacing sccp_connection_write calls
various memory leaks has been fixed.

For the MS we might have received a DTAP and need to do
an operation that requires a roundtrip and want to send
wait until this has happened. The two scenerios are sending
a SMS to the phone that requires to do something special
for the different SAPI. Currently it is assumed that
only one SAPI=0 -> SAPI=3 change happen during the connection.

For the first SAPI != 0 we will send the rll_ request
and then wait for the timeout or confirmation. In case
of timeout a SAPI "n" reject is sent and in case of
success the queue is getting emptied.
2009-11-20 17:35:45 +01:00
Holger Hans Peter Freyther
fb4433a129 [bssap] Implement SAPI "N" Reject message
This message will be needed when no RLL connection
on a different SAPI can be established or we don't
want to establish it.
2009-11-20 17:35:45 +01:00
Holger Hans Peter Freyther
d954dcf9e1 [bsc_msc_ip] This is a BSC that connects to real MSC via IP
This is a BSC to be used by on-waves.com to connect to a real
MSC using SCCP over IP.

The following messages and features are currently implemented:
    - IPA identity ack's
    - COMPLETE LAYER3 INFORMATION
    - DTAP
    - PAGING COMMAND
    - CLEAR COMPLETE/CLEAR REQUEST
    - CIPHER MODE COMMAND/ REJECT /COMPLETE

It comes with a tool to create the enum's from the spec and
a very simple test server to do the handshaking.
2009-11-20 17:35:45 +01:00
40 changed files with 3724 additions and 250 deletions

View File

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

2
openbsc/contrib/README Normal file
View File

@@ -0,0 +1,2 @@
This contains a set of scripts used for the development of the
MSC functionality.

View File

@@ -0,0 +1,30 @@
#!/usr/bin/env python
import sys
# packages
ACK ="\x00\x01\xfe\x06"
RESET_ACK = "\x00\x13\xfd\x09\x00\x03\x07\x0b\x04\x43\x01\x00\xfe\x04\x43\x5c\x00\xfe\x03\x00\x01\x31"
PAGE = "\x00\x20\xfd\x09\x00\x03\x07\x0b\x04\x43\x01\x00\xfe\x04\x43\x5c\x00\xfe\x10\x00\x0e\x52\x08\x08\x29\x42\x08\x05\x03\x12\x23\x42\x1a\x01\x06"
# simple handshake...
sys.stdout.write(ACK)
sys.stdout.flush()
sys.stdin.read(4)
# wait for some data and send reset ack
sys.stdin.read(21)
sys.stdout.write(RESET_ACK)
sys.stdout.flush()
sys.stdout.write(RESET_ACK)
sys.stdout.flush()
# page a subscriber
sys.stdout.write(PAGE)
sys.stdout.flush()
while True:
sys.stdin.read(1)

View File

@@ -5,4 +5,4 @@ noinst_HEADERS = abis_nm.h abis_rsl.h debug.h db.h gsm_04_08.h gsm_data.h \
gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \ gsm_utils.h ipaccess.h rs232.h openbscdefines.h rtp_proxy.h \
bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h \ bsc_rll.h mncc.h talloc.h transaction.h ussd.h gsm_04_80.h \
silent_call.h mgcp.h meas_rep.h bitvec.h rest_octets.h \ silent_call.h mgcp.h meas_rep.h bitvec.h rest_octets.h \
system_information.h handover.h system_information.h handover.h bssap.h bsc_msc.h bsc_nat.h

View File

@@ -0,0 +1,30 @@
/* Routines to talk to the MSC using the IPA Protocol */
/*
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010 by on-waves.com
* 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.
*
*/
#ifndef BSC_MSC_H
#define BSC_MSC_H
#include "select.h"
int connect_to_msc(struct bsc_fd *fd, const char *ip, int port);
#endif

View File

@@ -0,0 +1,33 @@
/*
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010 by on-waves.com
* 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.
*
*/
#ifndef BSC_NAT_H
#define BSC_NAT_H
#include <sys/types.h>
#include "msgb.h"
/**
* filter based on IP Access header in both directions
*/
int bsc_nat_filter_ipa(struct msgb *msg);
#endif

View File

@@ -0,0 +1,334 @@
/* From GSM08.08 */
#ifndef BSSAP_H
#define BSSAP_H
#include <stdlib.h>
#include <openbsc/msgb.h>
#include <openbsc/gsm_data.h>
/*
* this is from GSM 03.03 CGI but is copied in GSM 08.08
* in § 3.2.2.27 for Cell Identifier List
*/
enum CELL_IDENT {
CELL_IDENT_WHOLE_GLOBAL = 0,
CELL_IDENT_LAC_AND_CI = 1,
CELL_IDENT_CI = 2,
CELL_IDENT_NO_CELL = 3,
CELL_IDENT_LAI_AND_LAC = 4,
CELL_IDENT_LAC = 5,
CELL_IDENT_BSS = 6,
CELL_IDENT_UTRAN_PLMN_LAC_RNC = 8,
CELL_IDENT_UTRAN_RNC = 9,
CELL_IDENT_UTRAN_LAC_RNC = 10,
};
/* GSM 08.06 § 6.3 */
enum BSSAP_MSG_TYPE {
BSSAP_MSG_BSS_MANAGEMENT = 0x0,
BSSAP_MSG_DTAP = 0x1,
};
struct bssmap_header {
u_int8_t type;
u_int8_t length;
} __attribute__((packed));
struct dtap_header {
u_int8_t type;
u_int8_t link_id;
u_int8_t length;
} __attribute__((packed));
enum BSS_MAP_MSG_TYPE {
BSS_MAP_MSG_RESERVED_0 = 0,
/* ASSIGNMENT MESSAGES */
BSS_MAP_MSG_ASSIGMENT_RQST = 1,
BSS_MAP_MSG_ASSIGMENT_COMPLETE = 2,
BSS_MAP_MSG_ASSIGMENT_FAILURE = 3,
/* HANDOVER MESSAGES */
BSS_MAP_MSG_HANDOVER_RQST = 16,
BSS_MAP_MSG_HANDOVER_REQUIRED = 17,
BSS_MAP_MSG_HANDOVER_RQST_ACKNOWLEDGE= 18,
BSS_MAP_MSG_HANDOVER_CMD = 19,
BSS_MAP_MSG_HANDOVER_COMPLETE = 20,
BSS_MAP_MSG_HANDOVER_SUCCEEDED = 21,
BSS_MAP_MSG_HANDOVER_FAILURE = 22,
BSS_MAP_MSG_HANDOVER_PERFORMED = 23,
BSS_MAP_MSG_HANDOVER_CANDIDATE_ENQUIRE = 24,
BSS_MAP_MSG_HANDOVER_CANDIDATE_RESPONSE = 25,
BSS_MAP_MSG_HANDOVER_REQUIRED_REJECT = 26,
BSS_MAP_MSG_HANDOVER_DETECT = 27,
/* RELEASE MESSAGES */
BSS_MAP_MSG_CLEAR_CMD = 32,
BSS_MAP_MSG_CLEAR_COMPLETE = 33,
BSS_MAP_MSG_CLEAR_RQST = 34,
BSS_MAP_MSG_RESERVED_1 = 35,
BSS_MAP_MSG_RESERVED_2 = 36,
BSS_MAP_MSG_SAPI_N_REJECT = 37,
BSS_MAP_MSG_CONFUSION = 38,
/* OTHER CONNECTION RELATED MESSAGES */
BSS_MAP_MSG_SUSPEND = 40,
BSS_MAP_MSG_RESUME = 41,
BSS_MAP_MSG_CONNECTION_ORIENTED_INFORMATION = 42,
BSS_MAP_MSG_PERFORM_LOCATION_RQST = 43,
BSS_MAP_MSG_LSA_INFORMATION = 44,
BSS_MAP_MSG_PERFORM_LOCATION_RESPONSE = 45,
BSS_MAP_MSG_PERFORM_LOCATION_ABORT = 46,
BSS_MAP_MSG_COMMON_ID = 47,
/* GENERAL MESSAGES */
BSS_MAP_MSG_RESET = 48,
BSS_MAP_MSG_RESET_ACKNOWLEDGE = 49,
BSS_MAP_MSG_OVERLOAD = 50,
BSS_MAP_MSG_RESERVED_3 = 51,
BSS_MAP_MSG_RESET_CIRCUIT = 52,
BSS_MAP_MSG_RESET_CIRCUIT_ACKNOWLEDGE = 53,
BSS_MAP_MSG_MSC_INVOKE_TRACE = 54,
BSS_MAP_MSG_BSS_INVOKE_TRACE = 55,
BSS_MAP_MSG_CONNECTIONLESS_INFORMATION = 58,
/* TERRESTRIAL RESOURCE MESSAGES */
BSS_MAP_MSG_BLOCK = 64,
BSS_MAP_MSG_BLOCKING_ACKNOWLEDGE = 65,
BSS_MAP_MSG_UNBLOCK = 66,
BSS_MAP_MSG_UNBLOCKING_ACKNOWLEDGE = 67,
BSS_MAP_MSG_CIRCUIT_GROUP_BLOCK = 68,
BSS_MAP_MSG_CIRCUIT_GROUP_BLOCKING_ACKNOWLEDGE = 69,
BSS_MAP_MSG_CIRCUIT_GROUP_UNBLOCK = 70,
BSS_MAP_MSG_CIRCUIT_GROUP_UNBLOCKING_ACKNOWLEDGE = 71,
BSS_MAP_MSG_UNEQUIPPED_CIRCUIT = 72,
BSS_MAP_MSG_CHANGE_CIRCUIT = 78,
BSS_MAP_MSG_CHANGE_CIRCUIT_ACKNOWLEDGE = 79,
/* RADIO RESOURCE MESSAGES */
BSS_MAP_MSG_RESOURCE_RQST = 80,
BSS_MAP_MSG_RESOURCE_INDICATION = 81,
BSS_MAP_MSG_PAGING = 82,
BSS_MAP_MSG_CIPHER_MODE_CMD = 83,
BSS_MAP_MSG_CLASSMARK_UPDATE = 84,
BSS_MAP_MSG_CIPHER_MODE_COMPLETE = 85,
BSS_MAP_MSG_QUEUING_INDICATION = 86,
BSS_MAP_MSG_COMPLETE_LAYER_3 = 87,
BSS_MAP_MSG_CLASSMARK_RQST = 88,
BSS_MAP_MSG_CIPHER_MODE_REJECT = 89,
BSS_MAP_MSG_LOAD_INDICATION = 90,
/* VGCS/VBS */
BSS_MAP_MSG_VGCS_VBS_SETUP = 4,
BSS_MAP_MSG_VGCS_VBS_SETUP_ACK = 5,
BSS_MAP_MSG_VGCS_VBS_SETUP_REFUSE = 6,
BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RQST = 7,
BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_RESULT = 28,
BSS_MAP_MSG_VGCS_VBS_ASSIGNMENT_FAILURE = 29,
BSS_MAP_MSG_VGCS_VBS_QUEUING_INDICATION = 30,
BSS_MAP_MSG_UPLINK_RQST = 31,
BSS_MAP_MSG_UPLINK_RQST_ACKNOWLEDGE = 39,
BSS_MAP_MSG_UPLINK_RQST_CONFIRMATION = 73,
BSS_MAP_MSG_UPLINK_RELEASE_INDICATION = 74,
BSS_MAP_MSG_UPLINK_REJECT_CMD = 75,
BSS_MAP_MSG_UPLINK_RELEASE_CMD = 76,
BSS_MAP_MSG_UPLINK_SEIZED_CMD = 77,
};
enum GSM0808_IE_CODING {
GSM0808_IE_CIRCUIT_IDENTITY_CODE = 1,
GSM0808_IE_RESERVED_0 = 2,
GSM0808_IE_RESOURCE_AVAILABLE = 3,
GSM0808_IE_CAUSE = 4,
GSM0808_IE_CELL_IDENTIFIER = 5,
GSM0808_IE_PRIORITY = 6,
GSM0808_IE_LAYER_3_HEADER_INFORMATION = 7,
GSM0808_IE_IMSI = 8,
GSM0808_IE_TMSI = 9,
GSM0808_IE_ENCRYPTION_INFORMATION = 10,
GSM0808_IE_CHANNEL_TYPE = 11,
GSM0808_IE_PERIODICITY = 12,
GSM0808_IE_EXTENDED_RESOURCE_INDICATOR = 13,
GSM0808_IE_NUMBER_OF_MSS = 14,
GSM0808_IE_RESERVED_1 = 15,
GSM0808_IE_RESERVED_2 = 16,
GSM0808_IE_RESERVED_3 = 17,
GSM0808_IE_CLASSMARK_INFORMATION_T2 = 18,
GSM0808_IE_CLASSMARK_INFORMATION_T3 = 19,
GSM0808_IE_INTERFERENCE_BAND_TO_USE = 20,
GSM0808_IE_RR_CAUSE = 21,
GSM0808_IE_RESERVED_4 = 22,
GSM0808_IE_LAYER_3_INFORMATION = 23,
GSM0808_IE_DLCI = 24,
GSM0808_IE_DOWNLINK_DTX_FLAG = 25,
GSM0808_IE_CELL_IDENTIFIER_LIST = 26,
GSM0808_IE_RESPONSE_RQST = 27,
GSM0808_IE_RESOURCE_INDICATION_METHOD = 28,
GSM0808_IE_CLASSMARK_INFORMATION_TYPE_1 = 29,
GSM0808_IE_CIRCUIT_IDENTITY_CODE_LIST = 30,
GSM0808_IE_DIAGNOSTIC = 31,
GSM0808_IE_LAYER_3_MESSAGE_CONTENTS = 32,
GSM0808_IE_CHOSEN_CHANNEL = 33,
GSM0808_IE_TOTAL_RESOURCE_ACCESSIBLE = 34,
GSM0808_IE_CIPHER_RESPONSE_MODE = 35,
GSM0808_IE_CHANNEL_NEEDED = 36,
GSM0808_IE_TRACE_TYPE = 37,
GSM0808_IE_TRIGGERID = 38,
GSM0808_IE_TRACE_REFERENCE = 39,
GSM0808_IE_TRANSACTIONID = 40,
GSM0808_IE_MOBILE_IDENTITY = 41,
GSM0808_IE_OMCID = 42,
GSM0808_IE_FORWARD_INDICATOR = 43,
GSM0808_IE_CHOSEN_ENCR_ALG = 44,
GSM0808_IE_CIRCUIT_POOL = 45,
GSM0808_IE_CIRCUIT_POOL_LIST = 46,
GSM0808_IE_TIME_INDICATION = 47,
GSM0808_IE_RESOURCE_SITUATION = 48,
GSM0808_IE_CURRENT_CHANNEL_TYPE_1 = 49,
GSM0808_IE_QUEUEING_INDICATOR = 50,
GSM0808_IE_SPEECH_VERSION = 64,
GSM0808_IE_ASSIGNMENT_REQUIREMENT = 51,
GSM0808_IE_TALKER_FLAG = 53,
GSM0808_IE_CONNECTION_RELEASE_RQSTED = 54,
GSM0808_IE_GROUP_CALL_REFERENCE = 55,
GSM0808_IE_EMLPP_PRIORITY = 56,
GSM0808_IE_CONFIG_EVO_INDI = 57,
GSM0808_IE_OLD_BSS_TO_NEW_BSS_INFORMATION = 58,
GSM0808_IE_LSA_IDENTIFIER = 59,
GSM0808_IE_LSA_IDENTIFIER_LIST = 60,
GSM0808_IE_LSA_INFORMATION = 61,
GSM0808_IE_LCS_QOS = 62,
GSM0808_IE_LSA_ACCESS_CTRL_SUPPR = 63,
GSM0808_IE_LCS_PRIORITY = 67,
GSM0808_IE_LOCATION_TYPE = 68,
GSM0808_IE_LOCATION_ESTIMATE = 69,
GSM0808_IE_POSITIONING_DATA = 70,
GSM0808_IE_LCS_CAUSE = 71,
GSM0808_IE_LCS_CLIENT_TYPE = 72,
GSM0808_IE_APDU = 73,
GSM0808_IE_NETWORK_ELEMENT_IDENTITY = 74,
GSM0808_IE_GPS_ASSISTANCE_DATA = 75,
GSM0808_IE_DECIPHERING_KEYS = 76,
GSM0808_IE_RETURN_ERROR_RQST = 77,
GSM0808_IE_RETURN_ERROR_CAUSE = 78,
GSM0808_IE_SEGMENTATION = 79,
GSM0808_IE_SERVICE_HANDOVER = 80,
GSM0808_IE_SOURCE_RNC_TO_TARGET_RNC_TRANSPARENT_UMTS = 81,
GSM0808_IE_SOURCE_RNC_TO_TARGET_RNC_TRANSPARENT_CDMA2000= 82,
GSM0808_IE_RESERVED_5 = 65,
GSM0808_IE_RESERVED_6 = 66,
};
enum gsm0808_cause {
GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE = 0,
GSM0808_CAUSE_RADIO_INTERFACE_FAILURE = 1,
GSM0808_CAUSE_UPLINK_QUALITY = 2,
GSM0808_CAUSE_UPLINK_STRENGTH = 3,
GSM0808_CAUSE_DOWNLINK_QUALITY = 4,
GSM0808_CAUSE_DOWNLINK_STRENGTH = 5,
GSM0808_CAUSE_DISTANCE = 6,
GSM0808_CAUSE_O_AND_M_INTERVENTION = 7,
GSM0808_CAUSE_RESPONSE_TO_MSC_INVOCATION = 8,
GSM0808_CAUSE_CALL_CONTROL = 9,
GSM0808_CAUSE_RADIO_INTERFACE_FAILURE_REVERSION = 10,
GSM0808_CAUSE_HANDOVER_SUCCESSFUL = 11,
GSM0808_CAUSE_BETTER_CELL = 12,
GSM0808_CAUSE_DIRECTED_RETRY = 13,
GSM0808_CAUSE_JOINED_GROUP_CALL_CHANNEL = 14,
GSM0808_CAUSE_TRAFFIC = 15,
GSM0808_CAUSE_EQUIPMENT_FAILURE = 32,
GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE = 33,
GSM0808_CAUSE_RQSTED_TERRESTRIAL_RESOURCE_UNAVAILABLE = 34,
GSM0808_CAUSE_CCCH_OVERLOAD = 35,
GSM0808_CAUSE_PROCESSOR_OVERLOAD = 36,
GSM0808_CAUSE_BSS_NOT_EQUIPPED = 37,
GSM0808_CAUSE_MS_NOT_EQUIPPED = 38,
GSM0808_CAUSE_INVALID_CELL = 39,
GSM0808_CAUSE_TRAFFIC_LOAD = 40,
GSM0808_CAUSE_PREEMPTION = 41,
GSM0808_CAUSE_RQSTED_TRANSCODING_RATE_ADAPTION_UNAVAILABLE = 48,
GSM0808_CAUSE_CIRCUIT_POOL_MISMATCH = 49,
GSM0808_CAUSE_SWITCH_CIRCUIT_POOL = 50,
GSM0808_CAUSE_RQSTED_SPEECH_VERSION_UNAVAILABLE = 51,
GSM0808_CAUSE_LSA_NOT_ALLOWED = 52,
GSM0808_CAUSE_CIPHERING_ALGORITHM_NOT_SUPPORTED = 64,
GSM0808_CAUSE_TERRESTRIAL_CIRCUIT_ALREADY_ALLOCATED = 80,
GSM0808_CAUSE_INVALID_MESSAGE_CONTENTS = 81,
GSM0808_CAUSE_INFORMATION_ELEMENT_OR_FIELD_MISSING = 82,
GSM0808_CAUSE_INCORRECT_VALUE = 83,
GSM0808_CAUSE_UNKNOWN_MESSAGE_TYPE = 84,
GSM0808_CAUSE_UNKNOWN_INFORMATION_ELEMENT = 85,
GSM0808_CAUSE_PROTOCOL_ERROR_BETWEEN_BSS_AND_MSC = 96,
};
/* GSM 08.08 3.2.2.11 Channel Type */
enum gsm0808_chan_indicator {
GSM0808_CHAN_SPEECH = 1,
GSM0808_CHAN_DATA = 2,
GSM0808_CHAN_SIGN = 3,
};
enum gsm0808_chan_rate_type_data {
GSM0808_DATA_FULL_BM = 0x8,
GSM0808_DATA_HALF_LM = 0x9,
GSM0808_DATA_FULL_RPREF = 0xa,
GSM0808_DATA_HALF_PREF = 0xb,
GSM0808_DATA_FULL_PREF_NO_CHANGE = 0x1a,
GSM0808_DATA_HALF_PREF_NO_CHANGE = 0x1b,
GSM0808_DATA_MULTI_MASK = 0x20,
GSM0808_DATA_MULTI_MASK_NO_CHANGE = 0x30,
};
enum gsm0808_chan_rate_type_speech {
GSM0808_SPEECH_FULL_BM = 0x8,
GSM0808_SPEECH_HALF_LM = 0x9,
GSM0808_SPEECH_FULL_PREF= 0xa,
GSM0808_SPEECH_HALF_PREF= 0xb,
GSM0808_SPEECH_FULL_PREF_NO_CHANGE = 0x1a,
GSM0808_SPEECH_HALF_PREF_NO_CHANGE = 0x1b,
GSM0808_SPEECH_PERM = 0xf,
GSM0808_SPEECH_PERM_NO_CHANGE = 0x1f,
};
enum gsm0808_permitted_speech {
GSM0808_PERM_FR1 = 0x01,
GSM0808_PERM_FR2 = 0x11,
GSM0808_PERM_FR3 = 0x21,
GSM0808_PERM_HR1 = GSM0808_PERM_FR1 | 0x4,
GSM0808_PERM_HR2 = GSM0808_PERM_FR2 | 0x4,
GSM0808_PERM_HR3 = GSM0808_PERM_FR3 | 0x4,
};
int bssmap_rcvmsg_dt1(struct sccp_connection *conn, struct msgb *msg, unsigned int length);
int bssmap_rcvmsg_udt(struct gsm_network *net, struct msgb *msg, unsigned int length);
struct msgb *bssmap_create_layer3(struct msgb *msg);
struct msgb *bssmap_create_reset(void);
struct msgb *bssmap_create_clear_complete(void);
struct msgb *bssmap_create_cipher_complete(struct msgb *layer3);
struct msgb *bssmap_create_cipher_reject(u_int8_t cause);
struct msgb *bssmap_create_sapi_reject(u_int8_t link_id);
struct msgb *bssmap_create_assignment_completed(struct gsm_lchan *lchan, u_int8_t rr_cause);
struct msgb *bssmap_create_assignment_failure(u_int8_t cause, u_int8_t *rr_cause);
struct msgb *bssmap_create_classmark_update(const u_int8_t *classmark, u_int8_t length);
void gsm0808_send_assignment_failure(struct gsm_lchan *l, u_int8_t cause, u_int8_t *rr_value);
void gsm0808_send_assignment_compl(struct gsm_lchan *l, u_int8_t rr_value);
int dtap_rcvmsg(struct gsm_lchan *lchan, struct msgb *msg, unsigned int length);
struct msgb *dtap_create_msg(struct msgb *msg_l3, u_int8_t link_id);
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*);
#endif

View File

@@ -23,6 +23,28 @@
#include "gsm_subscriber.h" #include "gsm_subscriber.h"
/*
* Refcounting for the lchan. If the refcount drops to zero
* the channel will send a RSL release request.
*/
#define use_lchan(lchan) \
do { lchan->use_count++; \
DEBUGP(DCC, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) increases usage to: %d\n", \
lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, \
lchan->nr, lchan->use_count); \
} while(0);
#define put_lchan(lchan) \
do { lchan->use_count--; \
DEBUGP(DCC, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) decreases usage to: %d\n", \
lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, \
lchan->nr, lchan->use_count); \
if (lchan->use_count <= 0) \
_lchan_release(lchan); \
} while(0);
/* Special allocator for C0 of BTS */ /* Special allocator for C0 of BTS */
struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts, struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts,
enum gsm_phys_chan_config pchan); enum gsm_phys_chan_config pchan);
@@ -46,7 +68,7 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type);
/* Free a logical channel (SDCCH, TCH, ...) */ /* Free a logical channel (SDCCH, TCH, ...) */
void lchan_free(struct gsm_lchan *lchan); void lchan_free(struct gsm_lchan *lchan);
/* Consider releasing the channel */ /* internal.. do not use */
int lchan_auto_release(struct gsm_lchan *lchan); int _lchan_release(struct gsm_lchan *lchan);
#endif /* _CHAN_ALLOC_H */ #endif /* _CHAN_ALLOC_H */

View File

@@ -768,7 +768,7 @@ int gsm48_send_rr_release(struct gsm_lchan *lchan);
int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv); int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv);
int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id, int gsm48_send_rr_app_info(struct gsm_lchan *lchan, u_int8_t apdu_id,
u_int8_t apdu_len, const u_int8_t *apdu); u_int8_t apdu_len, const u_int8_t *apdu);
int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_class); int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, u_int8_t power_class);
int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan, int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan,
u_int8_t power_command, u_int8_t ho_ref); u_int8_t power_command, u_int8_t ho_ref);

View File

@@ -93,36 +93,51 @@ typedef int gsm_cbfn(unsigned int hooknum,
struct msgb *msg, struct msgb *msg,
void *data, void *param); void *data, void *param);
/*
* Use the channel. As side effect the lchannel recycle timer
* will be started.
*/
#define LCHAN_RELEASE_TIMEOUT 20, 0
#define use_lchan(lchan) \
do { lchan->use_count++; \
DEBUGP(DCC, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) increases usage to: %d\n", \
lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, \
lchan->nr, lchan->use_count); \
bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT); } while(0);
#define put_lchan(lchan) \
do { lchan->use_count--; \
DEBUGP(DCC, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) decreases usage to: %d\n", \
lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr, \
lchan->nr, lchan->use_count); \
} while(0);
/* communications link with a BTS */ /* communications link with a BTS */
struct gsm_bts_link { struct gsm_bts_link {
struct gsm_bts *bts; struct gsm_bts *bts;
}; };
struct sccp_connection;
struct gsm_lchan; struct gsm_lchan;
struct gsm_subscriber; struct gsm_subscriber;
struct gsm_mncc; struct gsm_mncc;
struct rtp_socket; struct rtp_socket;
/* BSC/MSC data holding them together */
struct bss_sccp_connection_data {
struct gsm_lchan *lchan;
struct gsm_lchan *secondary_lchan;
struct sccp_connection *sccp;
int ciphering_handled : 1;
/* Timers... */
/* for assginment command */
struct timer_list T10;
/* for SCCP ... */
struct timer_list sccp_it;
/* audio handling */
int rtp_port;
/* Queue SCCP and GSM0408 messages */
int block_gsm;
struct llist_head gsm_queue;
unsigned int gsm_queue_size;
struct llist_head sccp_queue;
unsigned int sccp_queue_size;
};
#define GSM0808_T10_VALUE 6, 0
#define sccp_get_lchan(data_ctx) ((struct bss_sccp_connection_data *)data_ctx)->lchan
#define lchan_get_sccp(lchan) lchan->msc_data->sccp
struct bss_sccp_connection_data *bss_sccp_create_data();
void bss_sccp_free_data(struct bss_sccp_connection_data *);
/* Network Management State */ /* Network Management State */
struct gsm_nm_state { struct gsm_nm_state {
u_int8_t operational; u_int8_t operational;
@@ -201,9 +216,6 @@ struct gsm_lchan {
/* To whom we are allocated at the moment */ /* To whom we are allocated at the moment */
struct gsm_subscriber *subscr; struct gsm_subscriber *subscr;
/* Timer started to release the channel */
struct timer_list release_timer;
struct timer_list T3101; struct timer_list T3101;
/* Established data link layer services */ /* Established data link layer services */
@@ -214,6 +226,12 @@ struct gsm_lchan {
*/ */
struct gsm_loc_updating_operation *loc_operation; struct gsm_loc_updating_operation *loc_operation;
/*
* MSC handling...
*/
struct bss_sccp_connection_data *msc_data;
/* use count. how many users use this channel */ /* use count. how many users use this channel */
unsigned int use_count; unsigned int use_count;
@@ -509,6 +527,14 @@ enum gsm_auth_policy {
#define GSM_T3101_DEFAULT 10 #define GSM_T3101_DEFAULT 10
#define GSM_T3113_DEFAULT 60 #define GSM_T3113_DEFAULT 60
/*
* internal data for audio management
*/
struct gsm_audio_support {
u_int8_t hr : 1,
ver : 7;
};
struct gsm_network { struct gsm_network {
/* global parameters */ /* global parameters */
u_int16_t country_code; u_int16_t country_code;
@@ -539,6 +565,11 @@ struct gsm_network {
struct gsmnet_stats stats; struct gsmnet_stats stats;
struct gsm_audio_support **audio_support;
int audio_length;
int rtp_payload;
int rtp_base_port;
/* layer 4 */ /* layer 4 */
int (*mncc_recv) (struct gsm_network *net, int msg_type, void *arg); int (*mncc_recv) (struct gsm_network *net, int msg_type, void *arg);
struct llist_head upqueue; struct llist_head upqueue;
@@ -564,6 +595,10 @@ struct gsm_network {
struct { struct {
enum rrlp_mode mode; enum rrlp_mode mode;
} rrlp; } rrlp;
/* a hack for On Waves. It must be signed */
int32_t core_country_code;
int32_t core_network_code;
}; };
#define SMS_HDR_SIZE 128 #define SMS_HDR_SIZE 128

View File

@@ -81,6 +81,8 @@ struct gsm_subscriber *subscr_get_by_extension(struct gsm_network *net,
const char *ext); const char *ext);
struct gsm_subscriber *subscr_get_by_id(struct gsm_network *net, struct gsm_subscriber *subscr_get_by_id(struct gsm_network *net,
unsigned long long id); unsigned long long id);
struct gsm_subscriber *subscr_get_or_create(struct gsm_network *net,
const char *imsi);
int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason); int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason);
void subscr_put_channel(struct gsm_lchan *lchan); void subscr_put_channel(struct gsm_lchan *lchan);
void subscr_get_channel(struct gsm_subscriber *subscr, void subscr_get_channel(struct gsm_subscriber *subscr,

View File

@@ -44,5 +44,6 @@ int ipaccess_connect(struct e1inp_line *line, struct sockaddr_in *sa);
int ipaccess_rcvmsg_base(struct msgb *msg, struct bsc_fd *bfd); int ipaccess_rcvmsg_base(struct msgb *msg, struct bsc_fd *bfd);
struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error); struct msgb *ipaccess_read_msg(struct bsc_fd *bfd, int *error);
void ipaccess_prepend_header(struct msgb *msg, int proto); void ipaccess_prepend_header(struct msgb *msg, int proto);
int ipaccess_send_id_ack(int fd);
#endif /* _IPACCESS_H */ #endif /* _IPACCESS_H */

View File

@@ -21,8 +21,6 @@
* *
*/ */
unsigned int rtp_base_port = 4000;
/** /**
* Calculate the RTP audio port for the given multiplex * Calculate the RTP audio port for the given multiplex
* and the direction. This allows a semi static endpoint * and the direction. This allows a semi static endpoint

View File

@@ -37,6 +37,7 @@ struct msgb {
unsigned char *l2h; unsigned char *l2h;
unsigned char *l3h; unsigned char *l3h;
unsigned char *smsh; unsigned char *smsh;
unsigned char *l4h;
u_int16_t data_len; u_int16_t data_len;
u_int16_t len; u_int16_t len;
@@ -55,6 +56,7 @@ extern void msgb_reset(struct msgb *m);
#define msgb_l2(m) ((void *)(m->l2h)) #define msgb_l2(m) ((void *)(m->l2h))
#define msgb_l3(m) ((void *)(m->l3h)) #define msgb_l3(m) ((void *)(m->l3h))
#define msgb_l4(m) ((void *)(m->l4h))
#define msgb_sms(m) ((void *)(m->smsh)) #define msgb_sms(m) ((void *)(m->smsh))
static inline unsigned int msgb_l2len(const struct msgb *msgb) static inline unsigned int msgb_l2len(const struct msgb *msgb)

View File

@@ -1,7 +1,7 @@
/* /*
* SCCP management code * SCCP management code
* *
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org> * (C) 2009, 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* *
* All Rights Reserved * All Rights Reserved
* *
@@ -143,4 +143,25 @@ extern const struct sockaddr_sccp sccp_ssn_bssap;
u_int32_t sccp_src_ref_to_int(struct sccp_source_reference *ref); u_int32_t sccp_src_ref_to_int(struct sccp_source_reference *ref);
struct sccp_source_reference sccp_src_ref_from_int(u_int32_t); struct sccp_source_reference sccp_src_ref_from_int(u_int32_t);
/**
* Below this are helper functions and structs for parsing SCCP messages
*/
struct sccp_parse_result {
struct sccp_address called;
struct sccp_address calling;
/* point to the msg packet */
struct sccp_source_reference *source_local_reference;
struct sccp_source_reference *destination_local_reference;
/* data pointer */
int data_len;
};
/*
* helper functions for the nat code
*/
int sccp_determine_msg_type(struct msgb *msg);
int sccp_parse_header(struct msgb *msg, struct sccp_parse_result *result);
#endif #endif

View File

@@ -2,21 +2,22 @@ INCLUDES = $(all_includes) -I$(top_srcdir)/include
AM_CFLAGS=-Wall AM_CFLAGS=-Wall
sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \ sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config \
isdnsync bsc_mgcp isdnsync bsc_mgcp bsc_msc_ip bsc_nat
noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a noinst_LIBRARIES = libbsc.a libmsc.a libvty.a libsccp.a
noinst_HEADERS = vty/cardshell.h noinst_HEADERS = vty/cardshell.h
libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \ libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_data.c gsm_04_08_utils.c \
msgb.c select.c chan_alloc.c timer.c debug.c handover_logic.c \ msgb.c select.c chan_alloc.c timer.c debug.c \
gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \ gsm_subscriber_base.c subchan_demux.c bsc_rll.c transaction.c \
trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \ trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \
input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \ input/misdn.c input/ipaccess.c signal.c gsm_utils.c talloc.c \
talloc_ctx.c system_information.c bitvec.c rest_octets.c \ talloc_ctx.c system_information.c bitvec.c rest_octets.c \
handover_decision.c meas_rep.c rtp_proxy.c rtp_proxy.c telnet_interface.c
libmsc_a_SOURCES = gsm_subscriber.c db.c telnet_interface.c \ libmsc_a_SOURCES = gsm_subscriber.c db.c \
mncc.c gsm_04_08.c gsm_04_11.c transaction.c \ mncc.c gsm_04_08.c gsm_04_11.c transaction.c \
token_auth.c rrlp.c gsm_04_80.c ussd.c silent_call.c token_auth.c rrlp.c gsm_04_80.c ussd.c silent_call.c \
handover_logic.c handover_decision.c meas_rep.c
libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c
@@ -25,6 +26,10 @@ libsccp_a_SOURCES = sccp/sccp.c
bsc_hack_SOURCES = bsc_hack.c bsc_init.c vty_interface.c vty_interface_layer3.c bsc_hack_SOURCES = bsc_hack.c bsc_init.c vty_interface.c vty_interface_layer3.c
bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT) bsc_hack_LDADD = libmsc.a libbsc.a libmsc.a libvty.a -ldl -ldbi $(LIBCRYPT)
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_ip_LDADD = libbsc.a libvty.a libsccp.a
bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c \ bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c \
select.c timer.c rs232.c tlv_parser.c signal.c talloc.c select.c timer.c rs232.c tlv_parser.c signal.c talloc.c
@@ -37,3 +42,6 @@ isdnsync_SOURCES = isdnsync.c
bsc_mgcp_SOURCES = bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c bsc_mgcp_SOURCES = bsc_mgcp.c msgb.c talloc.c debug.c select.c timer.c telnet_interface.c
bsc_mgcp_LDADD = libvty.a bsc_mgcp_LDADD = libvty.a
bsc_nat_SOURCES = nat/bsc_nat.c nat/bsc_filter.c bsc_msc.c
bsc_nat_LDADD = libbsc.a libsccp.a

View File

@@ -630,6 +630,10 @@ int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type,
msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power); msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power);
msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta); msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
msgb_tlv_put(msg, RSL_IE_MR_CONFIG, sizeof(lchan->mr_conf),
(u_int8_t *) &lchan->mr_conf);
msg->trx = lchan->ts->trx; msg->trx = lchan->ts->trx;
return abis_rsl_sendmsg(msg); return abis_rsl_sendmsg(msg);
@@ -853,6 +857,10 @@ int rsl_data_request(struct msgb *msg, u_int8_t link_id)
return -EINVAL; return -EINVAL;
} }
if (msg->lchan->use_count <= 0) {
DEBUGP(DRSL, "BUG: Trying to send data on unused lchan\n");
}
/* First push the L3 IE tag and length */ /* First push the L3 IE tag and length */
msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len); msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len);
@@ -1477,31 +1485,11 @@ static u_int8_t ipa_smod_s_for_lchan(struct gsm_lchan *lchan)
{ {
switch (lchan->tch_mode) { switch (lchan->tch_mode) {
case GSM48_CMODE_SPEECH_V1: case GSM48_CMODE_SPEECH_V1:
switch (lchan->type) { return 0x00;
case GSM_LCHAN_TCH_F:
return 0x00;
case GSM_LCHAN_TCH_H:
return 0x03;
default:
break;
}
case GSM48_CMODE_SPEECH_EFR: case GSM48_CMODE_SPEECH_EFR:
switch (lchan->type) { return 0x01;
case GSM_LCHAN_TCH_F:
return 0x01;
/* there's no half-rate EFR */
default:
break;
}
case GSM48_CMODE_SPEECH_AMR: case GSM48_CMODE_SPEECH_AMR:
switch (lchan->type) { return 0x02;
case GSM_LCHAN_TCH_F:
return 0x02;
case GSM_LCHAN_TCH_H:
return 0x05;
default:
break;
}
default: default:
break; break;
} }
@@ -1795,9 +1783,21 @@ static int abis_rsl_rx_ipacc(struct msgb *msg)
/* Entry-point where L2 RSL from BTS enters */ /* Entry-point where L2 RSL from BTS enters */
int abis_rsl_rcvmsg(struct msgb *msg) int abis_rsl_rcvmsg(struct msgb *msg)
{ {
struct abis_rsl_common_hdr *rslh = msgb_l2(msg) ; struct abis_rsl_common_hdr *rslh;
int rc = 0; int rc = 0;
if (!msg) {
DEBUGP(DRSL, "Empty RSL msg?..\n");
return -1;
}
if (msgb_l2len(msg) < sizeof(*rslh)) {
DEBUGP(DRSL, "Truncated RSL message with l2len: %u\n", msgb_l2len(msg));
return -1;
}
rslh = msgb_l2(msg);
switch (rslh->msg_discr & 0xfe) { switch (rslh->msg_discr & 0xfe) {
case ABIS_RSL_MDISC_RLL: case ABIS_RSL_MDISC_RLL:
rc = abis_rsl_rx_rll(msg); rc = abis_rsl_rx_rll(msg);

View File

@@ -356,12 +356,15 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
case NM_OC_SITE_MANAGER: case NM_OC_SITE_MANAGER:
bts = container_of(obj, struct gsm_bts, site_mgr); bts = container_of(obj, struct gsm_bts, site_mgr);
if (new_state->operational == 2 && if (new_state->operational == 2 &&
new_state->availability == NM_AVSTATE_OK) new_state->availability == NM_AVSTATE_OK) {
printf("STARTING SITE MANAGER\n");
abis_nm_opstart(bts, obj_class, 0xff, 0xff, 0xff); abis_nm_opstart(bts, obj_class, 0xff, 0xff, 0xff);
}
break; break;
case NM_OC_BTS: case NM_OC_BTS:
bts = obj; bts = obj;
if (new_state->availability == NM_AVSTATE_DEPENDENCY) { if (new_state->availability == NM_AVSTATE_DEPENDENCY) {
printf("STARTING BTS...\n");
patch_nm_tables(bts); patch_nm_tables(bts);
abis_nm_set_bts_attr(bts, nanobts_attr_bts, abis_nm_set_bts_attr(bts, nanobts_attr_bts,
sizeof(nanobts_attr_bts)); sizeof(nanobts_attr_bts));
@@ -377,6 +380,7 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
trx = ts->trx; trx = ts->trx;
if (new_state->operational == 1 && if (new_state->operational == 1 &&
new_state->availability == NM_AVSTATE_DEPENDENCY) { new_state->availability == NM_AVSTATE_DEPENDENCY) {
printf("STARTING OC Channel...\n");
patch_nm_tables(trx->bts); patch_nm_tables(trx->bts);
enum abis_nm_chan_comb ccomb = enum abis_nm_chan_comb ccomb =
abis_nm_chcomb4pchan(ts->pchan); abis_nm_chcomb4pchan(ts->pchan);

View File

@@ -63,7 +63,10 @@ static const char *audio_name = "GSM-EFR/8000";
static int audio_payload = 97; static int audio_payload = 97;
static int audio_loop = 0; static int audio_loop = 0;
static int early_bind = 0; static int early_bind = 0;
static int rtp_base_port = 4000;
static char *forward_ip = NULL;
static int forward_port = 0;
static char *config_file = "mgcp.cfg"; static char *config_file = "mgcp.cfg";
/* used by msgb and mgcp */ /* used by msgb and mgcp */
@@ -95,7 +98,7 @@ struct mgcp_endpoint {
char *local_options; char *local_options;
int conn_mode; int conn_mode;
/* the local rtp port */ /* the local rtp port we are binding to */
int rtp_port; int rtp_port;
/* /*
@@ -107,9 +110,10 @@ struct mgcp_endpoint {
struct bsc_fd local_rtcp; struct bsc_fd local_rtcp;
struct in_addr remote; struct in_addr remote;
struct in_addr bts;
/* in network byte order */ /* in network byte order */
int rtp, rtcp; int net_rtp, net_rtcp;
int bts_rtp, bts_rtcp; int bts_rtp, bts_rtcp;
}; };
@@ -235,8 +239,10 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
} }
/* do not forward aynthing... maybe there is a packet from the bts */ /* do not forward aynthing... maybe there is a packet from the bts */
if (endp->ci == CI_UNUSED) if (endp->ci == CI_UNUSED) {
DEBUGP(DMGCP, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp));
return -1; return -1;
}
/* /*
* Figure out where to forward it to. This code assumes that we * Figure out where to forward it to. This code assumes that we
@@ -246,20 +252,22 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
* able to tell if this is legitimate. * able to tell if this is legitimate.
*/ */
#warning "Slight spec violation. With connection mode recvonly we should attempt to forward." #warning "Slight spec violation. With connection mode recvonly we should attempt to forward."
dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 &&
(endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port)
? DEST_BTS : DEST_NETWORK; ? DEST_BTS : DEST_NETWORK;
proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP; proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP;
/* We have no idea who called us, maybe it is the BTS. */ /* We have no idea who called us, maybe it is the BTS. */
if (dest == DEST_NETWORK && endp->bts_rtp == 0) { if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || forward_ip)) {
/* it was the BTS... */ /* it was the BTS... */
if (memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) { if (!bts_ip || memcmp(&addr.sin_addr, &bts_in, sizeof(bts_in)) == 0) {
if (fd == &endp->local_rtp) { if (fd == &endp->local_rtp) {
endp->bts_rtp = addr.sin_port; endp->bts_rtp = addr.sin_port;
} else { } else {
endp->bts_rtcp = addr.sin_port; endp->bts_rtcp = addr.sin_port;
} }
endp->bts = addr.sin_addr;
DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d/%d\n", DEBUGP(DMGCP, "Found BTS for endpoint: 0x%x on port: %d/%d\n",
ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp)); ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp));
} }
@@ -271,10 +279,10 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
if (dest == DEST_NETWORK) { if (dest == DEST_NETWORK) {
return _send(fd->fd, &endp->remote, return _send(fd->fd, &endp->remote,
proto == PROTO_RTP ? endp->rtp : endp->rtcp, proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp,
buf, rc); buf, rc);
} else { } else {
return _send(fd->fd, &bts_in, return _send(fd->fd, &endp->bts,
proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp, proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp,
buf, rc); buf, rc);
} }
@@ -303,9 +311,6 @@ static int create_bind(struct bsc_fd *fd, int port)
static int bind_rtp(struct mgcp_endpoint *endp) static int bind_rtp(struct mgcp_endpoint *endp)
{ {
/* set to zero until we get the info */
memset(&endp->remote, 0, sizeof(endp->remote));
if (create_bind(&endp->local_rtp, endp->rtp_port) != 0) { if (create_bind(&endp->local_rtp, endp->rtp_port) != 0) {
DEBUGP(DMGCP, "Failed to create RTP port: %d on 0x%x\n", DEBUGP(DMGCP, "Failed to create RTP port: %d on 0x%x\n",
endp->rtp_port, ENDPOINT_NUMBER(endp)); endp->rtp_port, ENDPOINT_NUMBER(endp));
@@ -636,7 +641,10 @@ static void handle_create_con(struct msgb *msg, struct sockaddr_in *source)
MSG_TOKENIZE_END MSG_TOKENIZE_END
/* initialize */ /* initialize */
endp->rtp = endp->rtcp = endp->bts_rtp = endp->bts_rtcp = 0; endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
/* set to zero until we get the info */
memset(&endp->remote, 0, sizeof(endp->remote));
/* bind to the port now */ /* bind to the port now */
endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port); endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), rtp_base_port);
@@ -716,8 +724,8 @@ static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source)
const char *param = (const char *)&msg->l3h[line_start]; const char *param = (const char *)&msg->l3h[line_start];
if (sscanf(param, "m=audio %d RTP/AVP %*d", &port) == 1) { if (sscanf(param, "m=audio %d RTP/AVP %*d", &port) == 1) {
endp->rtp = htons(port); endp->net_rtp = htons(port);
endp->rtcp = htons(port + 1); endp->net_rtcp = htons(port + 1);
} }
break; break;
} }
@@ -740,7 +748,7 @@ static void handle_modify_con(struct msgb *msg, struct sockaddr_in *source)
/* modify */ /* modify */
DEBUGP(DMGCP, "Modified endpoint on: 0x%x Server: %s:%u\n", DEBUGP(DMGCP, "Modified endpoint on: 0x%x Server: %s:%u\n",
ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->rtp); ENDPOINT_NUMBER(endp), inet_ntoa(endp->remote), endp->net_rtp);
return send_with_sdp(endp, "MDCX", trans_id, source); return send_with_sdp(endp, "MDCX", trans_id, source);
error: error:
@@ -802,7 +810,7 @@ static void handle_delete_con(struct msgb *msg, struct sockaddr_in *source)
bsc_unregister_fd(&endp->local_rtcp); bsc_unregister_fd(&endp->local_rtcp);
} }
endp->rtp = endp->rtcp = endp->bts_rtp = endp->bts_rtcp = 0; endp->net_rtp = endp->net_rtcp = endp->bts_rtp = endp->bts_rtcp = 0;
return send_response(250, "DLCX", trans_id, source); return send_response(250, "DLCX", trans_id, source);
@@ -900,7 +908,8 @@ static int config_write_mgcp(struct vty *vty)
vty_out(vty, "mgcp%s", VTY_NEWLINE); vty_out(vty, "mgcp%s", VTY_NEWLINE);
if (local_ip) if (local_ip)
vty_out(vty, " local ip %s%s", local_ip, VTY_NEWLINE); vty_out(vty, " local ip %s%s", local_ip, VTY_NEWLINE);
vty_out(vty, " bts ip %s%s", bts_ip, VTY_NEWLINE); if (bts_ip)
vty_out(vty, " bts ip %s%s", bts_ip, VTY_NEWLINE);
vty_out(vty, " bind ip %s%s", source_addr, VTY_NEWLINE); vty_out(vty, " bind ip %s%s", source_addr, VTY_NEWLINE);
vty_out(vty, " bind port %u%s", source_port, VTY_NEWLINE); vty_out(vty, " bind port %u%s", source_port, VTY_NEWLINE);
vty_out(vty, " bind early %u%s", !!early_bind, VTY_NEWLINE); vty_out(vty, " bind early %u%s", !!early_bind, VTY_NEWLINE);
@@ -909,6 +918,10 @@ static int config_write_mgcp(struct vty *vty)
vty_out(vty, " sdp audio payload name %s%s", audio_name, VTY_NEWLINE); vty_out(vty, " sdp audio payload name %s%s", audio_name, VTY_NEWLINE);
vty_out(vty, " loop %u%s", !!audio_loop, VTY_NEWLINE); vty_out(vty, " loop %u%s", !!audio_loop, VTY_NEWLINE);
vty_out(vty, " endpoints %u%s", number_endpoints, VTY_NEWLINE); vty_out(vty, " endpoints %u%s", number_endpoints, VTY_NEWLINE);
if (forward_ip)
vty_out(vty, " forward audio ip %s%s", forward_ip, VTY_NEWLINE);
if (forward_port != 0)
vty_out(vty, " forward audio port %d%s", forward_port, VTY_NEWLINE);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@@ -923,7 +936,7 @@ DEFUN(show_mcgp, show_mgcp_cmd, "show mgcp",
struct mgcp_endpoint *endp = &endpoints[i]; struct mgcp_endpoint *endp = &endpoints[i];
vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s", vty_out(vty, " Endpoint 0x%.2x: CI: %d net: %u/%u bts: %u/%u%s",
i, endp->ci, i, endp->ci,
ntohs(endp->rtp), ntohs(endp->rtcp), ntohs(endp->net_rtp), ntohs(endp->net_rtcp),
ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE); ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp), VTY_NEWLINE);
} }
@@ -1055,6 +1068,26 @@ DEFUN(cfg_mgcp_number_endp,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN(cfg_mgcp_forward_ip,
cfg_mgcp_forward_ip_cmd,
"forward audio ip IP",
"Forward packets from and to the IP. This disables most of the MGCP feature.")
{
if (forward_ip)
talloc_free(forward_ip);
forward_ip = talloc_strdup(tall_bsc_ctx, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_forward_port,
cfg_mgcp_forward_port_cmd,
"forward audio port <1-15000>",
"Forward packets from and to the port. This disables most of the MGCP feature.")
{
forward_port = atoi(argv[0]);
return CMD_SUCCESS;
}
int bsc_vty_init(struct gsm_network *dummy) int bsc_vty_init(struct gsm_network *dummy)
{ {
cmd_init(1); cmd_init(1);
@@ -1076,6 +1109,8 @@ int bsc_vty_init(struct gsm_network *dummy)
install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd); install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd);
install_element(MGCP_NODE, &cfg_mgcp_loop_cmd); install_element(MGCP_NODE, &cfg_mgcp_loop_cmd);
install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd); install_element(MGCP_NODE, &cfg_mgcp_number_endp_cmd);
install_element(MGCP_NODE, &cfg_mgcp_forward_ip_cmd);
install_element(MGCP_NODE, &cfg_mgcp_forward_port_cmd);
return 0; return 0;
} }
@@ -1096,10 +1131,8 @@ int main(int argc, char** argv)
} }
if (!bts_ip) { if (!bts_ip)
fprintf(stderr, "Need to specify the BTS ip address for RTP handling.\n"); fprintf(stderr, "No BTS ip address specified. This will allow everyone to connect.\n");
return -1;
}
endpoints = _talloc_zero_array(tall_bsc_ctx, endpoints = _talloc_zero_array(tall_bsc_ctx,
sizeof(struct mgcp_endpoint), sizeof(struct mgcp_endpoint),
@@ -1116,37 +1149,69 @@ int main(int argc, char** argv)
endpoints[i].ci = CI_UNUSED; endpoints[i].ci = CI_UNUSED;
} }
/* initialize the socket */ /*
bfd.when = BSC_FD_READ; * This application supports two modes.
bfd.cb = read_call_agent; * 1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX
bfd.fd = socket(AF_INET, SOCK_DGRAM, 0); * 2.) plain forwarding of RTP packets on the endpoints.
if (bfd.fd < 0) { * both modes are mutual exclusive
perror("Gateway failed to listen"); */
return -1; if (forward_ip) {
} int port = rtp_base_port;
if (forward_port != 0)
port = forward_port;
setsockopt(bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (!early_bind) {
DEBUGP(DMGCP, "Forwarding requires early bind.\n");
return -1;
}
memset(&addr, 0, sizeof(addr)); /*
addr.sin_family = AF_INET; * Store the forward IP and assign a ci. For early bind
addr.sin_port = htons(source_port); * the sockets will be created after this.
inet_aton(source_addr, &addr.sin_addr); */
for (i = 1; i < number_endpoints; ++i) {
struct mgcp_endpoint *endp = &endpoints[i];
inet_aton(forward_ip, &endp->remote);
endp->ci = CI_UNUSED + 23;
endp->net_rtp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port));
endp->net_rtcp = htons(rtp_calculate_port(ENDPOINT_NUMBER(endp), port) + 1);
}
if (bind(bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { DEBUGP(DMGCP, "Configured for Audio Forwarding.\n");
perror("Gateway failed to bind"); } else {
return -1; bfd.when = BSC_FD_READ;
} bfd.cb = read_call_agent;
bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
if (bfd.fd < 0) {
perror("Gateway failed to listen");
return -1;
}
bfd.data = msgb_alloc(4096, "mgcp-msg"); setsockopt(bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (!bfd.data) {
fprintf(stderr, "Gateway memory error.\n"); memset(&addr, 0, sizeof(addr));
return -1; addr.sin_family = AF_INET;
} addr.sin_port = htons(source_port);
inet_aton(source_addr, &addr.sin_addr);
if (bind(bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("Gateway failed to bind");
return -1;
}
bfd.data = msgb_alloc(4096, "mgcp-msg");
if (!bfd.data) {
fprintf(stderr, "Gateway memory error.\n");
return -1;
}
if (bsc_register_fd(&bfd) != 0) { if (bsc_register_fd(&bfd) != 0) {
DEBUGP(DMGCP, "Failed to register the fd\n"); DEBUGP(DMGCP, "Failed to register the fd\n");
return -1; return -1;
}
DEBUGP(DMGCP, "Configured for MGCP.\n");
} }
/* initialisation */ /* initialisation */

72
openbsc/src/bsc_msc.c Normal file
View File

@@ -0,0 +1,72 @@
/* Routines to talk to the MSC using the IPA Protocol */
/*
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010 by on-waves.com
* 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.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int connect_to_msc(struct bsc_fd *fd, const char *ip, int port)
{
struct sockaddr_in sin;
int on = 1, ret;
printf("Attempting to connect MSC at %s:%d\n", ip, port);
fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
fd->when = BSC_FD_READ;
fd->data = NULL;
fd->priv_nr = 1;
if (fd->fd < 0) {
perror("Creating TCP socket failed");
return fd->fd;
}
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
inet_aton(ip, &sin.sin_addr);
setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
ret = connect(fd->fd, (struct sockaddr *) &sin, sizeof(sin));
if (ret < 0) {
perror("Connection failed");
return ret;
}
ret = bsc_register_fd(fd);
if (ret < 0) {
perror("Registering the fd failed");
close(fd->fd);
return ret;
}
return ret;
}

808
openbsc/src/bsc_msc_ip.c Normal file
View File

@@ -0,0 +1,808 @@
/* A hackish minimal BSC (+MSC +HLR) implementation */
/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009 by on-waves.com
* 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 <unistd.h>
#include <time.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define _GNU_SOURCE
#include <getopt.h>
#include <openbsc/select.h>
#include <openbsc/debug.h>
#include <openbsc/e1_input.h>
#include <openbsc/talloc.h>
#include <openbsc/select.h>
#include <openbsc/ipaccess.h>
#include <openbsc/bssap.h>
#include <openbsc/paging.h>
#include <openbsc/signal.h>
#include <openbsc/chan_alloc.h>
#include <openbsc/bsc_msc.h>
#include <sccp/sccp.h>
/* SCCP helper */
#define SCCP_IT_TIMER 60
/* MCC and MNC for the Location Area Identifier */
struct gsm_network *bsc_gsmnet = 0;
static const char *config_file = "openbsc.cfg";
static char *msc_address = "127.0.0.1";
static struct bsc_fd msc_connection;
static struct in_addr local_addr;
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 bss_sccp_connection_data *bss_sccp_create_data()
{
struct bss_sccp_connection_data *data;
data = _talloc_zero(tall_bsc_ctx,
sizeof(struct bss_sccp_connection_data),
"bsc<->msc");
if (!data)
return NULL;
INIT_LLIST_HEAD(&data->sccp_queue);
INIT_LLIST_HEAD(&data->gsm_queue);
return data;
}
void bss_sccp_free_data(struct bss_sccp_connection_data *data)
{
bsc_del_timer(&data->T10);
bsc_del_timer(&data->sccp_it);
bsc_free_queued(data->sccp);
bts_free_queued(data);
talloc_free(data);
}
static void sccp_it_fired(void *_data)
{
struct bss_sccp_connection_data *data =
(struct bss_sccp_connection_data *) _data;
sccp_connection_send_it(data->sccp);
bsc_schedule_timer(&data->sccp_it, SCCP_IT_TIMER, 0);
}
/* GSM subscriber drop-ins */
extern struct llist_head *subscr_bsc_active_subscriber(void);
struct gsm_subscriber *find_subscriber(u_int8_t type, const char *mi_string)
{
struct gsm_subscriber *subscr;
u_int32_t tmsi = GSM_RESERVED_TMSI;
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");
return NULL;
}
}
llist_for_each_entry(subscr, subscr_bsc_active_subscriber(), entry) {
if (type == GSM_MI_TYPE_TMSI && tmsi == subscr->tmsi) {
return subscr_get(subscr);
} else if (type == GSM_MI_TYPE_IMSI && strcmp(mi_string, subscr->imsi) == 0) {
return subscr_get(subscr);
}
}
DEBUGP(DMSC, "No subscriber has been found.\n");
return NULL;
}
/* SCCP handling */
void msc_outgoing_sccp_data(struct sccp_connection *conn, struct msgb *msg, unsigned int len)
{
struct bssmap_header *bs;
if (len < 1) {
DEBUGP(DMSC, "The header is too short.\n");
return;
}
switch (msg->l3h[0]) {
case BSSAP_MSG_BSS_MANAGEMENT:
msg->l4h = &msg->l3h[sizeof(*bs)];
msg->lchan = sccp_get_lchan(conn->data_ctx);
bssmap_rcvmsg_dt1(conn, msg, len - sizeof(*bs));
break;
case BSSAP_MSG_DTAP:
dtap_rcvmsg(sccp_get_lchan(conn->data_ctx), msg, len);
break;
default:
DEBUGPC(DMSC, "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);
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.");
lchan->msc_data = NULL;
put_lchan(lchan);
}
bss_sccp_free_data((struct bss_sccp_connection_data *)conn->data_ctx);
sccp_connection_free(conn);
return;
} else if (conn->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED) {
struct bss_sccp_connection_data *con_data;
DEBUGP(DMSC, "Connection established: %p\n", conn);
/* start the inactivity test timer */
con_data = (struct bss_sccp_connection_data *) conn->data_ctx;
con_data->sccp_it.cb = sccp_it_fired;
con_data->sccp_it.data = con_data;
bsc_schedule_timer(&con_data->sccp_it, SCCP_IT_TIMER, 0);
bsc_send_queued(conn);
}
}
/*
* General COMPLETE LAYER3 INFORMATION handling for
* PAGING RESPONSE, LOCATION UPDATING REQUEST, CM REESTABLISHMENT REQUEST,
* CM SERVICE REQUEST, IMSI DETACH, IMMEDIATE SETUP.
*
* IMMEDIATE SETUP is coming from GROUP CC that is not yet
* supported...
*/
int open_sccp_connection(struct msgb *layer3)
{
struct bss_sccp_connection_data *con_data;
struct sccp_connection *sccp_connection;
struct msgb *data;
DEBUGP(DMSC, "Opening new layer3 connection\n");
sccp_connection = sccp_connection_socket();
if (!sccp_connection) {
DEBUGP(DMSC, "Failed to allocate memory.\n");
return -ENOMEM;
}
data = bssmap_create_layer3(layer3);
if (!data) {
DEBUGP(DMSC, "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");
sccp_connection_free(sccp_connection);
msgb_free(data);
return -ENOMEM;
}
/* initialize the bridge */
con_data->lchan = layer3->lchan;
con_data->sccp = sccp_connection;
sccp_connection->state_cb = msc_outgoing_sccp_state;
sccp_connection->data_cb = msc_outgoing_sccp_data;
sccp_connection->data_ctx = con_data;
layer3->lchan->msc_data = con_data;
/* FIXME: Use transaction for this */
use_lchan(layer3->lchan);
sccp_connection_connect(sccp_connection, &sccp_ssn_bssap, data);
msgb_free(data);
return 1;
}
/* figure out if this is the inial layer3 message */
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");
return -1;
}
bsc_queue_connection_write(lchan_get_sccp(msg->lchan), dtap);
return 1;
} else {
return open_sccp_connection(msg);
}
}
/* Receive a PAGING RESPONSE message from the MS */
static int handle_paging_response(struct msgb *msg)
{
struct gsm_subscriber *subscr;
char mi_string[GSM48_MI_SIZE];
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",
mi_type, mi_string);
subscr = find_subscriber(mi_type, mi_string);
if (!subscr)
return -EINVAL;
/* 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");
return -1;
}
/* open a new transaction and SCCP connection */
return send_dtap_or_open_connection(msg);
}
/* Receive a CIPHER MODE COMPLETE from the MS */
static int handle_cipher_m_complete(struct msgb *msg)
{
struct msgb *resp;
DEBUGP(DMSC, "CIPHER MODE COMPLETE from MS, forwarding to MSC\n");
resp = bssmap_create_cipher_complete(msg);
if (!resp) {
DEBUGP(DMSC, "Creating MSC response failed.\n");
return -1;
}
/* handled this message */
bts_unblock_queue(msg->lchan->msc_data);
bsc_queue_connection_write(lchan_get_sccp(msg->lchan), resp);
return 1;
}
/* Receive a ASSIGNMENT COMPLETE */
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");
if (!msg->lchan->msc_data) {
DEBUGP(DMSC, "No MSC data\n");
put_lchan(msg->lchan);
return -1;
}
if (msg->lchan->msc_data->secondary_lchan != msg->lchan) {
LOGP(DMSC, LOGL_NOTICE, "Wrong assignment complete.\n");
put_lchan(msg->lchan);
return -1;
}
if (msgb_l3len(msg) - sizeof(*gh) != 1) {
DEBUGP(DMSC, "assignment failure invalid: %d\n",
msgb_l3len(msg) - sizeof(*gh));
put_lchan(msg->lchan);
return -1;
}
/* swap the channels and release the old */
old_chan = msg->lchan->msc_data->lchan;
msg->lchan->msc_data->lchan = msg->lchan;
msg->lchan->msc_data->secondary_lchan = NULL;
old_chan->msc_data = NULL;
/* give up the old channel to not do a SACCH deactivate */
subscr_put(old_chan->subscr);
old_chan->subscr = NULL;
put_lchan(old_chan);
/* activate audio on it... */
if (is_ipaccess_bts(msg->lchan->ts->trx->bts) && msg->lchan->tch_mode != GSM48_CMODE_SIGN)
rsl_ipacc_crcx(msg->lchan);
gsm0808_send_assignment_compl(msg->lchan, gh->data[0]);
return 1;
}
/*
* Receive a ASSIGNMENT FAILURE. If the message is failed
* to be parsed the T10 timer will send the failure.
*/
static int handle_ass_fail(struct msgb *msg)
{
struct gsm48_hdr *gh = msgb_l3(msg);
DEBUGP(DMSC, "ASSIGNMENT FAILURE from MS, forwarding to MSC\n");
if (!msg->lchan->msc_data) {
DEBUGP(DMSC, "No MSC data\n");
put_lchan(msg->lchan);
return -1;
}
if (msg->lchan->msc_data->secondary_lchan != msg->lchan) {
LOGP(DMSC, LOGL_NOTICE, "Wrong assignment complete.\n");
put_lchan(msg->lchan);
return -1;
}
if (msgb_l3len(msg) - sizeof(*gh) != 1) {
DEBUGP(DMSC, "assignment failure invalid: %d\n",
msgb_l3len(msg) - sizeof(*gh));
put_lchan(msg->lchan);
return -1;
}
gsm0808_send_assignment_failure(msg->lchan,
GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE, &gh->data[0]);
return 1;
}
/*
* Receive a GSM04.08 MODIFY ACK. Actually we have to check
* the content to see if this was a success or not.
*/
static int handle_modify_ack(struct msgb *msg)
{
int rc;
/* modify RSL */
rc = gsm48_rx_rr_modif_ack(msg);
if (rc < 0)
gsm0808_send_assignment_failure(msg->lchan,
GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
else
gsm0808_send_assignment_compl(msg->lchan, 0);
return 1;
}
/* Receive a GSM 04.08 Radio Resource (RR) message */
static int gsm0408_rcv_rr(struct msgb *msg)
{
struct gsm48_hdr *gh = msgb_l3(msg);
int rc = 0;
switch (gh->msg_type) {
case GSM48_MT_RR_PAG_RESP:
rc = handle_paging_response(msg);
break;
case GSM48_MT_RR_MEAS_REP:
/* ignore measurement for now */
rc = -1;
break;
case GSM48_MT_RR_CIPH_M_COMPL:
rc = handle_cipher_m_complete(msg);
break;
case GSM48_MT_RR_ASS_COMPL:
rc = handle_ass_compl(msg);
break;
case GSM48_MT_RR_ASS_FAIL:
rc = handle_ass_fail(msg);
break;
case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
rc = handle_modify_ack(msg);
break;
default:
break;
}
return rc;
}
/* Receive a GSM 04.08 Mobility Management (MM) message */
static int gsm0408_rcv_mm(struct msgb *msg)
{
struct gsm48_hdr *gh = msgb_l3(msg);
int rc = 0;
switch (gh->msg_type & 0xbf) {
case GSM48_MT_MM_LOC_UPD_REQUEST:
case GSM48_MT_MM_CM_REEST_REQ:
case GSM48_MT_MM_CM_SERV_REQ:
case GSM48_MT_MM_IMSI_DETACH_IND:
rc = send_dtap_or_open_connection(msg);
break;
default:
break;
}
return rc;
}
int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
{
struct gsm48_hdr *gh = msgb_l3(msg);
u_int8_t pdisc = gh->proto_discr & 0x0f;
int rc = 0;
switch (pdisc) {
case GSM48_PDISC_RR:
rc = gsm0408_rcv_rr(msg);
break;
case GSM48_PDISC_MM:
rc = gsm0408_rcv_mm(msg);
break;
default:
break;
}
/*
* if we have a sccp connection and didn't handle the message
* forward it to the MSC using DTAP
*/
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");
return -1;
}
bsc_queue_connection_write(lchan_get_sccp(msg->lchan), dtap);
}
return rc;
}
/* handle ipaccess signals */
static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
struct gsm_lchan *lchan = signal_data;
struct gsm_bts_trx_ts *ts;
int rc;
if (subsys != SS_ABISIP)
return 0;
ts = lchan->ts;
switch (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",
lchan->msc_data->rtp_port, lchan->abis_ip.conn_id);
int rtp_payload = ts->trx->bts->network->rtp_payload;
if (rtp_payload == 0)
rtp_payload = lchan->abis_ip.rtp_payload2;
rc = rsl_ipacc_mdcx(lchan, ntohl(local_addr.s_addr),
lchan->msc_data->rtp_port,
rtp_payload);
if (rc < 0) {
DEBUGP(DMSC, "Failed to send connect: %d\n", rc);
return rc;
}
}
break;
case S_ABISIP_DLCX_IND:
break;
}
return 0;
}
static void print_usage()
{
printf("Usage: bsc_hack\n");
}
/*
* SCCP handling
*/
static int msc_sccp_write_ipa(struct msgb *msg, void *data)
{
int ret;
DEBUGP(DMSC, "Sending SCCP to MSC: %u\n", msgb_l2len(msg));
ipaccess_prepend_header(msg, IPAC_PROTO_SCCP);
DEBUGP(DMI, "MSC TX %s\n", hexdump(msg->l2h, msgb_l2len(msg)));
ret = write(msc_connection.fd, msg->data, msg->len);
if (ret <= 0) {
perror("MSC: Failed to send SCCP");
return -1;
}
return 0;
}
static int msc_sccp_accept(struct sccp_connection *connection, void *data)
{
DEBUGP(DMSC, "Rejecting incoming SCCP connection.\n");
return -1;
}
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));
if (length < sizeof(*bs)) {
DEBUGP(DMSC, "The header is too short.\n");
return -1;
}
bs = (struct bssmap_header *) msgb->l3h;
if (bs->length < length - sizeof(*bs))
return -1;
switch (bs->type) {
case BSSAP_MSG_BSS_MANAGEMENT:
msgb->l4h = &msgb->l3h[sizeof(*bs)];
bssmap_rcvmsg_udt(bsc_gsmnet, msgb, length - sizeof(*bs));
break;
default:
DEBUGPC(DMSC, "Unimplemented msg type: %d\n", bs->type);
}
return 0;
}
/*
* network initialisation
*/
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);
}
/* send a gsm 08.08 reset message from here */
msg = bssmap_create_reset();
if (!msg) {
DEBUGP(DMSC, "Failed to create the reset message.\n");
return;
}
sccp_write(msg, &sccp_ssn_bssap, &sccp_ssn_bssap, 0);
msgb_free(msg);
}
}
/*
* callback with IP access data
*/
static int ipaccess_a_fd_cb(struct bsc_fd *bfd, unsigned int what)
{
int error;
struct msgb *msg = ipaccess_read_msg(bfd, &error);
struct ipaccess_head *hh;
if (!msg) {
if (error == 0) {
fprintf(stderr, "The connection to the MSC was lost, exiting\n");
exit(-2);
}
fprintf(stderr, "Failed to parse ip access message: %d\n", error);
return -1;
}
DEBUGP(DMSC, "From MSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
/* handle base message handling */
hh = (struct ipaccess_head *) msg->data;
ipaccess_rcvmsg_base(msg, bfd);
/* initialize the networking. This includes sending a GSM08.08 message */
if (hh->proto == IPAC_PROTO_IPACCESS && msg->l2h[0] == IPAC_MSGT_ID_ACK)
initialize_if_needed();
else if (hh->proto == IPAC_PROTO_SCCP)
sccp_system_incoming(msg);
return 0;
}
static void print_help()
{
printf(" Some useful help...\n");
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(" -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");
}
static void handle_options(int argc, char** argv)
{
while (1) {
int option_index = 0, c;
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"debug", 1, 0, 'd'},
{"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'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, "hd:sTPc:m:l:",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 'h':
print_usage();
print_help();
exit(0);
case 's':
debug_use_color(0);
break;
case 'd':
debug_parse_category_mask(optarg);
break;
case 'c':
config_file = strdup(optarg);
break;
case 'T':
debug_timestamp(1);
break;
case 'P':
ipacc_rtp_direct = 0;
break;
case 'm':
msc_address = strdup(optarg);
break;
case 'l':
inet_aton(optarg, &local_addr);
break;
default:
/* ignore */
break;
}
}
}
static void signal_handler(int signal)
{
fprintf(stdout, "signal %u received\n", signal);
switch (signal) {
case SIGINT:
bsc_shutdown_net(bsc_gsmnet);
sleep(3);
exit(0);
break;
case SIGABRT:
/* in case of abort, we want to obtain a talloc report
* and then return to the caller, who will abort the process */
case SIGUSR1:
talloc_report_full(tall_bsc_ctx, stderr);
break;
default:
break;
}
}
static void test_mode()
{
static const u_int8_t assignment_req[] = { 0x01, 0x0b, 0x03, 0x01, 0x0b, 0x25, 0x01, 0x00, 0x01 };
struct gsm_lchan lchan;
struct sccp_connection conn;
struct bss_sccp_connection_data data;
struct gsm_bts_trx_ts trx_ts;
struct gsm_bts_trx trx;
struct gsm_bts bts;
int rc;
/* initialize */
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);
}
bts.network = bsc_gsmnet;
trx.bts = &bts;
trx_ts.trx = &trx;
lchan.ts = &trx_ts;
/* create fake data connection */
data.lchan = &lchan;
data.sccp = &conn;
lchan.msc_data = &data;
conn.data_ctx = &data;
struct msgb *msg = msgb_alloc(400, "test-msg");
msg->lchan = &lchan;
msg->l4h = msgb_put(msg, ARRAY_SIZE(assignment_req));
memcpy(msg->l4h, assignment_req, ARRAY_SIZE(assignment_req));
bssmap_rcvmsg_dt1(&conn, msg, ARRAY_SIZE(assignment_req));
}
int main(int argc, char **argv)
{
int rc;
tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
/* parse options */
handle_options(argc, argv);
/* seed the PRNG */
srand(time(NULL));
/* initialize sccp */
sccp_system_init(msc_sccp_write_ipa, NULL);
sccp_connection_set_incoming(&sccp_ssn_bssap, msc_sccp_accept, NULL);
sccp_set_read(&sccp_ssn_bssap, msc_sccp_read, NULL);
/* initialize ipaccess handling */
register_signal_handler(SS_ABISIP, handle_abisip_signal, NULL);
msc_connection.cb = ipaccess_a_fd_cb;
rc = connect_to_msc(&msc_connection, msc_address, 5000);
if (rc < 0) {
fprintf(stderr, "Opening the MSC connection failed.\n");
exit(1);
}
signal(SIGINT, &signal_handler);
signal(SIGABRT, &signal_handler);
signal(SIGUSR1, &signal_handler);
signal(SIGPIPE, SIG_IGN);
while (1) {
bsc_select_main(0);
}
}

1299
openbsc/src/bssap.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -33,8 +33,6 @@
#include <openbsc/debug.h> #include <openbsc/debug.h>
#include <openbsc/signal.h> #include <openbsc/signal.h>
static void auto_release_channel(void *_lchan);
struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts, struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts,
enum gsm_phys_chan_config pchan) enum gsm_phys_chan_config pchan)
{ {
@@ -223,10 +221,9 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type)
/* clear multi rate config */ /* clear multi rate config */
memset(&lchan->mr_conf, 0, sizeof(lchan->mr_conf)); memset(&lchan->mr_conf, 0, sizeof(lchan->mr_conf));
/* Configure the time and start it so it will be closed */ /* clear any msc reference */
lchan->release_timer.cb = auto_release_channel; lchan->msc_data = NULL;
lchan->release_timer.data = lchan;
bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT);
} }
return lchan; return lchan;
@@ -249,8 +246,6 @@ void lchan_free(struct gsm_lchan *lchan)
lchan->use_count = 0; lchan->use_count = 0;
} }
/* stop the timer */
bsc_del_timer(&lchan->release_timer);
bsc_del_timer(&lchan->T3101); bsc_del_timer(&lchan->T3101);
/* clear cached measuement reports */ /* clear cached measuement reports */
@@ -261,21 +256,23 @@ void lchan_free(struct gsm_lchan *lchan)
} }
for (i = 0; i < ARRAY_SIZE(lchan->neigh_meas); i++) for (i = 0; i < ARRAY_SIZE(lchan->neigh_meas); i++)
lchan->neigh_meas[i].arfcn = 0; lchan->neigh_meas[i].arfcn = 0;
/* FIXME: ts_free() the timeslot, if we're the last logical /* FIXME: ts_free() the timeslot, if we're the last logical
* channel using it */ * channel using it */
} }
/* Consider releasing the channel now */ /* Consider releasing the channel now */
int lchan_auto_release(struct gsm_lchan *lchan) int _lchan_release(struct gsm_lchan *lchan)
{ {
if (lchan->use_count > 0) { if (lchan->use_count > 0) {
DEBUGP(DRLL, "BUG: _lchan_release called without zero use_count.\n");
return 0; return 0;
} }
/* Assume we have GSM04.08 running and send a release */ /* Assume we have GSM04.08 running and send a release */
if (lchan->subscr) { if (lchan->subscr) {
++lchan->use_count;
gsm48_send_rr_release(lchan); gsm48_send_rr_release(lchan);
--lchan->use_count;
} }
/* spoofed? message */ /* spoofed? message */
@@ -288,15 +285,6 @@ int lchan_auto_release(struct gsm_lchan *lchan)
return 1; return 1;
} }
/* Auto release the channel when the use count is zero */
static void auto_release_channel(void *_lchan)
{
struct gsm_lchan *lchan = _lchan;
if (!lchan_auto_release(lchan))
bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT);
}
struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr) { struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr) {
struct gsm_bts_trx *trx; struct gsm_bts_trx *trx;
int ts_no, lchan_no; int ts_no, lchan_no;

View File

@@ -232,7 +232,6 @@ static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg)
int rc; int rc;
db_subscriber_alloc_tmsi(lchan->subscr); db_subscriber_alloc_tmsi(lchan->subscr);
release_loc_updating_req(lchan);
rc = gsm0408_loc_upd_acc(msg->lchan, lchan->subscr->tmsi); rc = gsm0408_loc_upd_acc(msg->lchan, lchan->subscr->tmsi);
if (lchan->ts->trx->bts->network->send_mm_info) { if (lchan->ts->trx->bts->network->send_mm_info) {
/* send MM INFO with network name */ /* send MM INFO with network name */
@@ -244,8 +243,7 @@ static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg)
* trigger further action like SMS delivery */ * trigger further action like SMS delivery */
subscr_update(lchan->subscr, msg->trx->bts, subscr_update(lchan->subscr, msg->trx->bts,
GSM_SUBSCRIBER_UPDATE_ATTACHED); GSM_SUBSCRIBER_UPDATE_ATTACHED);
/* try to close channel ASAP */ release_loc_updating_req(lchan);
lchan_auto_release(lchan);
return rc; return rc;
} }
@@ -931,9 +929,8 @@ static void loc_upd_rej_cb(void *data)
struct gsm_lchan *lchan = data; struct gsm_lchan *lchan = data;
struct gsm_bts *bts = lchan->ts->trx->bts; struct gsm_bts *bts = lchan->ts->trx->bts;
release_loc_updating_req(lchan);
gsm0408_loc_upd_rej(lchan, bts->network->reject_cause); gsm0408_loc_upd_rej(lchan, bts->network->reject_cause);
lchan_auto_release(lchan); release_loc_updating_req(lchan);
} }
static void schedule_reject(struct gsm_lchan *lchan) static void schedule_reject(struct gsm_lchan *lchan)
@@ -1355,8 +1352,6 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg)
* imagine an IMSI DETACH happening during an active call! */ * imagine an IMSI DETACH happening during an active call! */
/* subscriber is detached: should we release lchan? */ /* subscriber is detached: should we release lchan? */
lchan_auto_release(msg->lchan);
return 0; return 0;
} }
@@ -2698,7 +2693,6 @@ static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg)
MNCC_REL_CNF, &rel); MNCC_REL_CNF, &rel);
/* FIXME: in case of multiple calls, we can't simply /* FIXME: in case of multiple calls, we can't simply
* hang up here ! */ * hang up here ! */
lchan_auto_release(msg->lchan);
break; break;
default: default:
rc = mncc_recvmsg(trans->subscr->net, trans, rc = mncc_recvmsg(trans->subscr->net, trans,

View File

@@ -567,7 +567,7 @@ int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan,
} }
/* Chapter 9.1.2: Assignment Command */ /* Chapter 9.1.2: Assignment Command */
int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command) int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, u_int8_t power_command)
{ {
struct msgb *msg = gsm48_msgb_alloc(); struct msgb *msg = gsm48_msgb_alloc();
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
@@ -576,7 +576,7 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command)
DEBUGP(DRR, "-> ASSIGNMENT COMMAND tch_mode=0x%02x\n", lchan->tch_mode); DEBUGP(DRR, "-> ASSIGNMENT COMMAND tch_mode=0x%02x\n", lchan->tch_mode);
msg->lchan = lchan; msg->lchan = dest_lchan;
gh->proto_discr = GSM48_PDISC_RR; gh->proto_discr = GSM48_PDISC_RR;
gh->msg_type = GSM48_MT_RR_ASS_CMD; gh->msg_type = GSM48_MT_RR_ASS_CMD;
@@ -591,6 +591,8 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command)
gsm48_chan_desc(&ass->chan_desc, lchan); gsm48_chan_desc(&ass->chan_desc, lchan);
ass->power_command = power_command; ass->power_command = power_command;
msgb_tv_put(msg, GSM48_IE_CHANMODE_1, lchan->tch_mode);
/* in case of multi rate we need to attach a config */ /* in case of multi rate we need to attach a config */
if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) { if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
if (lchan->mr_conf.ver == 0) { if (lchan->mr_conf.ver == 0) {

View File

@@ -224,6 +224,10 @@ struct gsm_network *gsm_network_init(u_int16_t country_code, u_int16_t network_c
net->mncc_recv = mncc_recv; net->mncc_recv = mncc_recv;
net->core_country_code = -1;
net->core_network_code = -1;
net->rtp_base_port = 4000;
return net; return net;
} }

View File

@@ -32,6 +32,7 @@
#include <openbsc/paging.h> #include <openbsc/paging.h>
#include <openbsc/debug.h> #include <openbsc/debug.h>
#include <openbsc/paging.h> #include <openbsc/paging.h>
#include <openbsc/chan_alloc.h>
LLIST_HEAD(active_subscribers); LLIST_HEAD(active_subscribers);
void *tall_subscr_ctx; void *tall_subscr_ctx;
@@ -89,6 +90,7 @@ static int subscr_paging_cb(unsigned int hooknum, unsigned int event,
request->cbfn(hooknum, event, msg, data, request->param); request->cbfn(hooknum, event, msg, data, request->param);
subscr->in_callback = 0; subscr->in_callback = 0;
subscr_put(request->subscr);
talloc_free(request); talloc_free(request);
return 0; return 0;
} }
@@ -166,7 +168,7 @@ void subscr_get_channel(struct gsm_subscriber *subscr,
} }
memset(request, 0, sizeof(*request)); memset(request, 0, sizeof(*request));
request->subscr = subscr; request->subscr = subscr_get(subscr);
request->channel_type = type; request->channel_type = type;
request->cbfn = cbfn; request->cbfn = cbfn;
request->param = param; request->param = param;
@@ -212,3 +214,22 @@ void subscr_put_channel(struct gsm_lchan *lchan)
subscr_send_paging_request(lchan->subscr); subscr_send_paging_request(lchan->subscr);
} }
struct gsm_subscriber *subscr_get_or_create(struct gsm_network *net,
const char *imsi)
{
struct gsm_subscriber *subscr;
llist_for_each_entry(subscr, subscr_bsc_active_subscriber(), entry) {
if (strcmp(subscr->imsi, imsi) == 0 && subscr->net == net)
return subscr_get(subscr);
}
subscr = subscr_alloc();
if (!subscr)
return NULL;
strcpy(subscr->imsi, imsi);
subscr->net = net;
return subscr;
}

View File

@@ -223,7 +223,6 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
trans_lchan_change(ho->old_lchan, new_lchan); trans_lchan_change(ho->old_lchan, new_lchan);
ho->old_lchan->state = LCHAN_S_INACTIVE; ho->old_lchan->state = LCHAN_S_INACTIVE;
lchan_auto_release(ho->old_lchan);
/* do something to re-route the actual speech frames ! */ /* do something to re-route the actual speech frames ! */

View File

@@ -164,6 +164,12 @@ static int parse_unitid(const char *str, u_int16_t *site_id, u_int16_t *bts_id,
return 0; return 0;
} }
/* send the id ack */
int ipaccess_send_id_ack(int fd)
{
return write(fd, id_ack, sizeof(id_ack));
}
/* base handling of the ip.access protocol */ /* base handling of the ip.access protocol */
int ipaccess_rcvmsg_base(struct msgb *msg, int ipaccess_rcvmsg_base(struct msgb *msg,
struct bsc_fd *bfd) struct bsc_fd *bfd)
@@ -180,7 +186,7 @@ int ipaccess_rcvmsg_base(struct msgb *msg,
break; break;
case IPAC_MSGT_ID_ACK: case IPAC_MSGT_ID_ACK:
DEBUGP(DMI, "ID_ACK? -> ACK!\n"); DEBUGP(DMI, "ID_ACK? -> ACK!\n");
ret = write(bfd->fd, id_ack, sizeof(id_ack)); ret = ipaccess_send_id_ack(bfd->fd);
break; break;
} }
return 0; return 0;

View File

@@ -95,6 +95,7 @@ void msgb_reset(struct msgb *msg)
msg->l2h = NULL; msg->l2h = NULL;
msg->l3h = NULL; msg->l3h = NULL;
msg->smsh = NULL; msg->smsh = NULL;
msg->l4h = NULL;
} }
static __attribute__((constructor)) void on_dso_load_trau_msgb(void) static __attribute__((constructor)) void on_dso_load_trau_msgb(void)

View File

@@ -0,0 +1,34 @@
/* BSC Multiplexer/NAT */
/*
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010 by on-waves.com
* 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_nat.h>
#include <openbsc/ipaccess.h>
int bsc_nat_filter_ipa(struct msgb *msg)
{
struct ipaccess_head *hh;
/* handle base message handling */
hh = (struct ipaccess_head *) msg->data;
return hh->proto == IPAC_PROTO_IPACCESS;
}

410
openbsc/src/nat/bsc_nat.c Normal file
View File

@@ -0,0 +1,410 @@
/* BSC Multiplexer/NAT */
/*
* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010 by on-waves.com
* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* 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 <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#define _GNU_SOURCE
#include <getopt.h>
#include <openbsc/debug.h>
#include <openbsc/msgb.h>
#include <openbsc/bsc_msc.h>
#include <openbsc/bsc_nat.h>
#include <openbsc/ipaccess.h>
#include <openbsc/abis_nm.h>
#include <openbsc/talloc.h>
#include <openbsc/linuxlist.h>
#include <sccp/sccp.h>
static const char *config_file = "openbsc.cfg";
static char *msc_address = "127.0.0.1";
static struct in_addr local_addr;
static struct bsc_fd msc_connection;
static struct bsc_fd bsc_connection;
/*
* Per BSC data structure
*/
struct bsc_connection {
struct llist_head list_entry;
/* do we know anything about this BSC? */
int authenticated;
/* the fd we use to communicate */
struct bsc_fd bsc_fd;
};
static LLIST_HEAD(bsc_connections);
/*
* below are stubs we need to link
*/
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
{
return -1;
}
void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
{}
int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
{
return -1;
}
/*
* Below is the handling of messages coming
* from the MSC and need to be forwarded to
* a real BSC.
*/
static void initialize_msc_if_needed()
{
static int init = 0;
init = 1;
/* do we need to send a GSM 08.08 message here? */
}
static void forward_sccp_to_bts(struct msgb *msg)
{
struct bsc_connection *bsc;
int rc;
/* filter, drop, patch the message? */
/* drop packets with the wrong IPA header */
if (bsc_nat_filter_ipa(msg))
return;
/* currently send this to every BSC connected */
llist_for_each_entry(bsc, &bsc_connections, list_entry) {
rc = write(bsc->bsc_fd.fd, msg->data, msg->len);
/* try the next one */
if (rc < msg->len)
fprintf(stderr, "Failed to write message to BTS.\n");
}
}
static int ipaccess_msc_cb(struct bsc_fd *bfd, unsigned int what)
{
int error;
struct msgb *msg = ipaccess_read_msg(bfd, &error);
struct ipaccess_head *hh;
if (!msg) {
if (error == 0) {
fprintf(stderr, "The connection to the MSC was lost, exiting\n");
exit(-2);
}
fprintf(stderr, "Failed to parse ip access message: %d\n", error);
return -1;
}
DEBUGP(DMSC, "MSG from MSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
/* handle base message handling */
hh = (struct ipaccess_head *) msg->data;
ipaccess_rcvmsg_base(msg, bfd);
/* initialize the networking. This includes sending a GSM08.08 message */
if (hh->proto == IPAC_PROTO_IPACCESS && msg->l2h[0] == IPAC_MSGT_ID_ACK)
initialize_msc_if_needed();
else if (hh->proto == IPAC_PROTO_SCCP)
forward_sccp_to_bts(msg);
return 0;
}
/*
* Below is the handling of messages coming
* from the BSC and need to be forwarded to
* a real BSC.
*/
/*
* Remove the connection from the connections list,
* remove it from the patching of SCCP header lists
* as well. Maybe in the future even close connection..
*/
static void remove_bsc_connection(struct bsc_connection *connection)
{
bsc_unregister_fd(&connection->bsc_fd);
llist_del(&connection->list_entry);
talloc_free(connection);
}
static int forward_sccp_to_msc(struct msgb *msg)
{
/* FIXME: We need to filter out certain messages */
/* drop packets with the wrong IPA header */
if (bsc_nat_filter_ipa(msg))
return 0;
/* send the non-filtered but maybe modified msg */
return write(msc_connection.fd, msg->data, msg->len);
}
static int ipaccess_bsc_cb(struct bsc_fd *bfd, unsigned int what)
{
int error;
struct msgb *msg = ipaccess_read_msg(bfd, &error);
if (!msg) {
if (error == 0) {
fprintf(stderr, "The connection to the BSC was lost. Cleaning it\n");
remove_bsc_connection((struct bsc_connection *) bfd->data);
}
fprintf(stderr, "Failed to parse ip access message: %d\n", error);
return -1;
}
DEBUGP(DMSC, "MSG from BSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
/* Handle messages from the BSC */
/* FIXME: Currently no PONG is sent to the BSC */
/* FIXME: Currently no ID ACK is sent to the BSC */
forward_sccp_to_msc(msg);
return 0;
}
static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what)
{
struct bsc_connection *bsc;
int ret;
struct sockaddr_in sa;
socklen_t sa_len = sizeof(sa);
if (!(what & BSC_FD_READ))
return 0;
ret = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len);
if (ret < 0) {
perror("accept");
return ret;
}
/* todo... do something with the connection */
/* todo... use GNUtls to see if we want to trust this as a BTS */
/*
*
*/
bsc = talloc_zero(tall_bsc_ctx, struct bsc_connection);
if (!bsc) {
DEBUGP(DMSC, "Failed to allocate BSC struct.\n");
close(ret);
return -1;
}
bsc->bsc_fd.data = bsc;
bsc->bsc_fd.fd = ret;
bsc->bsc_fd.cb = ipaccess_bsc_cb;
bsc->bsc_fd.when = BSC_FD_READ;
if (bsc_register_fd(&bsc->bsc_fd) < 0) {
DEBUGP(DMSC, "Failed to register BSC fd.\n");
close(ret);
talloc_free(bsc);
return -2;
}
DEBUGP(DMSC, "Registered new BSC\n");
llist_add(&bsc->list_entry, &bsc_connections);
ipaccess_send_id_ack(ret);
return 0;
}
static int listen_for_bsc(struct bsc_fd *bfd, struct in_addr *in_addr, int port)
{
struct sockaddr_in addr;
int ret, on = 1;
bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
bfd->cb = ipaccess_listen_bsc_cb;
bfd->when = BSC_FD_READ;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = in_addr->s_addr;
setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
if (ret < 0) {
fprintf(stderr, "Could not bind the BSC socket %s\n",
strerror(errno));
return -EIO;
}
ret = listen(bfd->fd, 1);
if (ret < 0) {
perror("listen");
return ret;
}
ret = bsc_register_fd(bfd);
if (ret < 0) {
perror("register_listen_fd");
return ret;
}
return 0;
}
static void print_usage()
{
printf("Usage: bsc_nat\n");
}
static void print_help()
{
printf(" Some useful help...\n");
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(" -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 this BSC.\n");
}
static void handle_options(int argc, char** argv)
{
while (1) {
int option_index = 0, c;
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"debug", 1, 0, 'd'},
{"config-file", 1, 0, 'c'},
{"disable-color", 0, 0, 's'},
{"timestamp", 0, 0, 'T'},
{"msc", 1, 0, 'm'},
{"local", 1, 0, 'l'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, "hd:sTPc:m:l:",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 'h':
print_usage();
print_help();
exit(0);
case 's':
debug_use_color(0);
break;
case 'd':
debug_parse_category_mask(optarg);
break;
case 'c':
config_file = strdup(optarg);
break;
case 'T':
debug_timestamp(1);
break;
case 'm':
msc_address = strdup(optarg);
break;
case 'l':
inet_aton(optarg, &local_addr);
break;
default:
/* ignore */
break;
}
}
}
static void signal_handler(int signal)
{
fprintf(stdout, "signal %u received\n", signal);
switch (signal) {
case SIGABRT:
/* in case of abort, we want to obtain a talloc report
* and then return to the caller, who will abort the process */
case SIGUSR1:
talloc_report_full(tall_bsc_ctx, stderr);
break;
default:
break;
}
}
int main(int argc, char** argv)
{
int rc;
/* parse options */
local_addr.s_addr = INADDR_ANY;
handle_options(argc, argv);
/* seed the PRNG */
srand(time(NULL));
/* connect to the MSC */
msc_connection.cb = ipaccess_msc_cb;
rc = connect_to_msc(&msc_connection, msc_address, 5000);
if (rc < 0) {
fprintf(stderr, "Opening the MSC connection failed.\n");
exit(1);
}
/* wait for the BSC */
if (listen_for_bsc(&bsc_connection, &local_addr, 5000) < 0) {
fprintf(stderr, "Failed to listen for BSC.\n");
exit(1);
}
signal(SIGINT, &signal_handler);
signal(SIGABRT, &signal_handler);
signal(SIGUSR1, &signal_handler);
signal(SIGPIPE, SIG_IGN);
while (1) {
bsc_select_main(0);
}
return 0;
}

View File

@@ -160,7 +160,7 @@ static void paging_handle_pending_requests(struct gsm_bts_paging_state *paging_b
} while (paging_bts->available_slots > 0 } while (paging_bts->available_slots > 0
&& initial_request != current_request); && initial_request != current_request);
bsc_schedule_timer(&paging_bts->work_timer, 1, 0); bsc_schedule_timer(&paging_bts->work_timer, 2, 0);
} }
static void paging_worker(void *data) static void paging_worker(void *data)
@@ -245,7 +245,7 @@ static int _paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscr,
llist_add_tail(&req->entry, &bts_entry->pending_requests); llist_add_tail(&req->entry, &bts_entry->pending_requests);
if (!bsc_timer_pending(&bts_entry->work_timer)) if (!bsc_timer_pending(&bts_entry->work_timer))
bsc_schedule_timer(&bts_entry->work_timer, 1, 0); bsc_schedule_timer(&bts_entry->work_timer, 2, 0);
return 0; return 0;
} }

View File

@@ -37,7 +37,7 @@ int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos)
memset(&bv, 0, sizeof(bv)); memset(&bv, 0, sizeof(bv));
bv.data = data; bv.data = data;
bv.data_len = 2; bv.data_len = 1;
if (nch_pos) { if (nch_pos) {
bitvec_set_bit(&bv, H); bitvec_set_bit(&bv, H);
@@ -45,7 +45,7 @@ int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos)
} else } else
bitvec_set_bit(&bv, L); bitvec_set_bit(&bv, L);
bitvec_spare_padding(&bv, 15); bitvec_spare_padding(&bv, 7);
return 0; return 0;
} }
@@ -95,7 +95,7 @@ int rest_octets_si3(u_int8_t *data, const struct gsm48_si_ro_info *si3)
memset(&bv, 0, sizeof(bv)); memset(&bv, 0, sizeof(bv));
bv.data = data; bv.data = data;
bv.data_len = 5; bv.data_len = 4;
/* Optional Selection Parameters */ /* Optional Selection Parameters */
append_selection_params(&bv, &si3->selection_params); append_selection_params(&bv, &si3->selection_params);
@@ -141,7 +141,7 @@ int rest_octets_si4(u_int8_t *data, const struct gsm48_si_ro_info *si4)
memset(&bv, 0, sizeof(bv)); memset(&bv, 0, sizeof(bv));
bv.data = data; bv.data = data;
bv.data_len = 11; /* FIXME: up to ? */ bv.data_len = 10; /* FIXME: up to ? */
/* SI4 Rest Octets O */ /* SI4 Rest Octets O */
append_selection_params(&bv, &si4->selection_params); append_selection_params(&bv, &si4->selection_params);
@@ -340,7 +340,7 @@ int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13)
memset(&bv, 0, sizeof(bv)); memset(&bv, 0, sizeof(bv));
bv.data = data; bv.data = data;
bv.data_len = 21; bv.data_len = 20;
if (0) { if (0) {
/* No rest octets */ /* No rest octets */

View File

@@ -1,8 +1,8 @@
/* /*
* SCCP management code * SCCP management code
* *
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org> * (C) 2009, 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2009 by on-waves.com * (C) 2009, 2010 by on-waves.com
* *
* All Rights Reserved * All Rights Reserved
* *
@@ -199,6 +199,134 @@ static int _sccp_parse_optional_data(const int offset,
return -1; return -1;
} }
int _sccp_parse_connection_request(struct msgb *msgb, struct sccp_parse_result *result)
{
static const u_int32_t header_size =
sizeof(struct sccp_connection_request);
static const u_int32_t optional_offset =
offsetof(struct sccp_connection_request, optional_start);
static const u_int32_t called_offset =
offsetof(struct sccp_connection_request, variable_called);
struct sccp_connection_request *req = (struct sccp_connection_request *)msgb->data;
struct sccp_optional_data optional_data;
/* header check */
if (msgb_l2len(msgb) < header_size) {
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
msgb_l2len(msgb), header_size);
return -1;
}
/* copy out the calling and called address. Add the offset */
if (copy_address(&result->called, called_offset + req->variable_called, msgb) != 0)
return -1;
if (check_address(&result->called) != 0) {
DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
*(u_int8_t *)&result->called.address, result->called.ssn);
return -1;
}
result->source_local_reference = &req->source_local_reference;
/*
* parse optional data.
*/
memset(&optional_data, 0, sizeof(optional_data));
if (_sccp_parse_optional_data(optional_offset + req->optional_start, msgb, &optional_data) != 0) {
DEBUGP(DSCCP, "parsing of optional data failed.\n");
return -1;
}
if (optional_data.data_len != 0) {
msgb->l3h = &msgb->l2h[optional_data.data_start];
result->data_len = optional_data.data_len;
} else {
result->data_len = 0;
}
return 0;
}
int _sccp_parse_connection_released(struct msgb *msg, struct sccp_parse_result *result)
{
return -1;
}
int _sccp_parse_connection_refused(struct msgb *msg, struct sccp_parse_result *result)
{
return -1;
}
int _sccp_parse_connection_confirm(struct msgb *msg, struct sccp_parse_result *result)
{
return -1;
}
int _sccp_parse_connection_release_complete(struct msgb *msg, struct sccp_parse_result *result)
{
return -1;
}
int _sccp_parse_connection_dt1(struct msgb *msg, struct sccp_parse_result *result)
{
return -1;
}
int _sccp_parse_udt(struct msgb *msgb, struct sccp_parse_result *result)
{
static const u_int32_t header_size = sizeof(struct sccp_data_unitdata);
static const u_int32_t called_offset = offsetof(struct sccp_data_unitdata, variable_called);
static const u_int32_t calling_offset = offsetof(struct sccp_data_unitdata, variable_calling);
static const u_int32_t data_offset = offsetof(struct sccp_data_unitdata, variable_data);
struct sccp_data_unitdata *udt = (struct sccp_data_unitdata *)msgb->l2h;
if (msgb_l2len(msgb) < header_size) {
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
msgb_l2len(msgb), header_size);
return -1;
}
/* copy out the calling and called address. Add the off */
if (copy_address(&result->called, called_offset + udt->variable_called, msgb) != 0)
return -1;
if (check_address(&result->called) != 0) {
DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
*(u_int8_t *)&result->called.address, result->called.ssn);
return -1;
}
if (copy_address(&result->calling, calling_offset + udt->variable_calling, msgb) != 0)
return -1;
if (check_address(&result->calling) != 0) {
DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
*(u_int8_t *)&result->called.address, result->called.ssn);
}
/* we don't have enough size for the data */
if (msgb_l2len(msgb) < data_offset + udt->variable_data + 1) {
DEBUGP(DSCCP, "msgb < header + offset %u %u %u\n",
msgb_l2len(msgb), header_size, udt->variable_data);
return -1;
}
msgb->l3h = &udt->data[udt->variable_data];
if (msgb_l3len(msgb) != msgb->l3h[-1]) {
DEBUGP(DSCCP, "msgb is truncated %u %u\n",
msgb_l3len(msgb), msgb->l3h[-1]);
return -1;
}
return 0;
}
/* /*
* Send UDT. Currently we have a fixed address... * Send UDT. Currently we have a fixed address...
*/ */
@@ -249,59 +377,15 @@ static int _sccp_send_data(int class, const struct sockaddr_sccp *in,
static int _sccp_handle_read(struct msgb *msgb) static int _sccp_handle_read(struct msgb *msgb)
{ {
static const u_int32_t header_size = sizeof(struct sccp_data_unitdata);
static const u_int32_t called_offset = offsetof(struct sccp_data_unitdata, variable_called);
static const u_int32_t calling_offset = offsetof(struct sccp_data_unitdata, variable_calling);
static const u_int32_t data_offset = offsetof(struct sccp_data_unitdata, variable_data);
struct sccp_data_callback *cb; struct sccp_data_callback *cb;
struct sccp_data_unitdata *udt = (struct sccp_data_unitdata *)msgb->l2h; struct sccp_parse_result result;
struct sccp_address called, calling;
/* we don't have enough size for the struct */ if (_sccp_parse_udt(msgb, &result) != 0)
if (msgb_l2len(msgb) < header_size) {
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
msgb_l2len(msgb), header_size);
return -1;
}
/* copy out the calling and called address. Add the off */
if (copy_address(&called, called_offset + udt->variable_called, msgb) != 0)
return -1; return -1;
if (check_address(&called) != 0) { cb = _find_ssn(result.called.ssn);
DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
*(u_int8_t *)&called.address, called.ssn);
return -1;
}
cb = _find_ssn(called.ssn);
if (!cb || !cb->read_cb) { if (!cb || !cb->read_cb) {
DEBUGP(DSCCP, "No routing for UDT for called SSN: %u\n", called.ssn); DEBUGP(DSCCP, "No routing for UDT for called SSN: %u\n", result.called.ssn);
return -1;
}
if (copy_address(&calling, calling_offset + udt->variable_calling, msgb) != 0)
return -1;
if (check_address(&calling) != 0) {
DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
*(u_int8_t *)&called.address, called.ssn);
}
/* we don't have enough size for the data */
if (msgb_l2len(msgb) < data_offset + udt->variable_data + 1) {
DEBUGP(DSCCP, "msgb < header + offset %u %u %u\n",
msgb_l2len(msgb), header_size, udt->variable_data);
return -1;
}
msgb->l3h = &udt->data[udt->variable_data];
if (msgb_l3len(msgb) != msgb->l3h[-1]) {
DEBUGP(DSCCP, "msgb is truncated %u %u\n",
msgb_l3len(msgb), msgb->l3h[-1]);
return -1; return -1;
} }
@@ -374,7 +458,7 @@ static void _sccp_set_connection_state(struct sccp_connection *connection, int n
connection->state_cb(connection, old_state); connection->state_cb(connection, old_state);
} }
static int _sccp_send_refuse(struct sccp_connection_request *req, int cause) static int _sccp_send_refuse(struct sccp_source_reference *src_ref, int cause)
{ {
struct msgb *msgb; struct msgb *msgb;
struct sccp_connection_refused *ref; struct sccp_connection_refused *ref;
@@ -387,7 +471,7 @@ static int _sccp_send_refuse(struct sccp_connection_request *req, int cause)
ref = (struct sccp_connection_refused *) msgb_put(msgb, sizeof(*ref)); ref = (struct sccp_connection_refused *) msgb_put(msgb, sizeof(*ref));
ref->type = SCCP_MSG_TYPE_CREF; ref->type = SCCP_MSG_TYPE_CREF;
memcpy(&ref->destination_local_reference, &req->source_local_reference, memcpy(&ref->destination_local_reference, src_ref,
sizeof(struct sccp_source_reference)); sizeof(struct sccp_source_reference));
ref->cause = cause; ref->cause = cause;
ref->optional_start = 1; ref->optional_start = 1;
@@ -601,39 +685,17 @@ static int _sccp_send_connection_released(struct sccp_connection *conn, int caus
*/ */
static int _sccp_handle_connection_request(struct msgb *msgb) static int _sccp_handle_connection_request(struct msgb *msgb)
{ {
static const u_int32_t header_size = struct sccp_parse_result result;
sizeof(struct sccp_connection_request);
static const u_int32_t optional_offset =
offsetof(struct sccp_connection_request, optional_start);
static const u_int32_t called_offset =
offsetof(struct sccp_connection_request, variable_called);
struct sccp_data_callback *cb; struct sccp_data_callback *cb;
struct sccp_connection_request *req = (struct sccp_connection_request *)msgb->data;
struct sccp_address called;
struct sccp_connection *connection; struct sccp_connection *connection;
struct sccp_optional_data optional_data;
/* header check */ if (_sccp_parse_connection_request(msgb, &result) != 0)
if (msgb_l2len(msgb) < header_size) {
DEBUGP(DSCCP, "msgb < header_size %u %u\n",
msgb_l2len(msgb), header_size);
return -1;
}
/* copy out the calling and called address. Add the offset */
if (copy_address(&called, called_offset + req->variable_called, msgb) != 0)
return -1; return -1;
if (check_address(&called) != 0) { cb = _find_ssn(result.called.ssn);
DEBUGP(DSCCP, "Invalid called address according to 08.06: 0x%x 0x%x\n",
*(u_int8_t *)&called.address, called.ssn);
return -1;
}
cb = _find_ssn(called.ssn);
if (!cb || !cb->accept_cb) { if (!cb || !cb->accept_cb) {
DEBUGP(DSCCP, "No routing for CR for called SSN: %u\n", called.ssn); DEBUGP(DSCCP, "No routing for CR for called SSN: %u\n", result.called.ssn);
return -1; return -1;
} }
@@ -651,28 +713,18 @@ static int _sccp_handle_connection_request(struct msgb *msgb)
* and send a connection confirm, otherwise we will send a refuseed * and send a connection confirm, otherwise we will send a refuseed
* one.... * one....
*/ */
if (destination_local_reference_is_free(&req->source_local_reference) != 0) { if (destination_local_reference_is_free(result.source_local_reference) != 0) {
DEBUGP(DSCCP, "Need to reject connection with existing reference\n"); DEBUGP(DSCCP, "Need to reject connection with existing reference\n");
_sccp_send_refuse(req, SCCP_REFUSAL_SCCP_FAILURE); _sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_SCCP_FAILURE);
talloc_free(connection); talloc_free(connection);
return -1; return -1;
} }
connection->incoming = 1; connection->incoming = 1;
connection->destination_local_reference = req->source_local_reference; connection->destination_local_reference = *result.source_local_reference;
/*
* parse optional data.
*/
memset(&optional_data, 0, sizeof(optional_data));
if (_sccp_parse_optional_data(optional_offset + req->optional_start, msgb, &optional_data) != 0) {
DEBUGP(DSCCP, "parsing of optional data failed.\n");
talloc_free(connection);
return -1;
}
if (cb->accept_cb(connection, cb->accept_context) != 0) { if (cb->accept_cb(connection, cb->accept_context) != 0) {
_sccp_send_refuse(req, SCCP_REFUSAL_END_USER_ORIGINATED); _sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_END_USER_ORIGINATED);
_sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED); _sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED);
talloc_free(connection); talloc_free(connection);
return 0; return 0;
@@ -684,7 +736,7 @@ static int _sccp_handle_connection_request(struct msgb *msgb)
if (_sccp_send_connection_confirm(connection) != 0) { if (_sccp_send_connection_confirm(connection) != 0) {
DEBUGP(DSCCP, "Sending confirm failed... no available source reference?\n"); DEBUGP(DSCCP, "Sending confirm failed... no available source reference?\n");
_sccp_send_refuse(req, SCCP_REFUSAL_SCCP_FAILURE); _sccp_send_refuse(result.source_local_reference, SCCP_REFUSAL_SCCP_FAILURE);
_sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED); _sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_REFUSED);
llist_del(&connection->list); llist_del(&connection->list);
talloc_free(connection); talloc_free(connection);
@@ -695,9 +747,8 @@ static int _sccp_handle_connection_request(struct msgb *msgb)
/* /*
* If we have data let us forward things. * If we have data let us forward things.
*/ */
if (optional_data.data_len != 0 && connection->data_cb) { if (result.data_len != 0 && connection->data_cb) {
msgb->l3h = &msgb->l2h[optional_data.data_start]; connection->data_cb(connection, msgb, result.data_len);
connection->data_cb(connection, msgb, optional_data.data_len);
} }
return 0; return 0;
@@ -1160,6 +1211,14 @@ struct sccp_source_reference sccp_src_ref_from_int(u_int32_t int_ref)
return ref; return ref;
} }
int sccp_determine_msg_type(struct msgb *msg)
{
if (msgb_l2len(msg) < 1)
return -1;
return msg->l2h[0];
}
static __attribute__((constructor)) void on_dso_load(void) static __attribute__((constructor)) void on_dso_load(void)
{ {
tall_sccp_ctx = talloc_named_const(NULL, 1, "sccp"); tall_sccp_ctx = talloc_named_const(NULL, 1, "sccp");

View File

@@ -319,6 +319,8 @@ static int generate_si5(u_int8_t *output, struct gsm_bts *bts)
struct gsm48_system_information_type_5 *si5; struct gsm48_system_information_type_5 *si5;
int rc, l2_plen = 18; int rc, l2_plen = 18;
memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
/* ip.access nanoBTS needs l2_plen!! */ /* ip.access nanoBTS needs l2_plen!! */
if (is_ipaccess_bts(bts)) { if (is_ipaccess_bts(bts)) {
*output++ = (l2_plen << 2) | 1; *output++ = (l2_plen << 2) | 1;
@@ -326,7 +328,6 @@ static int generate_si5(u_int8_t *output, struct gsm_bts *bts)
} }
si5 = (struct gsm48_system_information_type_5 *) output; si5 = (struct gsm48_system_information_type_5 *) output;
memset(si5, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
/* l2 pseudo length, not part of msg: 18 */ /* l2 pseudo length, not part of msg: 18 */
si5->rr_protocol_discriminator = GSM48_PDISC_RR; si5->rr_protocol_discriminator = GSM48_PDISC_RR;
@@ -345,6 +346,8 @@ static int generate_si6(u_int8_t *output, struct gsm_bts *bts)
struct gsm48_system_information_type_6 *si6; struct gsm48_system_information_type_6 *si6;
int l2_plen = 11; int l2_plen = 11;
memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
/* ip.access nanoBTS needs l2_plen!! */ /* ip.access nanoBTS needs l2_plen!! */
if (is_ipaccess_bts(bts)) { if (is_ipaccess_bts(bts)) {
*output++ = (l2_plen << 2) | 1; *output++ = (l2_plen << 2) | 1;
@@ -352,7 +355,6 @@ static int generate_si6(u_int8_t *output, struct gsm_bts *bts)
} }
si6 = (struct gsm48_system_information_type_6 *) output; si6 = (struct gsm48_system_information_type_6 *) output;
memset(si6, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
/* l2 pseudo length, not part of msg: 11 */ /* l2 pseudo length, not part of msg: 11 */
si6->rr_protocol_discriminator = GSM48_PDISC_RR; si6->rr_protocol_discriminator = GSM48_PDISC_RR;

View File

@@ -28,6 +28,7 @@
#include <openbsc/gsm_04_08.h> #include <openbsc/gsm_04_08.h>
#include <openbsc/mncc.h> #include <openbsc/mncc.h>
#include <openbsc/paging.h> #include <openbsc/paging.h>
#include <openbsc/chan_alloc.h>
void *tall_trans_ctx; void *tall_trans_ctx;
@@ -95,14 +96,14 @@ void trans_free(struct gsm_trans *trans)
break; break;
} }
if (trans->lchan)
put_lchan(trans->lchan);
if (!trans->lchan && trans->subscr && trans->subscr->net) { if (!trans->lchan && trans->subscr && trans->subscr->net) {
/* Stop paging on all bts' */ /* Stop paging on all bts' */
paging_request_stop(NULL, trans->subscr, NULL); paging_request_stop(NULL, trans->subscr, NULL);
} }
if (trans->lchan)
put_lchan(trans->lchan);
if (trans->subscr) if (trans->subscr)
subscr_put(trans->subscr); subscr_put(trans->subscr);

View File

@@ -76,6 +76,8 @@ static void net_dump_nmstate(struct vty *vty, struct gsm_nm_state *nms)
static void net_dump_vty(struct vty *vty, struct gsm_network *net) static void net_dump_vty(struct vty *vty, struct gsm_network *net)
{ {
int i;
vty_out(vty, "BSC is on Country Code %u, Network Code %u " vty_out(vty, "BSC is on Country Code %u, Network Code %u "
"and has %u BTS%s", net->country_code, net->network_code, "and has %u BTS%s", net->country_code, net->network_code,
net->num_bts, VTY_NEWLINE); net->num_bts, VTY_NEWLINE);
@@ -97,6 +99,11 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net)
VTY_NEWLINE); VTY_NEWLINE);
vty_out(vty, " Handover: %s%s", net->handover.active ? "On" : "Off", vty_out(vty, " Handover: %s%s", net->handover.active ? "On" : "Off",
VTY_NEWLINE); VTY_NEWLINE);
vty_out(vty, " Allowed Audio Codecs: ");
for (i = 0; i < net->audio_length; ++i)
vty_out(vty, "hr: %d ver: %d, ",
net->audio_support[i]->hr, net->audio_support[i]->ver);
vty_out(vty, "%s", VTY_NEWLINE);
} }
DEFUN(show_net, show_net_cmd, "show network", DEFUN(show_net, show_net_cmd, "show network",
@@ -287,7 +294,11 @@ static int config_write_net(struct vty *vty)
{ {
vty_out(vty, "network%s", VTY_NEWLINE); vty_out(vty, "network%s", VTY_NEWLINE);
vty_out(vty, " network country code %u%s", gsmnet->country_code, VTY_NEWLINE); vty_out(vty, " network country code %u%s", gsmnet->country_code, VTY_NEWLINE);
if (gsmnet->core_country_code > 0)
vty_out(vty, " core network country code %u%s", gsmnet->core_country_code, VTY_NEWLINE);
vty_out(vty, " mobile network code %u%s", gsmnet->network_code, VTY_NEWLINE); vty_out(vty, " mobile network code %u%s", gsmnet->network_code, VTY_NEWLINE);
if (gsmnet->core_network_code > 0)
vty_out(vty, " core mobile network code %u%s", gsmnet->core_network_code, VTY_NEWLINE);
vty_out(vty, " short name %s%s", gsmnet->name_short, VTY_NEWLINE); vty_out(vty, " short name %s%s", gsmnet->name_short, VTY_NEWLINE);
vty_out(vty, " long name %s%s", gsmnet->name_long, VTY_NEWLINE); vty_out(vty, " long name %s%s", gsmnet->name_long, VTY_NEWLINE);
vty_out(vty, " auth policy %s%s", gsm_auth_policy_name(gsmnet->auth_policy), VTY_NEWLINE); vty_out(vty, " auth policy %s%s", gsm_auth_policy_name(gsmnet->auth_policy), VTY_NEWLINE);
@@ -322,6 +333,25 @@ static int config_write_net(struct vty *vty)
vty_out(vty, " timer t3117 %u%s", gsmnet->T3117, VTY_NEWLINE); vty_out(vty, " timer t3117 %u%s", gsmnet->T3117, VTY_NEWLINE);
vty_out(vty, " timer t3119 %u%s", gsmnet->T3119, VTY_NEWLINE); vty_out(vty, " timer t3119 %u%s", gsmnet->T3119, VTY_NEWLINE);
vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE); vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE);
vty_out(vty, " ipacc rtp_payload %u%s", gsmnet->rtp_payload, VTY_NEWLINE);
vty_out(vty, " rtp base %u%s", gsmnet->rtp_base_port, VTY_NEWLINE);
if (gsmnet->audio_length != 0) {
int i;
vty_out(vty, " codec_list ");
for (i = 0; i < gsmnet->audio_length; ++i) {
printf("I... %d %d\n", i, gsmnet->audio_length);
if (i != 0)
vty_out(vty, ", ");
if (gsmnet->audio_support[i]->hr)
vty_out(vty, "hr%.1u", gsmnet->audio_support[i]->ver);
else
vty_out(vty, "fr%.1u", gsmnet->audio_support[i]->ver);
}
vty_out(vty, "%s", VTY_NEWLINE);
}
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@@ -818,6 +848,16 @@ DEFUN(cfg_net_ncc,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN(cfg_core_net_ncc,
cfg_core_net_ncc_cmd,
"core network country code <1-999>",
"Set the GSM country code to be used in the MSC connection")
{
gsmnet->core_country_code = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_mnc, DEFUN(cfg_net_mnc,
cfg_net_mnc_cmd, cfg_net_mnc_cmd,
"mobile network code <1-999>", "mobile network code <1-999>",
@@ -828,6 +868,16 @@ DEFUN(cfg_net_mnc,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN(cfg_core_net_mnc,
cfg_core_net_mnc_cmd,
"core mobile network code <1-999>",
"Set the GSM mobile network code to be used in the MSC connection")
{
gsmnet->core_network_code = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_name_short, DEFUN(cfg_net_name_short,
cfg_net_name_short_cmd, cfg_net_name_short_cmd,
"short name NAME", "short name NAME",
@@ -976,6 +1026,90 @@ DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN(cfg_net_supported_codecs,
cfg_net_supported_codecs_cmd,
"codec_list .LIST",
"Set the three preferred audio codecs.\n"
"Codec List")
{
int saw_fr, saw_hr;
int i;
saw_fr = saw_hr = 0;
/* free the old list... if it exists */
if (gsmnet->audio_support) {
talloc_free(gsmnet->audio_support);
gsmnet->audio_support = NULL;
gsmnet->audio_length = 0;
}
/* create a new array */
gsmnet->audio_support =
talloc_zero_array(gsmnet, struct gsm_audio_support *, argc);
gsmnet->audio_length = argc;
for (i = 0; i < argc; ++i) {
/* check for hrX or frX */
if (strlen(argv[i]) != 3
|| argv[i][1] != 'r'
|| (argv[i][0] != 'h' && argv[i][0] != 'f')
|| argv[i][2] < 0x30
|| argv[i][2] > 0x39)
goto error;
gsmnet->audio_support[i] = talloc_zero(gsmnet->audio_support,
struct gsm_audio_support);
gsmnet->audio_support[i]->ver = atoi(argv[i] + 2);
if (strncmp("hr", argv[i], 2) == 0) {
gsmnet->audio_support[i]->hr = 1;
saw_hr = 1;
} else if (strncmp("fr", argv[i], 2) == 0) {
gsmnet->audio_support[i]->hr = 0;
saw_fr = 1;
}
if (saw_hr && saw_fr) {
vty_out(vty, "Can not have full-rate and half-rate codec.%s",
VTY_NEWLINE);
return CMD_ERR_INCOMPLETE;
}
}
return CMD_SUCCESS;
error:
vty_out(vty, "Codec name must be hrX or frX. Was '%s'%s",
argv[i], VTY_NEWLINE);
return CMD_ERR_INCOMPLETE;
}
DEFUN(cfg_net_ipacc_rtp_payload,
cfg_net_ipacc_rtp_payload_cmd,
"ipacc rtp_payload <0-256>",
"Override the RTP payload to use")
{
gsmnet->rtp_payload = atoi(argv[0]) & 0xff;
return CMD_SUCCESS;
}
DEFUN(cfg_net_rtp_base_port,
cfg_net_rtp_base_port_cmd,
"rtp base <0-65534>",
"Base port to use for MGCP RTP")
{
unsigned int port = atoi(argv[0]);
if (port > 65534) {
vty_out(vty, "%% wrong base port '%s'%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
gsmnet->rtp_base_port = port;
return CMD_SUCCESS;
}
#define DECLARE_TIMER(number) \ #define DECLARE_TIMER(number) \
DEFUN(cfg_net_T##number, \ DEFUN(cfg_net_T##number, \
cfg_net_T##number##_cmd, \ cfg_net_T##number##_cmd, \
@@ -986,7 +1120,7 @@ DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd,
\ \
if (value < 0 || value > 65535) { \ if (value < 0 || value > 65535) { \
vty_out(vty, "Timer value %s out of range.%s", \ vty_out(vty, "Timer value %s out of range.%s", \
argv[0], VTY_NEWLINE); \ argv[0], VTY_NEWLINE); \
return CMD_WARNING; \ return CMD_WARNING; \
} \ } \
\ \
@@ -1006,7 +1140,6 @@ DECLARE_TIMER(3117)
DECLARE_TIMER(3119) DECLARE_TIMER(3119)
DECLARE_TIMER(3141) DECLARE_TIMER(3141)
/* per-BTS configuration */ /* per-BTS configuration */
DEFUN(cfg_bts, DEFUN(cfg_bts,
cfg_bts_cmd, cfg_bts_cmd,
@@ -1476,7 +1609,9 @@ int bsc_vty_init(struct gsm_network *net)
install_node(&net_node, config_write_net); install_node(&net_node, config_write_net);
install_default(GSMNET_NODE); install_default(GSMNET_NODE);
install_element(GSMNET_NODE, &cfg_net_ncc_cmd); install_element(GSMNET_NODE, &cfg_net_ncc_cmd);
install_element(GSMNET_NODE, &cfg_core_net_ncc_cmd);
install_element(GSMNET_NODE, &cfg_net_mnc_cmd); install_element(GSMNET_NODE, &cfg_net_mnc_cmd);
install_element(GSMNET_NODE, &cfg_core_net_mnc_cmd);
install_element(GSMNET_NODE, &cfg_net_name_short_cmd); install_element(GSMNET_NODE, &cfg_net_name_short_cmd);
install_element(GSMNET_NODE, &cfg_net_name_long_cmd); install_element(GSMNET_NODE, &cfg_net_name_long_cmd);
install_element(GSMNET_NODE, &cfg_net_auth_policy_cmd); install_element(GSMNET_NODE, &cfg_net_auth_policy_cmd);
@@ -1492,6 +1627,9 @@ int bsc_vty_init(struct gsm_network *net)
install_element(GSMNET_NODE, &cfg_net_ho_pwr_interval_cmd); install_element(GSMNET_NODE, &cfg_net_ho_pwr_interval_cmd);
install_element(GSMNET_NODE, &cfg_net_ho_pwr_hysteresis_cmd); install_element(GSMNET_NODE, &cfg_net_ho_pwr_hysteresis_cmd);
install_element(GSMNET_NODE, &cfg_net_ho_max_distance_cmd); install_element(GSMNET_NODE, &cfg_net_ho_max_distance_cmd);
install_element(GSMNET_NODE, &cfg_net_supported_codecs_cmd);
install_element(GSMNET_NODE, &cfg_net_ipacc_rtp_payload_cmd);
install_element(GSMNET_NODE, &cfg_net_rtp_base_port_cmd);
install_element(GSMNET_NODE, &cfg_net_T3101_cmd); install_element(GSMNET_NODE, &cfg_net_T3101_cmd);
install_element(GSMNET_NODE, &cfg_net_T3103_cmd); install_element(GSMNET_NODE, &cfg_net_T3103_cmd);
install_element(GSMNET_NODE, &cfg_net_T3105_cmd); install_element(GSMNET_NODE, &cfg_net_T3105_cmd);

View File

@@ -0,0 +1,48 @@
/* OpenBSC interface to quagga VTY - BSC options */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* 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 <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <vty/command.h>
#include <vty/buffer.h>
#include <vty/vty.h>
#include <openbsc/gsm_data.h>
static struct gsmnet *gsmnet = NULL;
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);
return CMD_SUCCESS;
}
int bsc_vty_init_extra(struct gsm_network *net)
{
gsmnet = net;
/* get runtime information */
install_element(VIEW_NODE, &show_bsc_cmd);
return 0;
}

View File

@@ -76,4 +76,5 @@ int main(int argc, char** argv)
void nm_state_event() {} void nm_state_event() {}
void input_event() {} void input_event() {}
void sms_alloc() {} void sms_alloc() {}
void _lchan_release() {}