Compare commits

...

122 Commits

Author SHA1 Message Date
Holger Hans Peter Freyther
2ad760fe5f Versioning... 2010-06-13 14:24:11 +08:00
Holger Hans Peter Freyther
fea0aebd36 bsc_msc_ip: Attempt to plug an lchan leak...
If we end up with a channel that has refcount of zero,
has no msc_data attached and the handler has not returned
1 we will just close it.
2010-06-13 14:15:39 +08:00
Holger Hans Peter Freyther
c9b7d74a08 channel: Keep track on when a channel got allocated.
This can help to detect 'stale' channels in a network.
2010-06-13 12:38:35 +08:00
Holger Hans Peter Freyther
42a4e9a52d abis_rsl: Reduce logging to LOGL_DEBUG as it is quite nosiy
The nanoBTS will send us at least one measurement report
after we have decided to close the channel... degrade that
output to a debug message.
2010-06-13 10:09:45 +08:00
Holger Hans Peter Freyther
d4f7a81992 nat: Fix the access-list-name command...
We have added two commands with the same name to the tree..
the second one should have been the BSC...
2010-06-08 11:18:26 +08:00
Holger Hans Peter Freyther
cd4afce470 nat: Add both entries to the tail to keep the order they are inserted 2010-06-08 11:00:09 +08:00
Holger Hans Peter Freyther
299d5aa2a4 nat: Allow to specify multiple entries in the access-list...
Inside the access-list we have a list of entries that have
either one allow or one deny rule... we do not allow to remove
a single rule but one has to remove the whole list, in that case
talloc will handle cleaning all entries.

Right now the matching is O(n*m) as we traverse the list
(multiple times) and run the regexp multiple times. One
way to make it faster would be to concat all regexps into
one.
2010-06-08 10:53:39 +08:00
Holger Hans Peter Freyther
f85e93cd4d nat: Shorten the access-list struct and method names (still way too long) 2010-06-08 10:14:44 +08:00
Holger Hans Peter Freyther
fdfaf9c519 bsc_msc_ip: Possible crash fix on the early assignment code path
The crash happened when we had released the primary channel
for one reason or another but still got the assignment complete
on the secondary. This null checking is some extra caution, with
the previous commit we should fail the msc_data test early in
this method.
2010-06-07 22:32:10 +08:00
Holger Hans Peter Freyther
4d4e6714cd bsc_msc_ip: When closing the SCCP check primary and secondary lchan
When closing a SCCP connection and any of the two lchan's are open,
then close them down properly.

Move the lchan freeing into a new method and call that one from the
SCCP connection close handling. Move the bss scp data varaible to
the top of the context..
2010-06-07 22:28:56 +08:00
Holger Hans Peter Freyther
3806b070bb Version bump... 2010-06-07 15:02:01 +08:00
Holger Hans Peter Freyther
3dd069cfd7 bssap.c: Claim to always do HR AMR right now.
The bssap.c code is sending a multirate config with
only AMR 5.9kb marked as supported, the MSC does not
like if we assign a FR channel and send the GSM 0808
FR AMR mode back to the MSC. So change the code to
not look at the channel type for AMR...
2010-06-07 14:47:25 +08:00
Harald Welte
e1dcbc7622 [GPRS] Change SI13 to NMO_II, as some phones (like G1) dislike NMO_III
I still believe NMO_III is what we want, but as indiciated some phones
absolutely refuse to even connect to the GPRS network in this mode :(
2010-06-07 12:26:12 +08:00
Holger Hans Peter Freyther
6be75737c4 Revert "bsc_init: Set the paging config like in the trace..."
I added this to have the patch in the history, I don't think
that we need to include this but it is good to have it cherry
pickable in the history.

This reverts commit 290a11d0ad.
2010-06-06 21:32:02 +08:00
Holger Hans Peter Freyther
290a11d0ad bsc_init: Set the paging config like in the trace...
The value of this config is not known.... the paging load
needs to be tested again with these parameters...
2010-06-06 21:29:07 +08:00
Holger Hans Peter Freyther
67505f46b7 bsc_init: Use configuration settings from a trace... as default
Use the values but the paging configuration from a trace...
2010-06-06 21:25:33 +08:00
Holger Hans Peter Freyther
8b4898360a [nat] Implement the removal of an access-list. 2010-06-03 01:44:05 +08:00
Holger Hans Peter Freyther
6e495eee4b [nat] Fix the parsing of the access-list regexp...
We need to start at argv[1] for the regexp of
this access-list, also subtract one from number
of items..
2010-06-03 01:38:53 +08:00
Holger Hans Peter Freyther
e6a8a9359d [nat] Fix VTY bug with access-lists...
vty->index does not hold a BSC Config at this point as we are
on the nat level... use the global _nat pointer for now...
2010-06-03 01:34:20 +08:00
Holger Hans Peter Freyther
1d55fd9e2b Mark a new test release.. 2010-06-02 17:36:43 +08:00
Holger Hans Peter Freyther
df342ea82b [nat] Introduce the concept of access-list
One can set one access-list to one BSC and one
access-list to one NAT. The matching of IMSIs
remains the same for now, also applying the
white/blacklist. Access lists can not be deleted
for now and no perf opt is done (e.g. one could
cache the result of the last lookup in the bsc
struct).
2010-06-01 01:03:13 +08:00
Harald Welte
049eb23b73 [GPRS] Make sure SI13 rest octets look like those of the ip.access BSC 2010-05-31 19:20:11 +08:00
Holger Hans Peter Freyther
95eb9dd339 [gprs] Use the defaults coming from a trace file.
* Enable sending RLC3
* Use values from the trace..

This is not intended to be merged to master as this enables the
RLC3 that the comment claims to only work on EGPRS enabled models
and it is changing timers to hex indicating a change where none
happened... This is mostly for testing.
2010-05-31 19:19:10 +08:00
Holger Hans Peter Freyther
ca660ac9ca [nat] Add ip-tos option to the nat.
This is applied to all incoming BSC connections.
2010-05-31 10:36:35 +08:00
Holger Hans Peter Freyther
96d6ed2552 [mgcp] Set the IP_TOS/DSCP on RTP/RTCP IP packets. 2010-05-31 10:22:00 +08:00
Harald Welte
170619fef6 [gprs] NS/BSSGP: Make all timers configurable from VTY 2010-05-22 22:21:36 +08:00
Holger Hans Peter Freyther
09f28ea6b3 [misc] Remove spaces, fix indention. 2010-05-22 22:13:13 +08:00
Sylvain Munaut
1884f89d9b bsc_init: Fix ccch description in SI messages
The previous code just hardcoded RSL_BCCH_CCCH_CONF_1_C, but
we need to inspect the timeslot config to know what to use.

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
2010-05-22 22:12:48 +08:00
Holger Hans Peter Freyther
0777fb2d32 [mgcp] Only patch RTP packets when they arrived on the RTP port
Do not attempt to patch RTCP packets...
2010-05-22 22:06:13 +08:00
Holger Hans Peter Freyther
35e56453d2 msc: Add msc ip-tos NR option for the BSC
Allow to set the TOS field via the VTY interface. The
SO_PRIORITY was not used as it has no effect on the
packets being sent (in contrast to the documentation).
2010-05-18 03:31:16 +08:00
Holger Hans Peter Freyther
4fcf80a59a [nat] Make the refusal more complicated to support more MSCs
We will need to confirm the connection, then we can send the
GSM48 message, then we need to close the connection... the
embedding in the refusal method was way too easy..
2010-05-16 20:45:16 +08:00
Holger Hans Peter Freyther
31e0bafa10 [sccp] Add method to create a dt1 packet. 2010-05-16 20:45:15 +08:00
Holger Hans Peter Freyther
01ffc204f3 [sccp] Create a method to create RLSD messages. 2010-05-16 20:45:15 +08:00
Holger Hans Peter Freyther
466c40bec2 [sccp] Create a SCCP CC creation routine. 2010-05-16 20:45:15 +08:00
Holger Hans Peter Freyther
60a2f4a7e6 [nat] Make create_sccp_src_ref return the SCCP Connection.
Right now it was not possible to just find a connection, by returning
the connection that is created we will have direct access to it. It
will be used by the local connection handling.
2010-05-16 20:45:15 +08:00
Holger Hans Peter Freyther
797b9f0af0 [nat] Remove parameter that is never accessed directly
The msgb needs to be around when we access the parsed structure
but that needs to be guranteed by the caller handing out the parsed
structure.
2010-05-16 20:45:15 +08:00
Holger Hans Peter Freyther
677f0e7f90 [nat] Add the notion of a "local" connection.
A local connection is only between the MUX and the real BSC. We will
not forward anything to the MSC. This will be needed for the IMSI
filtering as sending a CREF is not liked by every BSC...
2010-05-16 20:45:15 +08:00
Holger Hans Peter Freyther
ddbb5a4e1e [nat] Do not access the con after the removal
In case of a RLC message we will destroy the SCCP connection. This means
that accessing the con and con->bsc will access old memory. Keep the status
local and move the con into an inner scope.
2010-05-16 20:45:15 +08:00
Holger Hans Peter Freyther
75042b80be [nat] Send a GSM48 message within the reject message 2010-05-16 08:15:11 +08:00
Holger Hans Peter Freyther
c32589f395 gsm48: Split LU Reject sending and generation into two. 2010-05-16 02:49:12 +08:00
Holger Hans Peter Freyther
abd0719f23 gsm48: Separate CM Service Reject sending and creation.
Split out the msg generation from the sending, this will
be used by the nat to send a refusal message.
2010-05-16 02:49:12 +08:00
Holger Hans Peter Freyther
5bac62216e [nat] Move the SCCP CREF handling into a new method.
We will need to generate messages with a proper reason
and it is easier to do that from a dedicated method.
2010-05-16 02:49:12 +08:00
Holger Hans Peter Freyther
c93c523872 [bsc_msc_ip] Move the command to the right place
Apparently I could not find the vty_interface_bsc.c when I was
searching for it. Move an extra BSC command into that file.
2010-05-16 02:49:12 +08:00
Holger Hans Peter Freyther
ed1c872352 [bsc_msc_ip] Print SCCP src/dst ref as hex 2010-05-16 02:49:12 +08:00
Holger Hans Peter Freyther
e21bdea501 [nat] Use and print the connection type of a SCCP connection. 2010-05-16 02:49:11 +08:00
Holger Hans Peter Freyther
11c17233fe [nat] Set the connection type/reason as out parameter
We are analyzing each CR message and it is nice to know the
reason these connections were created. Change the nat method.
2010-05-16 02:49:11 +08:00
Holger Hans Peter Freyther
fceee8779e Bump the version. 2010-05-16 01:37:49 +08:00
Holger Hans Peter Freyther
e27740a0e2 [nat] Use the new gsm48 method to parse the MI followed by a classmark. 2010-05-16 01:13:28 +08:00
Holger Hans Peter Freyther
95defd542d gsm48: Add a generic MI from classmark+mi extraction.
This is a generic MI extraction for the MI if it is followed
after a classmark. For the Phase1 Phones the classmark2 is not
four bytes but it might be different. This code can be used
by the CM Service Request handling as well.
2010-05-16 01:07:20 +08:00
Holger Hans Peter Freyther
2d2a43f3d6 [nat] Let IMSI DETACH and other messages pass by. 2010-05-16 01:05:47 +08:00
Holger Hans Peter Freyther
a9aab6a9ca [nat] Print on which BSC config this happend. 2010-05-16 00:45:07 +08:00
Holger Hans Peter Freyther
775b3dc566 [nat] Parse the PAGING RESPONSE inside a CR message as well.
Now we are parsing a CM Service Request, Location Updating Request
and the Paging Response. For all other messages we claim to not
support it and force a refuse.
2010-05-15 23:55:28 +08:00
Holger Hans Peter Freyther
45bb8bfc1a gsm48: Add size checks to the paging response mi parsing.
We go from no size checks to some content checking. We should
refactor the whole classmark2 + mi parsing that is used throughout
the code into one place with proper size checking. This is the
start and requires a new libosmocore as well.
2010-05-15 23:55:28 +08:00
Holger Hans Peter Freyther
57900f0008 [nat] Check proto descriptor and the message type 2010-05-15 23:55:28 +08:00
Holger Hans Peter Freyther
66ac860f62 [nat] Add code to filter the CM Service Request by IMSI.
The code should be shared among the GSM0408 implementation
and this one, and like the LU we are not handling a TMSI
properly as we have no idea where it is coming from.
2010-05-15 23:55:28 +08:00
Holger Hans Peter Freyther
ec82426c5e [nat] Mention where the MSG is coming from. 2010-05-15 19:13:52 +08:00
Holger Hans Peter Freyther
60fa0efcc8 [sccp] Make it optional to send data on a SCCP Connection Refuse
This can be used to send a Location Updating Reject down to the
BSC when it is clear that a subscriber is not allowed.
2010-05-15 01:04:42 +08:00
Holger Hans Peter Freyther
3dfcd4636a [nat] Remove the imsi allow option on the nat level.
For now we have:
1.) bsc imsi deny to deny at the BSC level
2.) bsc imsi allow to allow a SIM at the BSC level
3.) nat imsi deny to deny at the global level
2010-05-15 00:36:54 +08:00
Holger Hans Peter Freyther
50818d0c20 [nat] Separate exit2/exit3 as this can not be shared...
We have tried to send a refuse for arbitary things and ended
up with a segfault... separate the exi2 and exit3 label to have
separate exits and cleanups.
2010-05-15 00:29:50 +08:00
Holger Hans Peter Freyther
317934a2ba [nat] Add a token to the nat config and handle ID GET
This allows to chain a nat with a nat by answering to the
id get code and sending the token.
2010-05-15 00:14:58 +08:00
Holger Hans Peter Freyther
565b355c82 [bsc_msc] Move the id get response into the bsc_msc.c
Create the message in a common place and then it can be used
by tools having an a link or such.
2010-05-15 00:12:19 +08:00
Holger Hans Peter Freyther
be9201a272 [nat] Add a regexp test command to the VTY.
This allows to test the regexp to be used for allo/deny of
the imsi filter.
2010-05-14 23:43:12 +08:00
Holger Hans Peter Freyther
a43c56637d [nat] Fix the regexp of the test and the command line. 2010-05-14 23:07:58 +08:00
Holger Hans Peter Freyther
980c84f0a3 [nat] Fix the imsi deny config write. 2010-05-14 23:06:09 +08:00
Holger Hans Peter Freyther
1ae7b7c372 [nat] We do not want to see the actual matches. 2010-05-14 22:24:36 +08:00
Holger Hans Peter Freyther
e265db68b0 [nat] Allow to set the description for the bsc.
This will allow to add description to each BSC.
2010-05-14 22:06:28 +08:00
Holger Hans Peter Freyther
fdc4a9386f [nat] Implement IMSI filtering... 2010-05-14 19:49:35 +08:00
Holger Hans Peter Freyther
023ac93377 [nat] Fix the size check of the LU Request. 2010-05-14 19:24:06 +08:00
Holger Hans Peter Freyther
fa53aba62c [nat] Make the string -> regexp parsing public
This way it can be used from within a test case to test
the regexps..
2010-05-14 18:38:29 +08:00
Holger Hans Peter Freyther
34c0b245fb nat: Add code to parse the SCCP optional data.
First we have the Complete Layer3 Information, then we have
the IE for the Layer3 information, then the GSM48 hdr, then
the actual content with data. Right now we are parsing the
LU but we are not filtering anything yet.
2010-05-14 08:14:09 +08:00
Holger Hans Peter Freyther
4c4d2d48ec nat: Start to add a test case.. with one CR message. 2010-05-14 08:12:57 +08:00
Holger Hans Peter Freyther
13441a1c50 gsm48: Typo fix. 2010-05-14 08:02:08 +08:00
Holger Hans Peter Freyther
8ff74e8c24 nat: Introduce a nat filter that is working on the CR message.
Currently there is no implementation but the refusal code is
in place and will send a refusal back to the BSC.
2010-05-14 03:47:52 +08:00
Holger Hans Peter Freyther
a202342d64 [sccp] Export function to create SCCP Refuse message. 2010-05-14 03:34:35 +08:00
Holger Hans Peter Freyther
d275cf6407 [bsc_msc_ip] Use A.B.C.D for the VTY code. 2010-05-14 02:37:54 +08:00
Holger Hans Peter Freyther
c00e9ce09f [nat] Use A.B.C.D for the IP address
The VTY code will then be able to validate the IP Address.
2010-05-14 02:36:42 +08:00
Holger Hans Peter Freyther
5d645bf984 [nat] Remove range checks inside the VTY command.
The ranges are enforced by the VTY code.
2010-05-14 02:35:51 +08:00
Holger Hans Peter Freyther
723fb87a6c [mgcp] Clean up VTY code, the ranges are checked by the VTY code. 2010-05-14 02:34:35 +08:00
Holger Hans Peter Freyther
9da4492655 [mgcp] Use A.B.C.D for the ip addresses inside the vty config
Make the vty code parse the ip addresses for us and validate
them for us.
2010-05-14 02:27:50 +08:00
Holger Hans Peter Freyther
1927e93ce5 [mgcp] Improve the language of the comments. 2010-05-14 02:18:59 +08:00
Holger Hans Peter Freyther
7bbd416a52 [mgcp] Include stdlib.h for abs. 2010-05-14 02:14:09 +08:00
Holger Hans Peter Freyther
efd38dd015 [vty] Add power measurements to the one line summary. 2010-05-14 01:58:17 +08:00
Holger Hans Peter Freyther
e8d8811b12 [vty] Add a one line show lchan summary command. 2010-05-14 01:45:52 +08:00
Holger Hans Peter Freyther
39cb9f2a3c [vty] Move "show lchan" into a parameterized method
I want to have a shorter lchan summary but with the same
config parameters. Change the current code to be a method
that takes a dump routine as parameter.
2010-05-14 01:45:45 +08:00
Holger Hans Peter Freyther
0558a5a0dd [vty] Remove unfinished code from the VTY... 2010-05-14 00:58:11 +08:00
Holger Hans Peter Freyther
fcb4468de4 A new day, a new tag 2010-05-14 00:49:14 +08:00
Holger Hans Peter Freyther
9e96b2df12 rach: Allow to set the emergency call bit
Add the rach emergency call allowed (0|1) setting and implement
it by directly manipulating the t2 value. It is the third bit which
is set to 0 when emergency calls are enabled and to one if it is
only enabled for access classes 11 to 15.
2010-05-14 00:39:19 +08:00
Holger Hans Peter Freyther
72952d854c [mgcp] Use tabs here.. 2010-05-14 00:20:32 +08:00
Holger Hans Peter Freyther
637dce99ba ipaccess: Move the RSL delay down to 0 milliseconds.
Set the delay to zero milliseconds to send RSL messages as fast
as possible.
2010-05-14 00:09:05 +08:00
Holger Hans Peter Freyther
641b07ab73 ipaccess: Make sure flashing of the secondary BTS is working
Use the TRX throughout the flash process.
2010-05-13 00:17:17 +08:00
Holger Hans Peter Freyther
6eae31e39f sw_load: Specify the trx_nr for the software load
For the multi TRX setup we will need to specify the right trx->nr
to be able to flash the BTS. For the BS11 case we are ignoring the
additional argument.
2010-05-13 00:17:17 +08:00
Holger Hans Peter Freyther
4647015f69 ipaccess: Send the reset to the BASEBAND_TRANSC and supply TRX
Send the IPA Restart to a given BTS/TRX, change the signal callbacks
to carry the trx instead of the BTS so we have an easy access to the
right TRX and change the ipaccess-config to use that TRX. This is
fixing the restart with a multi TRX setup.

Even if we have the msg->trx, use the gsm_bts_trx_by_nr and get
the TRX from the fom header. This is because the OpenBSC and the
BTS numbering might not match for the multi TRX case.
2010-05-13 00:16:15 +08:00
Holger Hans Peter Freyther
239f95467c ipaccess: Refactor... unite some code 2010-05-12 23:39:51 +08:00
Holger Hans Peter Freyther
cd80c73f37 ipaccess: Use the right trx when performing the test 2010-05-12 23:02:23 +08:00
Holger Hans Peter Freyther
d6f1c4afbb ipaccess: Use the current TRX to set the OML address. 2010-05-12 22:48:28 +08:00
Holger Hans Peter Freyther
0c8af75c94 Increase the version number. 2010-05-12 22:25:40 +08:00
Holger Hans Peter Freyther
e4b33be6fc chan: After sending the GSM04.08 RR Release, reset the subscriber and wait
After we send the SACH DEACTIVATE the BTS will get back to us with a
Release Indication which will trigger the RF Channel Release handling. This
is why we can return here, but we need to put the subscriber reference to
make sure to not end in a infinite loop.

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

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

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

View File

@@ -1,7 +1,6 @@
dnl Process this file with autoconf to produce a configure script
AC_INIT
AM_INIT_AUTOMAKE(openbsc, 0.3.99.5onwaves)
AC_INIT(openbsc, 0.3.99.15onwaves)
AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
dnl kernel style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
@@ -16,7 +15,7 @@ dnl checks for libraries
AC_SEARCH_LIBS(crypt, crypt,
[LIBCRYPT="-lcrypt"; AC_DEFINE([VTY_CRYPT_PW], [], [Use crypt functionality of vty.])])
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.1.3)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.1.7)
dnl checks for header files
AC_HEADER_STDC

View File

@@ -92,7 +92,7 @@ int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1,
int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *msg);
int abis_nm_event_reports(struct gsm_bts *bts, int on);
int abis_nm_reset_resource(struct gsm_bts *bts);
int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
u_int8_t win_size, int forced,
gsm_cbfn *cbfn, void *cb_data);
int abis_nm_software_load_status(struct gsm_bts *bts);
@@ -148,7 +148,7 @@ int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
u_int8_t *attr, int attr_len);
int abis_nm_ipaccess_set_nvattr(struct gsm_bts_trx *trx, u_int8_t *attr,
int attr_len);
int abis_nm_ipaccess_restart(struct gsm_bts *bts);
int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx);
int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
u_int8_t *attr, u_int8_t attr_len);
@@ -164,7 +164,8 @@ enum nm_evt {
EVT_STATECHG_ADM,
};
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state);
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
struct abis_om_obj_inst *obj_inst);
const char *nm_opstate_name(u_int8_t os);
const char *nm_avail_name(u_int8_t avail);

View File

@@ -32,16 +32,20 @@ struct bsc_msc_connection {
int is_authenticated;
const char *ip;
int port;
int prio;
void (*connection_loss) (struct bsc_msc_connection *);
void (*connected) (struct bsc_msc_connection *);
struct timer_list reconnect_timer;
struct timer_list timeout_timer;
};
struct bsc_msc_connection *bsc_msc_create(const char *ip, int port);
struct bsc_msc_connection *bsc_msc_create(const char *ip, int port, int prio);
int bsc_msc_connect(struct bsc_msc_connection *);
void bsc_msc_schedule_connect(struct bsc_msc_connection *);
void bsc_msc_lost(struct bsc_msc_connection *);
struct msgb *bsc_msc_id_get_resp(const char *token);
#endif

View File

@@ -42,6 +42,15 @@
struct bsc_nat;
enum {
NAT_CON_TYPE_NONE,
NAT_CON_TYPE_LU,
NAT_CON_TYPE_CM_SERV_REQ,
NAT_CON_TYPE_PAG_RESP,
NAT_CON_TYPE_LOCAL_REJECT,
NAT_CON_TYPE_OTHER,
};
/*
* For the NAT we will need to analyze and later patch
* the received message. This would require us to parse
@@ -116,10 +125,17 @@ struct sccp_connections {
struct sccp_source_reference remote_ref;
int has_remote_ref;
/* status */
int con_type;
int con_local;
/* GSM audio handling. That is 32 * multiplex + ts */
int crcx;
int msc_timeslot;
int bsc_timeslot;
/* timeout handling */
struct timespec creation_time;
};
/**
@@ -146,11 +162,10 @@ struct bsc_config {
unsigned int lac;
int nr;
char *description;
/* imsi white and blacklist */
char *imsi_allow;
regex_t imsi_allow_re;
char *imsi_deny;
regex_t imsi_deny_re;
char *acc_lst_name;
int forbid_paging;
@@ -189,6 +204,24 @@ struct bsc_nat_statistics {
} msc;
};
struct bsc_nat_acc_lst {
struct llist_head list;
/* the name of the list */
const char *name;
struct llist_head fltr_list;
};
struct bsc_nat_acc_lst_entry {
struct llist_head list;
/* the filter */
char *imsi_allow;
regex_t imsi_allow_re;
char *imsi_deny;
regex_t imsi_deny_re;
};
/**
* the structure of the "nat" network
*/
@@ -199,9 +232,13 @@ struct bsc_nat {
/* active BSC connections that need patching */
struct llist_head bsc_connections;
/* access lists */
struct llist_head access_lists;
/* known BSC's */
struct llist_head bsc_configs;
int num_bsc;
int bsc_ip_tos;
/* MGCP config */
struct mgcp_config *mgcp_cfg;
@@ -213,6 +250,8 @@ struct bsc_nat {
char *msc_ip;
int msc_port;
int first_contact;
struct bsc_msc_connection *msc_con;
char *token;
/* timeouts */
int auth_timeout;
@@ -222,10 +261,7 @@ struct bsc_nat {
struct bsc_endpoint *bsc_endpoints;
/* filter */
char *imsi_allow;
regex_t imsi_allow_re;
char *imsi_deny;
regex_t imsi_deny_re;
char *acc_lst_name;
/* statistics */
struct bsc_nat_statistics stats;
@@ -241,6 +277,8 @@ void bsc_nat_set_msc_ip(struct bsc_nat *bsc, const char *ip);
void sccp_connection_destroy(struct sccp_connections *);
void bsc_close_connection(struct bsc_connection *);
const char *bsc_con_type_to_string(int type);
/**
* parse the given message into the above structure
*/
@@ -253,10 +291,16 @@ int bsc_nat_filter_ipa(int direction, struct msgb *msg, struct bsc_nat_parsed *p
int bsc_nat_vty_init(struct bsc_nat *nat);
struct bsc_connection *bsc_nat_find_bsc(struct bsc_nat *nat, struct msgb *msg, int *_lac);
/**
* Content filtering.
*/
int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg,
struct bsc_nat_parsed *, int *con_type);
/**
* SCCP patching and handling
*/
int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed);
struct sccp_connections *create_sccp_src_ref(struct bsc_connection *bsc, struct bsc_nat_parsed *parsed);
int update_sccp_src_ref(struct sccp_connections *sccp, struct bsc_nat_parsed *parsed);
void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed);
struct sccp_connections *patch_sccp_src_ref_to_bsc(struct msgb *, struct bsc_nat_parsed *, struct bsc_nat *);
@@ -283,4 +327,12 @@ int bsc_mgcp_extract_ci(const char *resp);
int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int id);
/* IMSI allow/deny handling */
void bsc_parse_reg(void *ctx, regex_t *reg, char **imsi, int argc, const char **argv);
struct bsc_nat_acc_lst *bsc_nat_acc_lst_find(struct bsc_nat *nat, const char *name);
struct bsc_nat_acc_lst *bsc_nat_acc_lst_get(struct bsc_nat *nat, const char *name);
void bsc_nat_acc_lst_delete(struct bsc_nat_acc_lst *lst);
struct bsc_nat_acc_lst_entry *bsc_nat_acc_lst_entry_create(struct bsc_nat_acc_lst *);
#endif

View File

@@ -45,12 +45,15 @@ int decode_bcd_number(char *output, int output_len, const u_int8_t *bcd_lv,
int h_len);
int send_siemens_mrpci(struct gsm_lchan *lchan, u_int8_t *classmark2_lv);
int gsm48_paging_extract_mi(struct msgb *msg, char *mi_string, u_int8_t *mi_type);
int gsm48_extract_mi(uint8_t *classmark2, int length, char *mi_string, uint8_t *mi_type);
int gsm48_paging_extract_mi(struct gsm48_pag_resp *pag, int length, char *mi_string, u_int8_t *mi_type);
int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr);
int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode);
int gsm48_rx_rr_modif_ack(struct msgb *msg);
int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg);
struct msgb *gsm48_create_mm_serv_rej(enum gsm48_reject_value value);
struct msgb *gsm48_create_loc_upd_rej(uint8_t cause);
#endif

View File

@@ -3,6 +3,8 @@
#include <sys/types.h>
struct bsc_msc_connection;
enum gsm_phys_chan_config {
GSM_PCHAN_NONE,
GSM_PCHAN_CCCH,
@@ -286,6 +288,9 @@ struct gsm_lchan {
/* release reason */
u_int8_t release_reason;
/* timestamp */
struct timeval alloc_time;
};
struct gsm_e1_subslot {
@@ -513,10 +518,12 @@ struct gsm_bts {
struct {
struct gsm_nm_state nm_state;
u_int16_t nsei;
uint8_t timer[7];
} nse;
struct {
struct gsm_nm_state nm_state;
u_int16_t bvci;
uint8_t timer[11];
} cell;
struct gsm_bts_gprs_nsvc nsvc[2];
u_int8_t rac;
@@ -673,6 +680,8 @@ struct gsm_network {
char *bsc_token;
char *msc_ip;
int msc_port;
int msc_prio;
struct bsc_msc_connection *msc_con;
int ping_timeout;
int pong_timeout;
};

View File

@@ -93,6 +93,7 @@ struct mgcp_config {
int audio_loop;
int early_bind;
int rtp_base_port;
int endp_tos;
/* only used in forward mode */
char *forward_ip;

View File

@@ -133,7 +133,7 @@ struct scall_signal_data {
};
struct ipacc_ack_signal_data {
struct gsm_bts *bts;
struct gsm_bts_trx *trx;
u_int8_t msg_type;
};

View File

@@ -148,6 +148,11 @@ extern const struct sockaddr_sccp sccp_ssn_bssap;
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 msgb *sccp_create_refuse(struct sccp_source_reference *src_ref, int cause, uint8_t *data, int length);
struct msgb *sccp_create_cc(struct sccp_source_reference *src_ref, struct sccp_source_reference *dst_ref);
struct msgb *sccp_create_rlsd(struct sccp_source_reference *src_ref, struct sccp_source_reference *dst_ref, int cause);
struct msgb *sccp_create_dt1(struct sccp_source_reference *dst_ref, uint8_t *data, uint8_t len);
/**
* Below this are helper functions and structs for parsing SCCP messages
*/

View File

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

View File

@@ -678,7 +678,7 @@ static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
new_state = *nm_state;
new_state.administrative = adm_state;
rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state);
rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state, obj_inst);
nm_state->administrative = adm_state;
@@ -732,7 +732,7 @@ static int abis_nm_rx_statechg_rep(struct msgb *mb)
/* Update the operational state of a given object in our in-memory data
* structures and send an event to the higher layer */
void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state);
rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state, &foh->obj_inst);
nm_state->operational = new_state.operational;
nm_state->availability = new_state.availability;
if (nm_state->administrative == 0)
@@ -1139,6 +1139,7 @@ enum sw_state {
struct abis_nm_sw {
struct gsm_bts *bts;
int trx_nr;
gsm_cbfn *cbfn;
void *cb_data;
int forced;
@@ -1592,7 +1593,7 @@ static int abis_nm_rcvmsg_sw(struct msgb *mb)
}
/* Load the specified software into the BTS */
int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
int abis_nm_software_load(struct gsm_bts *bts, int trx_nr, const char *fname,
u_int8_t win_size, int forced,
gsm_cbfn *cbfn, void *cb_data)
{
@@ -1606,6 +1607,7 @@ int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
return -EBUSY;
sw->bts = bts;
sw->trx_nr = trx_nr;
switch (bts->type) {
case GSM_BTS_TYPE_BS11:
@@ -1616,8 +1618,8 @@ int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
break;
case GSM_BTS_TYPE_NANOBTS:
sw->obj_class = NM_OC_BASEB_TRANSC;
sw->obj_instance[0] = 0x00;
sw->obj_instance[1] = 0x00;
sw->obj_instance[0] = sw->bts->nr;
sw->obj_instance[1] = sw->trx_nr;
sw->obj_instance[2] = 0xff;
break;
case GSM_BTS_TYPE_UNKNOWN:
@@ -2551,7 +2553,7 @@ static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
fle = fl_dequeue(&bs11_sw->file_list);
if (fle) {
/* start download the next file of our file list */
rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
rc = abis_nm_software_load(bs11_sw->bts, 0xff, fle->fname,
bs11_sw->win_size,
bs11_sw->forced,
&bs11_swload_cbfn, bs11_sw);
@@ -2607,7 +2609,7 @@ int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
return -EINVAL;
/* start download the next file of our file list */
rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
rc = abis_nm_software_load(bts, 0xff, fle->fname, win_size, forced,
bs11_swload_cbfn, bs11_sw);
talloc_free(fle);
return rc;
@@ -2775,12 +2777,12 @@ static int abis_nm_rx_ipacc(struct msgb *msg)
case NM_MT_IPACC_RSL_CONNECT_NACK:
case NM_MT_IPACC_SET_NVATTR_NACK:
case NM_MT_IPACC_GET_NVATTR_NACK:
signal.bts = msg->trx->bts;
signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
signal.msg_type = foh->msg_type;
dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
break;
case NM_MT_IPACC_SET_NVATTR_ACK:
signal.bts = msg->trx->bts;
signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
signal.msg_type = foh->msg_type;
dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
break;
@@ -2866,9 +2868,16 @@ int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
}
/* restart / reboot an ip.access nanoBTS */
int abis_nm_ipaccess_restart(struct gsm_bts *bts)
int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
{
return __simple_cmd(bts, NM_MT_IPACC_RESTART);
struct abis_om_hdr *oh;
struct msgb *msg = nm_msgb_alloc();
oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
fill_om_fom_hdr(oh, 0, NM_MT_IPACC_RESTART, NM_OC_BASEB_TRANSC,
trx->bts->nr, trx->nr, 0xff);
return abis_nm_sendmsg(trx->bts, msg);
}
int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,

View File

@@ -911,7 +911,7 @@ static int rsl_rx_meas_res(struct msgb *msg)
/* check if this channel is actually active */
/* FIXME: maybe this check should be way more generic/centralized */
if (msg->lchan->state != LCHAN_S_ACTIVE) {
LOGP(DRSL, LOGL_NOTICE, "%s: MEAS RES for inactive channel\n",
LOGP(DRSL, LOGL_DEBUG, "%s: MEAS RES for inactive channel\n",
gsm_lchan_name(msg->lchan));
return 0;
}

View File

@@ -481,7 +481,7 @@ static int handle_state_resp(enum abis_bs11_phase state)
* argument, so our swload_cbfn can distinguish
* a safety load from a regular software */
if (file_is_readable(fname_safety))
rc = abis_nm_software_load(g_bts, fname_safety,
rc = abis_nm_software_load(g_bts, 0xff, fname_safety,
win_size, param_forced,
swload_cbfn, g_bts);
else
@@ -697,7 +697,8 @@ int handle_serial_msg(struct msgb *rx_msg)
}
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
struct abis_om_obj_inst *obj_ins)
{
return 0;
}

View File

@@ -317,14 +317,14 @@ static unsigned char bs11_attr_radio[] =
static unsigned char nanobts_attr_bts[] = {
NM_ATT_INTERF_BOUND, 0x55, 0x5b, 0x61, 0x67, 0x6d, 0x73,
/* interference avg. period in numbers of SACCH multifr */
NM_ATT_INTAVE_PARAM, 0x06,
NM_ATT_INTAVE_PARAM, 0x1f,
/* conn fail based on SACCH error rate */
NM_ATT_CONN_FAIL_CRIT, 0x00, 0x02, 0x01, 0x10,
NM_ATT_T200, 0x1e, 0x24, 0x24, 0xa8, 0x34, 0x21, 0xa8,
NM_ATT_MAX_TA, 0x3f,
NM_ATT_OVERL_PERIOD, 0x00, 0x01, 10, /* seconds */
NM_ATT_CCCH_L_T, 10, /* percent */
NM_ATT_CCCH_L_I_P, 1, /* seconds */
NM_ATT_CONN_FAIL_CRIT, 0x00, 0x02, 0x01, 0x20,
NM_ATT_T200, 0x1e, 0x1e, 0x24, 0xa8, 0x34, 0x21, 0xa8,
NM_ATT_MAX_TA, 0x00,
NM_ATT_OVERL_PERIOD, 0x00, 0x01, 5, /* seconds */
NM_ATT_CCCH_L_T, 32, /* percent */
NM_ATT_CCCH_L_I_P, 5, /* seconds */
NM_ATT_RACH_B_THRESH, 10, /* busy threshold in - dBm */
NM_ATT_LDAVG_SLOTS, 0x03, 0xe8, /* rach load averaging 1000 slots */
NM_ATT_BTS_AIR_TIMER, 128, /* miliseconds */
@@ -345,7 +345,7 @@ static unsigned char nanobts_attr_nse[] = {
3, /* (un)blocking retries */
3, /* reset timer (Tns-reset) */
3, /* reset retries */
30, /* test timer (Tns-test) */
3, /* test timer (Tns-test) */
3, /* alive timer (Tns-alive) */
10, /* alive retrires */
NM_ATT_IPACC_BSSGP_CFG, 0, 11,
@@ -366,29 +366,27 @@ static unsigned char nanobts_attr_cell[] = {
NM_ATT_IPACC_RAC, 0, 1, 1, /* routing area code */
NM_ATT_IPACC_GPRS_PAGING_CFG, 0, 2,
5, /* repeat time (50ms) */
3, /* repeat count */
1, /* repeat count */
NM_ATT_IPACC_BVCI, 0, 2, 0x03, 0x9d, /* BVCI 925 */
NM_ATT_IPACC_RLC_CFG, 0, 9,
20, /* T3142 */
5, /* T3169 */
5, /* T3191 */
200, /* T3193 */
5, /* T3195 */
10, /* N3101 */
4, /* N3103 */
8, /* N3105 */
15, /* RLC CV countdown */
NM_ATT_IPACC_CODING_SCHEMES, 0, 2, 0x0f, 0x00, /* CS1..CS4 */
0x14, /* T3142 */
0x05, /* T3169 */
0x05, /* T3191 */
0x14, /* T3193 */
0x05, /* T3195 */
0x0a, /* N3101 */
0x04, /* N3103 */
0x08, /* N3105 */
0x0f, /* RLC CV countdown */
NM_ATT_IPACC_CODING_SCHEMES, 0, 2, 0x8f, 0xff, /* CS1..CS4 */
NM_ATT_IPACC_RLC_CFG_2, 0, 5,
0x00, 250, /* T downlink TBF extension (0..500) */
0x00, 250, /* T uplink TBF extension (0..500) */
0x00, 0x96, /* T downlink TBF extension (0..500) */
0x00, 0x32, /* T uplink TBF extension (0..500) */
2, /* CS2 */
#if 0
/* EDGE model only, breaks older models.
* Should inquire the BTS capabilities */
NM_ATT_IPACC_RLC_CFG_3, 0, 1,
2, /* MCS2 */
#endif
};
static unsigned char nanobts_attr_nsvc0[] = {
@@ -401,7 +399,8 @@ static unsigned char nanobts_attr_nsvc0[] = {
/* Callback function to be called whenever we get a GSM 12.21 state change event */
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
struct abis_om_obj_inst *obj_inst)
{
struct gsm_bts *bts;
struct gsm_bts_trx *trx;
@@ -493,7 +492,7 @@ int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
bts = nsvc->bts;
if (bts->gprs.mode == BTS_GPRS_NONE)
break;
/* We skip NSVC1 since we only use NSVC0 */
/* We skip NSVC1 since we only use NSVC0 */
if (nsvc->id == 1)
break;
if (new_state->availability == NM_AVSTATE_OFF_LINE) {
@@ -883,6 +882,10 @@ static void patch_nm_tables(struct gsm_bts *bts)
/* patch NSEI */
nanobts_attr_nse[3] = bts->gprs.nse.nsei >> 8;
nanobts_attr_nse[4] = bts->gprs.nse.nsei & 0xff;
memcpy(nanobts_attr_nse+8, bts->gprs.nse.timer,
ARRAY_SIZE(bts->gprs.nse.timer));
memcpy(nanobts_attr_nse+18, bts->gprs.cell.timer,
ARRAY_SIZE(bts->gprs.cell.timer));
/* patch NSVCI */
nanobts_attr_nsvc0[3] = bts->gprs.nsvc[0].nsvci >> 8;
@@ -974,6 +977,8 @@ void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
static int bootstrap_bts(struct gsm_bts *bts)
{
int i, n;
switch (bts->band) {
case GSM_BAND_1800:
if (bts->c0->arfcn < 512 || bts->c0->arfcn > 885) {
@@ -1010,10 +1015,34 @@ static int bootstrap_bts(struct gsm_bts *bts)
/* Control Channel Description */
bts->si_common.chan_desc.att = 1;
bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C;
bts->si_common.chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5;
/* T3212 is set from vty/config */
/* Set ccch config by looking at ts config */
for (n=0, i=0; i<8; i++)
n += bts->c0->ts[i].pchan == GSM_PCHAN_CCCH ? 1 : 0;
switch (n) {
case 0:
bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C;
break;
case 1:
bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_NC;
break;
case 2:
bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_2_NC;
break;
case 3:
bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_3_NC;
break;
case 4:
bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_4_NC;
break;
default:
LOGP(DNM, LOGL_ERROR, "Unsupported CCCH timeslot configuration\n");
return -EINVAL;
}
/* some defaults for our system information */
bts->si_common.cell_options.radio_link_timeout = 2; /* 12 */
bts->si_common.cell_options.dtx = 2; /* MS shall not use upplink DTX */

View File

@@ -22,6 +22,7 @@
#include <openbsc/bsc_msc.h>
#include <openbsc/debug.h>
#include <openbsc/ipaccess.h>
#include <osmocore/write_queue.h>
#include <osmocore/talloc.h>
@@ -49,6 +50,14 @@ static void connection_loss(struct bsc_msc_connection *con)
con->connection_loss(con);
}
static void msc_con_timeout(void *_con)
{
struct bsc_msc_connection *con = _con;
LOGP(DMSC, LOGL_ERROR, "MSC Connection timeout.\n");
bsc_msc_lost(con);
}
static int bsc_msc_except(struct bsc_fd *bfd)
{
struct write_queue *wrt;
@@ -98,6 +107,7 @@ static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
con->is_connected = 1;
bsc_del_timer(&con->timeout_timer);
LOGP(DMSC, LOGL_NOTICE, "(Re)Connected to the MSC.\n");
if (con->connected)
con->connected(con);
@@ -153,6 +163,13 @@ int bsc_msc_connect(struct bsc_msc_connection *con)
/* make it non blocking */
setnonblocking(fd);
/* set the socket priority */
ret = setsockopt(fd->fd, IPPROTO_IP, IP_TOS,
&con->prio, sizeof(con->prio));
if (ret != 0)
LOGP(DMSC, LOGL_ERROR, "Failed to set prio to %d. %s\n",
con->prio, strerror(errno));
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(con->port);
@@ -165,6 +182,9 @@ int bsc_msc_connect(struct bsc_msc_connection *con)
LOGP(DMSC, LOGL_ERROR, "MSC Connection in progress\n");
fd->when = BSC_FD_WRITE;
fd->cb = msc_connection_connect;
con->timeout_timer.cb = msc_con_timeout;
con->timeout_timer.data = con;
bsc_schedule_timer(&con->timeout_timer, 20, 0);
} else if (ret < 0) {
perror("Connection failed");
connection_loss(con);
@@ -188,7 +208,7 @@ int bsc_msc_connect(struct bsc_msc_connection *con)
}
struct bsc_msc_connection *bsc_msc_create(const char *ip, int port)
struct bsc_msc_connection *bsc_msc_create(const char *ip, int port, int prio)
{
struct bsc_msc_connection *con;
@@ -200,6 +220,7 @@ struct bsc_msc_connection *bsc_msc_create(const char *ip, int port)
con->ip = ip;
con->port = port;
con->prio = prio;
write_queue_init(&con->write_queue, 100);
con->write_queue.except_cb = bsc_msc_except;
return con;
@@ -227,3 +248,24 @@ void bsc_msc_schedule_connect(struct bsc_msc_connection *con)
con->reconnect_timer.data = con;
bsc_schedule_timer(&con->reconnect_timer, 5, 0);
}
struct msgb *bsc_msc_id_get_resp(const char *token)
{
struct msgb *msg;
if (!token) {
LOGP(DMSC, LOGL_ERROR, "No token specified.\n");
return NULL;
}
msg = msgb_alloc_headroom(4096, 128, "id resp");
if (!msg) {
LOGP(DMSC, LOGL_ERROR, "Failed to create the message.\n");
return NULL;
}
msg->l2h = msgb_v_put(msg, IPAC_MSGT_ID_RESP);
msgb_l16tv_put(msg, strlen(token) + 1,
IPAC_IDTAG_UNITNAME, (u_int8_t *) token);
return msg;
}

View File

@@ -30,6 +30,7 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#define _GNU_SOURCE
@@ -49,6 +50,7 @@
#include <osmocore/select.h>
#include <osmocore/talloc.h>
#include <osmocore/write_queue.h>
#include <osmocore/gsm0808.h>
#include <sccp/sccp.h>
@@ -64,22 +66,34 @@ static struct in_addr local_addr;
static LLIST_HEAD(active_connections);
static struct write_queue mgcp_agent;
static const char *rf_ctl = NULL;
static int testmode = 0;
extern int ipacc_rtp_direct;
/* msc handling */
static struct bsc_msc_connection *msc_con;
static struct timer_list msc_ping_timeout;
static struct timer_list msc_pong_timeout;
extern int bsc_bootstrap_network(int (*layer4)(struct gsm_network *, int, void *), const char *cfg_file);
extern int bsc_shutdown_net(struct gsm_network *net);
struct llist_head *bsc_sccp_connections()
{
return &active_connections;
}
/*
* Having a subscriber in the lchan is used to indicate that a SACH DEACTIVATE
* should be send. We will just introduce a fake subscriber and bind it to the
* lchan.
*/
static void assign_dummy_subscr(struct gsm_lchan *lchan)
{
if (!lchan->conn.subscr) {
lchan->conn.subscr = subscr_get_or_create(bsc_gsmnet, "2323");
lchan->conn.subscr->lac = 2323;
}
}
struct bss_sccp_connection_data *bss_sccp_create_data()
{
struct bss_sccp_connection_data *data;
@@ -117,7 +131,8 @@ static void sccp_it_fired(void *_data)
bsc_schedule_timer(&data->sccp_it, SCCP_IT_TIMER, 0);
}
static void bss_force_close(struct bss_sccp_connection_data *bss)
/* make sure to stop the T10 timer... bss_sccp_free_data is doing that */
static void bss_close_lchans(struct bss_sccp_connection_data *bss)
{
if (bss->lchan) {
bss->lchan->msc_data = NULL;
@@ -130,6 +145,11 @@ static void bss_force_close(struct bss_sccp_connection_data *bss)
put_subscr_con(&bss->secondary_lchan->conn, 0);
bss->secondary_lchan = NULL;
}
}
static void bss_force_close(struct bss_sccp_connection_data *bss)
{
bss_close_lchans(bss);
/* force the close by poking stuff */
if (bss->sccp) {
@@ -221,23 +241,21 @@ void msc_outgoing_sccp_data(struct sccp_connection *conn, struct msgb *msg, unsi
void msc_outgoing_sccp_state(struct sccp_connection *conn, int old_state)
{
struct bss_sccp_connection_data *con_data;
if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) {
con_data = (struct bss_sccp_connection_data *) conn->data_ctx;
LOGP(DMSC, LOGL_DEBUG, "Freeing sccp conn: %p state: %d\n", conn, conn->connection_state);
if (sccp_get_lchan(conn->data_ctx) != NULL) {
struct gsm_lchan *lchan = sccp_get_lchan(conn->data_ctx);
if (con_data->lchan || con_data->secondary_lchan) {
LOGP(DMSC, LOGL_ERROR, "ERROR: The lchan is still associated\n.");
lchan->msc_data = NULL;
put_subscr_con(&lchan->conn, 0);
bss_close_lchans(con_data);
}
bss_sccp_free_data((struct bss_sccp_connection_data *)conn->data_ctx);
bss_sccp_free_data(con_data);
sccp_connection_free(conn);
return;
} else if (conn->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED) {
struct bss_sccp_connection_data *con_data;
LOGP(DMSC, LOGL_DEBUG, "Connection established: %p\n", conn);
con_data = (struct bss_sccp_connection_data *) conn->data_ctx;
@@ -269,10 +287,8 @@ static int open_sccp_connection(struct msgb *layer3)
struct msgb *data;
/* When not connected to a MSC. We will simply close things down. */
if (!msc_con->is_authenticated) {
if (!bsc_gsmnet->msc_con->is_authenticated) {
LOGP(DMSC, LOGL_ERROR, "Not connected to a MSC. Not forwarding data.\n");
use_subscr_con(&layer3->lchan->conn);
put_subscr_con(&layer3->lchan->conn, 0);
return -1;
}
@@ -313,6 +329,8 @@ static int open_sccp_connection(struct msgb *layer3)
bsc_schedule_timer(&con_data->sccp_cc_timeout, 10, 0);
/* FIXME: Use transaction for this */
/* assign a dummy subscriber */
assign_dummy_subscr(layer3->lchan);
use_subscr_con(&layer3->lchan->conn);
sccp_connection_connect(sccp_connection, &sccp_ssn_bssap, data);
msgb_free(data);
@@ -344,7 +362,14 @@ static int handle_paging_response(struct msgb *msg)
char mi_string[GSM48_MI_SIZE];
u_int8_t mi_type;
gsm48_paging_extract_mi(msg, mi_string, &mi_type);
struct gsm48_hdr *hdr;
struct gsm48_pag_resp *resp;
hdr = msgb_l3(msg);
resp = (struct gsm48_pag_resp *) &hdr->data[0];
gsm48_paging_extract_mi(resp, msgb_l3len(msg) - sizeof(*hdr),
mi_string, &mi_type);
LOGP(DMSC, LOGL_DEBUG, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
mi_type, mi_string);
@@ -414,17 +439,22 @@ static int handle_ass_compl(struct msgb *msg)
return -1;
}
/* assign a dummy subscriber */
assign_dummy_subscr(msg->lchan);
/* 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;
if (old_chan) {
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 */
if (old_chan->conn.subscr)
subscr_put(old_chan->conn.subscr);
old_chan->conn.subscr = NULL;
put_subscr_con(&old_chan->conn, 1);
/* give up the old channel to not do a SACCH deactivate */
if (old_chan->conn.subscr)
subscr_put(old_chan->conn.subscr);
old_chan->conn.subscr = NULL;
put_subscr_con(&old_chan->conn, 1);
}
/* activate audio on it... */
if (is_ipaccess_bts(msg->lchan->ts->trx->bts) && msg->lchan->tch_mode != GSM48_CMODE_SIGN)
@@ -579,6 +609,12 @@ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
}
bsc_queue_connection_write(lchan_get_sccp(msg->lchan), dtap);
} else if (rc <= 0 && !msg->lchan->msc_data && msg->lchan->conn.use_count == 0) {
if (msg->lchan->state == LCHAN_S_ACTIVE) {
LOGP(DMSC, LOGL_NOTICE, "Closing unowned channel.\n");
use_subscr_con(&msg->lchan->conn);
put_subscr_con(&msg->lchan->conn, 0);
}
}
return rc;
@@ -635,7 +671,7 @@ static void print_usage()
static int msc_queue_write(struct msgb *msg, int proto)
{
ipaccess_prepend_header(msg, proto);
if (write_queue_enqueue(&msc_con->write_queue, msg) != 0) {
if (write_queue_enqueue(&bsc_gsmnet->msc_con->write_queue, msg) != 0) {
LOGP(DMSC, LOGL_FATAL, "Failed to queue IPA/%d\n", proto);
msgb_free(msg);
return -1;
@@ -651,7 +687,7 @@ static int msc_sccp_do_write(struct bsc_fd *fd, struct msgb *msg)
LOGP(DMSC, LOGL_DEBUG, "Sending SCCP to MSC: %u\n", msgb_l2len(msg));
LOGP(DMI, LOGL_DEBUG, "MSC TX %s\n", hexdump(msg->l2h, msgb_l2len(msg)));
ret = write(msc_con->write_queue.bfd.fd, msg->data, msg->len);
ret = write(bsc_gsmnet->msc_con->write_queue.bfd.fd, msg->data, msg->len);
if (ret < msg->len)
perror("MSC: Failed to send SCCP");
@@ -823,9 +859,9 @@ static void initialize_if_needed(void)
struct msgb *msg;
if (!msc_con->is_authenticated) {
if (!bsc_gsmnet->msc_con->is_authenticated) {
/* send a gsm 08.08 reset message from here */
msg = bssmap_create_reset();
msg = gsm0808_create_reset();
if (!msg) {
LOGP(DMSC, LOGL_ERROR, "Failed to create the reset message.\n");
return;
@@ -833,7 +869,7 @@ static void initialize_if_needed(void)
sccp_write(msg, &sccp_ssn_bssap, &sccp_ssn_bssap, 0);
msgb_free(msg);
msc_con->is_authenticated = 1;
bsc_gsmnet->msc_con->is_authenticated = 1;
}
}
@@ -845,19 +881,38 @@ static void send_id_get_response(int fd)
return;
}
if (!bsc_gsmnet->bsc_token) {
LOGP(DMSC, LOGL_ERROR, "The bsc token is not set.\n");
msg = bsc_msc_id_get_resp(bsc_gsmnet->bsc_token);
if (!msg)
return;
}
msg = msgb_alloc_headroom(4096, 128, "id resp");
msg->l2h = msgb_v_put(msg, IPAC_MSGT_ID_RESP);
msgb_l16tv_put(msg, strlen(bsc_gsmnet->bsc_token) + 1,
IPAC_IDTAG_UNITNAME, (u_int8_t *) bsc_gsmnet->bsc_token);
msc_queue_write(msg, IPAC_PROTO_IPACCESS);
}
/*
* Send some packets to test the MSC.
*/
static void test_msc()
{
struct msgb *msg;
if (!testmode)
return;
static const uint8_t pag_resp[] = {
0x01, 0xf3, 0x26, 0x09, 0x02, 0x02, 0x04, 0x02, 0x42,
0xfe, 0x0f, 0x1f, 0x00, 0x1d, 0x57, 0x05, 0x08, 0x00,
0x72, 0xf4, 0x80, 0x10, 0x1c, 0x9c, 0x40, 0x17, 0x10,
0x06, 0x27, 0x02, 0x03, 0x30, 0x18, 0xa0, 0x08, 0x59,
0x51, 0x30, 0x10, 0x30, 0x32, 0x80, 0x06, 0x00
};
msg = msgb_alloc_headroom(4096, 128, "paging response");
if (!msg)
return;
msg->l2h = msgb_put(msg, sizeof(pag_resp));
memcpy(msg->l2h, pag_resp, sizeof(pag_resp));
msc_queue_write(msg, IPAC_PROTO_SCCP);
}
/*
* The connection to the MSC was lost and we will need to free all
* resources and then attempt to reconnect.
@@ -882,7 +937,7 @@ static void msc_connection_was_lost(struct bsc_msc_connection *msc)
static void msc_pong_timeout_cb(void *data)
{
LOGP(DMSC, LOGL_ERROR, "MSC didn't answer PING. Closing connection.\n");
bsc_msc_lost(msc_con);
bsc_msc_lost(bsc_gsmnet->msc_con);
}
static void send_ping(void)
@@ -917,6 +972,12 @@ static void msc_ping_timeout_cb(void *data)
static void msc_connection_connected(struct bsc_msc_connection *con)
{
int ret, on;
on = 1;
ret = setsockopt(con->write_queue.bfd.fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
if (ret != 0)
LOGP(DMSC, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
msc_ping_timeout_cb(con);
}
@@ -932,7 +993,7 @@ static int ipaccess_a_fd_cb(struct bsc_fd *bfd)
if (!msg) {
if (error == 0) {
LOGP(DMSC, LOGL_ERROR, "The connection to the MSC was lost.\n");
bsc_msc_lost(msc_con);
bsc_msc_lost(bsc_gsmnet->msc_con);
return -1;
}
@@ -952,6 +1013,7 @@ static int ipaccess_a_fd_cb(struct bsc_fd *bfd)
initialize_if_needed();
else if (msg->l2h[0] == IPAC_MSGT_ID_GET) {
send_id_get_response(bfd->fd);
test_msc();
} else if (msg->l2h[0] == IPAC_MSGT_PONG) {
bsc_del_timer(&msc_pong_timeout);
}
@@ -977,6 +1039,7 @@ static void print_help()
printf(" -l --local=IP. The local address of the MGCP.\n");
printf(" -e --log-level number. Set a global loglevel.\n");
printf(" -r --rf-ctl NAME. A unix domain socket to listen for cmds.\n");
printf(" -t --testmode. A special mode to provoke failures at the MSC.\n");
}
static void handle_options(int argc, char** argv)
@@ -993,10 +1056,11 @@ static void handle_options(int argc, char** argv)
{"local", 1, 0, 'l'},
{"log-level", 1, 0, 'e'},
{"rf-ctl", 1, 0, 'r'},
{"testmode", 0, 0, 't'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, "hd:sTc:m:l:e:r:",
c = getopt_long(argc, argv, "hd:sTc:m:l:e:r:t",
long_options, &option_index);
if (c == -1)
break;
@@ -1033,6 +1097,9 @@ static void handle_options(int argc, char** argv)
case 'r':
rf_ctl = optarg;
break;
case 't':
testmode = 1;
break;
default:
/* ignore */
break;
@@ -1059,9 +1126,9 @@ static void signal_handler(int signal)
talloc_report_full(tall_bsc_ctx, stderr);
break;
case SIGUSR2:
if (!msc_con || !msc_con->is_connected)
if (!bsc_gsmnet->msc_con || !bsc_gsmnet->msc_con->is_connected)
return;
bsc_msc_lost(msc_con);
bsc_msc_lost(bsc_gsmnet->msc_con);
break;
default:
break;
@@ -1176,8 +1243,10 @@ int main(int argc, char **argv)
if (msc_address)
msc = msc_address;
msc_con = bsc_msc_create(msc, bsc_gsmnet->msc_port);
if (!msc_con) {
bsc_gsmnet->msc_con = bsc_msc_create(msc,
bsc_gsmnet->msc_port,
bsc_gsmnet->msc_prio);
if (!bsc_gsmnet->msc_con) {
fprintf(stderr, "Creating a bsc_msc_connection failed.\n");
exit(1);
}
@@ -1185,11 +1254,11 @@ int main(int argc, char **argv)
msc_ping_timeout.cb = msc_ping_timeout_cb;
msc_pong_timeout.cb = msc_pong_timeout_cb;
msc_con->connection_loss = msc_connection_was_lost;
msc_con->connected = msc_connection_connected;
msc_con->write_queue.read_cb = ipaccess_a_fd_cb;
msc_con->write_queue.write_cb = msc_sccp_do_write;
bsc_msc_connect(msc_con);
bsc_gsmnet->msc_con->connection_loss = msc_connection_was_lost;
bsc_gsmnet->msc_con->connected = msc_connection_connected;
bsc_gsmnet->msc_con->write_queue.read_cb = ipaccess_a_fd_cb;
bsc_gsmnet->msc_con->write_queue.write_cb = msc_sccp_do_write;
bsc_msc_connect(bsc_gsmnet->msc_con);
@@ -1197,3 +1266,4 @@ int main(int argc, char **argv)
bsc_select_main(0);
}
}

View File

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

View File

@@ -174,7 +174,7 @@ static int bssmap_handle_clear_command(struct sccp_connection *conn,
}
/* send the clear complete message */
resp = bssmap_create_clear_complete();
resp = gsm0808_create_clear_complete();
if (!resp) {
LOGP(DMSC, LOGL_ERROR, "Sending clear complete failed.\n");
return -1;
@@ -312,7 +312,7 @@ static void bssmap_t10_fired(void *_conn)
msc_data = conn->data_ctx;
bssmap_free_secondary(msc_data);
resp = bssmap_create_assignment_failure(
resp = gsm0808_create_assignment_failure(
GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
if (!resp) {
LOGP(DMSC, LOGL_ERROR, "Allocation failure: %p\n", conn);
@@ -765,36 +765,6 @@ struct msgb *bssmap_create_layer3(struct msgb *msg_l3)
return msg;
}
struct msgb *bssmap_create_reset(void)
{
struct msgb *msg = msgb_alloc(30, "bssmap: reset");
if (!msg)
return NULL;
msg->l3h = msgb_put(msg, 6);
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
msg->l3h[1] = 0x04;
msg->l3h[2] = 0x30;
msg->l3h[3] = 0x04;
msg->l3h[4] = 0x01;
msg->l3h[5] = 0x20;
return msg;
}
struct msgb *bssmap_create_clear_complete(void)
{
struct msgb *msg = msgb_alloc(30, "bssmap: clear complete");
if (!msg)
return NULL;
msg->l3h = msgb_put(msg, 3);
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
msg->l3h[1] = 1;
msg->l3h[2] = BSS_MAP_MSG_CLEAR_COMPLETE;
return msg;
}
struct msgb *bssmap_create_cipher_complete(struct msgb *layer3)
{
struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
@@ -902,7 +872,9 @@ static u_int8_t chan_mode_to_speech(struct gsm_lchan *lchan)
break;
}
if (lchan->type == GSM_LCHAN_TCH_H)
/* assume to always do AMR HR on any TCH type */
if (lchan->type == GSM_LCHAN_TCH_H ||
lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
mode |= 0x4;
return mode;
@@ -1005,36 +977,6 @@ struct msgb *bssmap_create_assignment_completed(struct gsm_lchan *lchan, u_int8_
return msg;
}
struct msgb *bssmap_create_assignment_failure(u_int8_t cause, u_int8_t *rr_cause)
{
u_int8_t *data;
struct msgb *msg = msgb_alloc(35, "bssmap: ass fail");
if (!msg)
return NULL;
msg->l3h = msgb_put(msg, 6);
msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
msg->l3h[1] = 0xff;
msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_FAILURE;
msg->l3h[3] = GSM0808_IE_CAUSE;
msg->l3h[4] = 1;
msg->l3h[5] = cause;
/* RR cause 3.2.2.22 */
if (rr_cause) {
data = msgb_put(msg, 2);
data[0] = GSM0808_IE_RR_CAUSE;
data[1] = *rr_cause;
}
/* Circuit pool 3.22.45 */
/* Circuit pool list 3.2.2.46 */
/* update the size */
msg->l3h[1] = msgb_l3len(msg) - 2;
return msg;
}
struct msgb *dtap_create_msg(struct msgb *msg_l3, u_int8_t link_id)
{
struct dtap_header *header;
@@ -1312,7 +1254,7 @@ void gsm0808_send_assignment_failure(struct gsm_lchan *lchan, u_int8_t cause, u_
bsc_del_timer(&lchan->msc_data->T10);
bssmap_free_secondary(lchan->msc_data);
resp = bssmap_create_assignment_failure(cause, rr_value);
resp = gsm0808_create_assignment_failure(cause, rr_value);
if (!resp) {
LOGP(DMSC, LOGL_ERROR, "Allocation failure: %p\n", lchan_get_sccp(lchan));
return;

View File

@@ -25,6 +25,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <openbsc/gsm_data.h>
#include <openbsc/chan_alloc.h>
@@ -287,6 +288,9 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type,
memset(&lchan->conn, 0, sizeof(lchan->conn));
lchan->conn.lchan = lchan;
lchan->conn.bts = lchan->ts->trx->bts;
/* set the alloc time */
gettimeofday(&lchan->alloc_time, NULL);
} else {
struct challoc_signal_data sig;
sig.bts = bts;
@@ -381,6 +385,11 @@ static void _lchan_handle_release(struct gsm_lchan *lchan)
++lchan->conn.use_count;
gsm48_send_rr_release(lchan);
--lchan->conn.use_count;
/* avoid reentrancy */
subscr_put(lchan->conn.subscr);
lchan->conn.subscr = NULL;
return;
}
/* spoofed? message */

View File

@@ -175,24 +175,24 @@ int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause)
{
struct gsm_subscriber_connection *conn;
struct gsm_bts *bts = lchan->ts->trx->bts;
struct msgb *msg = gsm48_msgb_alloc();
struct gsm48_hdr *gh;
struct msgb *msg;
counter_inc(bts->network->stats.loc_upd_resp.reject);
msg = gsm48_create_loc_upd_rej(cause);
if (!msg) {
LOGP(DMM, LOGL_ERROR, "Failed to create msg for LOCATION UPDATING REJECT.\n");
return -1;
}
msg->lchan = lchan;
conn = &lchan->conn;
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
gh->proto_discr = GSM48_PDISC_MM;
gh->msg_type = GSM48_MT_MM_LOC_UPD_REJECT;
gh->data[0] = cause;
LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT "
"LAC=%u BTS=%u\n", conn->subscr ?
subscr_name(conn->subscr) : "unknown",
lchan->ts->trx->bts->location_area_code, lchan->ts->trx->bts->nr);
counter_inc(bts->network->stats.loc_upd_resp.reject);
return gsm48_sendmsg(msg, NULL);
}
@@ -574,19 +574,17 @@ static int gsm48_tx_mm_serv_ack(struct gsm_lchan *lchan)
static int gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn,
enum gsm48_reject_value value)
{
struct msgb *msg = gsm48_msgb_alloc();
struct gsm48_hdr *gh;
struct msgb *msg;
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
msg = gsm48_create_mm_serv_rej(value);
if (!msg) {
LOGP(DMM, LOGL_ERROR, "Failed to allocate CM Service Reject.\n");
return -1;
}
DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value);
msg->lchan = conn->lchan;
use_subscr_con(conn);
gh->proto_discr = GSM48_PDISC_MM;
gh->msg_type = GSM48_MT_MM_CM_SERV_REJ;
gh->data[0] = value;
DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value);
return gsm48_sendmsg(msg, NULL);
}
@@ -609,7 +607,7 @@ static int gsm48_rx_mm_serv_req(struct msgb *msg)
struct gsm48_hdr *gh = msgb_l3(msg);
struct gsm48_service_request *req =
(struct gsm48_service_request *)gh->data;
/* unfortunately in Phase1 the classmar2 length is variable */
/* unfortunately in Phase1 the classmark2 length is variable */
u_int8_t classmark2_len = gh->data[1];
u_int8_t *classmark2 = gh->data+2;
u_int8_t mi_len = *(classmark2 + classmark2_len);
@@ -779,13 +777,16 @@ static int gsm48_rx_rr_pag_resp(struct msgb *msg)
{
struct gsm_bts *bts = msg->lchan->ts->trx->bts;
struct gsm48_hdr *gh = msgb_l3(msg);
struct gsm48_pag_resp *resp;
u_int8_t *classmark2_lv = gh->data + 1;
u_int8_t mi_type;
char mi_string[GSM48_MI_SIZE];
struct gsm_subscriber *subscr = NULL;
int rc = 0;
gsm48_paging_extract_mi(msg, mi_string, &mi_type);
resp = (struct gsm48_pag_resp *) &gh->data[0];
gsm48_paging_extract_mi(resp, msgb_l3len(msg) - sizeof(*gh),
mi_string, &mi_type);
DEBUGP(DRR, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
mi_type, mi_string);

View File

@@ -285,16 +285,30 @@ int send_siemens_mrpci(struct gsm_lchan *lchan,
return rsl_siemens_mrpci(lchan, &mrpci);
}
int gsm48_paging_extract_mi(struct msgb *msg, char *mi_string, u_int8_t *mi_type)
int gsm48_extract_mi(uint8_t *classmark2_lv, int length, char *mi_string, uint8_t *mi_type)
{
struct gsm48_hdr *gh = msgb_l3(msg);
u_int8_t *classmark2_lv = gh->data + 1;
u_int8_t *mi_lv = gh->data + 2 + *classmark2_lv;
*mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
/* Check the size for the classmark */
if (length < 1 + *classmark2_lv)
return -1;
u_int8_t *mi_lv = classmark2_lv + *classmark2_lv + 1;
if (length < 2 + *classmark2_lv + mi_lv[0])
return -2;
*mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
return gsm48_mi_to_string(mi_string, GSM48_MI_SIZE, mi_lv+1, *mi_lv);
}
int gsm48_paging_extract_mi(struct gsm48_pag_resp *resp, int length,
char *mi_string, u_int8_t *mi_type)
{
static const uint32_t classmark_offset =
offsetof(struct gsm48_pag_resp, classmark2);
u_int8_t *classmark2_lv = (uint8_t *) &resp->classmark2;
return gsm48_extract_mi(classmark2_lv, length - classmark_offset,
mi_string, mi_type);
}
int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr)
{
struct gsm_bts *bts = msg->lchan->ts->trx->bts;
@@ -321,7 +335,7 @@ int gsm48_handle_paging_resp(struct msgb *msg, struct gsm_subscriber *subscr)
sig_data.bts = msg->lchan->ts->trx->bts;
sig_data.lchan = msg->lchan;
bts->network->stats.paging.completed++;
counter_inc(bts->network->stats.paging.completed);
dispatch_signal(SS_PAGING, S_PAGING_SUCCEEDED, &sig_data);
@@ -615,3 +629,36 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg)
return 0;
}
struct msgb *gsm48_create_mm_serv_rej(enum gsm48_reject_value value)
{
struct msgb *msg;
struct gsm48_hdr *gh;
msg = gsm48_msgb_alloc();
if (!msg)
return NULL;
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
gh->proto_discr = GSM48_PDISC_MM;
gh->msg_type = GSM48_MT_MM_CM_SERV_REJ;
gh->data[0] = value;
return msg;
}
struct msgb *gsm48_create_loc_upd_rej(uint8_t cause)
{
struct gsm48_hdr *gh;
struct msgb *msg;
msg = gsm48_msgb_alloc();
if (!msg)
return NULL;
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
gh->proto_discr = GSM48_PDISC_MM;
gh->msg_type = GSM48_MT_MM_LOC_UPD_REJECT;
gh->data[0] = cause;
return msg;
}

View File

@@ -172,6 +172,10 @@ struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts)
return trx;
}
static const uint8_t bts_nse_timer_default[] = { 3, 3, 3, 3, 3, 3, 10 };
static const uint8_t bts_cell_timer_default[] =
{ 3, 3, 3, 3, 3, 10, 3, 10, 3, 10, 3 };
struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type,
u_int8_t tsc, u_int8_t bsic)
{
@@ -213,6 +217,10 @@ struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, enum gsm_bts_type type,
bts->gprs.nsvc[i].bts = bts;
bts->gprs.nsvc[i].id = i;
}
memcpy(&bts->gprs.nse.timer, bts_nse_timer_default,
sizeof(bts->gprs.nse.timer));
memcpy(&bts->gprs.cell.timer, bts_cell_timer_default,
sizeof(bts->gprs.cell.timer));
/* create our primary TRX */
bts->c0 = gsm_bts_trx_alloc(bts);

View File

@@ -265,7 +265,7 @@ static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg,
trx->rsl_link = e1inp_sign_link_create(e1i_ts,
E1INP_SIGN_RSL, trx,
trx->rsl_tei, 0);
trx->rsl_link->ts->sign.delay = 10;
trx->rsl_link->ts->sign.delay = 0;
/* get rid of our old temporary bfd */
memcpy(newbfd, bfd, sizeof(*newbfd));

View File

@@ -1,8 +1,8 @@
/* ip.access nanoBTS configuration tool */
/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2009 by Holger Hans Peter Freyther
* (C) 2009 by On Waves
* (C) 2009,2010 by Holger Hans Peter Freyther
* (C) 2009,2010 by On Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -59,7 +59,7 @@ static int sw_load_state = 0;
static int oml_state = 0;
static int dump_files = 0;
static char *firmware_analysis = NULL;
static int trx_nr = 0;
static int found_trx = 0;
struct sw_load {
u_int8_t file_id[255];
@@ -92,23 +92,23 @@ static int ipacc_msg_nack(u_int8_t mt)
return 0;
}
static int ipacc_msg_ack(u_int8_t mt, struct gsm_bts *bts)
static void check_restart_or_exit(struct gsm_bts_trx *trx)
{
if (restart) {
abis_nm_ipaccess_restart(trx);
} else {
exit(0);
}
}
static int ipacc_msg_ack(u_int8_t mt, struct gsm_bts_trx *trx)
{
if (sw_load_state == 1) {
fprintf(stderr, "The new software is activaed.\n");
if (restart) {
abis_nm_ipaccess_restart(bts);
} else {
exit(0);
}
check_restart_or_exit(trx);
} else if (oml_state == 1) {
fprintf(stderr, "Set the primary OML IP.\n");
if (restart) {
abis_nm_ipaccess_restart(bts);
} else {
exit(0);
}
check_restart_or_exit(trx);
}
return 0;
@@ -203,7 +203,7 @@ static int nm_sig_cb(unsigned int subsys, unsigned int signal,
return ipacc_msg_nack(ipacc_data->msg_type);
case S_NM_IPACC_ACK:
ipacc_data = signal_data;
return ipacc_msg_ack(ipacc_data->msg_type, ipacc_data->bts);
return ipacc_msg_ack(ipacc_data->msg_type, ipacc_data->trx);
case S_NM_TEST_REP:
return test_rep(signal_data);
case S_NM_IPACC_RESTART_ACK:
@@ -228,12 +228,12 @@ static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg,
void *data, void *param)
{
struct msgb *msg;
struct gsm_bts *bts;
struct gsm_bts_trx *trx;
if (hook != GSM_HOOK_NM_SWLOAD)
return 0;
bts = (struct gsm_bts *) data;
trx = (struct gsm_bts_trx *) data;
switch (event) {
case NM_MT_LOAD_INIT_ACK:
@@ -272,7 +272,7 @@ static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg,
msg->l2h[1] = msgb_l3len(msg) >> 8;
msg->l2h[2] = msgb_l3len(msg) & 0xff;
printf("Foo l2h: %p l3h: %p... length l2: %u l3: %u\n", msg->l2h, msg->l3h, msgb_l2len(msg), msgb_l3len(msg));
abis_nm_ipaccess_set_nvattr(bts->c0, msg->l2h, msgb_l2len(msg));
abis_nm_ipaccess_set_nvattr(trx, msg->l2h, msgb_l2len(msg));
msgb_free(msg);
break;
case NM_MT_LOAD_END_NACK:
@@ -286,7 +286,7 @@ static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg,
case NM_MT_ACTIVATE_SW_ACK:
break;
case NM_MT_LOAD_SEG_ACK:
percent = abis_nm_software_load_status(bts);
percent = abis_nm_software_load_status(trx->bts);
if (percent > percent_old)
printf("Software Download Progress: %d%%\n", percent);
percent_old = percent;
@@ -299,13 +299,13 @@ static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg,
return 0;
}
static void bootstrap_om(struct gsm_bts *bts)
static void bootstrap_om(struct gsm_bts_trx *trx)
{
int len;
static u_int8_t buf[1024];
u_int8_t *cur = buf;
printf("OML link established\n");
printf("OML link established using TRX %d\n", trx->nr);
if (unit_id) {
len = strlen(unit_id);
@@ -317,8 +317,7 @@ static void bootstrap_om(struct gsm_bts *bts)
memcpy(buf+3, unit_id, len);
buf[3+len] = 0;
printf("setting Unit ID to '%s'\n", unit_id);
abis_nm_ipaccess_set_nvattr(gsm_bts_trx_by_nr(bts, trx_nr),
buf, 3+len+1);
abis_nm_ipaccess_set_nvattr(trx, buf, 3+len+1);
}
if (prim_oml_ip) {
struct in_addr ia;
@@ -342,7 +341,7 @@ static void bootstrap_om(struct gsm_bts *bts)
*cur++ = 0;
printf("setting primary OML link IP to '%s'\n", inet_ntoa(ia));
oml_state = 1;
abis_nm_ipaccess_set_nvattr(bts->c0, buf, 3+len);
abis_nm_ipaccess_set_nvattr(trx, buf, 3+len);
}
if (nv_mask) {
len = 4;
@@ -356,13 +355,12 @@ static void bootstrap_om(struct gsm_bts *bts)
*cur++ = nv_mask >> 8;
printf("setting NV Flags/Mask to 0x%04x/0x%04x\n",
nv_flags, nv_mask);
abis_nm_ipaccess_set_nvattr(gsm_bts_trx_by_nr(bts, trx_nr),
buf, 3+len);
abis_nm_ipaccess_set_nvattr(trx, buf, 3+len);
}
if (restart && !prim_oml_ip && !software) {
printf("restarting BTS\n");
abis_nm_ipaccess_restart(bts);
abis_nm_ipaccess_restart(trx);
}
}
@@ -373,7 +371,6 @@ void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
case EVT_E1_TEI_UP:
switch (type) {
case E1INP_SIGN_OML:
bootstrap_om(trx->bts);
break;
case E1INP_SIGN_RSL:
/* FIXME */
@@ -392,22 +389,29 @@ void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
}
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
struct abis_om_obj_inst *obj_inst)
{
if (evt == EVT_STATECHG_OPER &&
if (obj_class == NM_OC_BASEB_TRANSC) {
if (!found_trx && obj_inst->trx_nr != 0xff) {
struct gsm_bts_trx *trx = container_of(obj, struct gsm_bts_trx, bb_transc);
bootstrap_om(trx);
found_trx = 1;
}
} else if (evt == EVT_STATECHG_OPER &&
obj_class == NM_OC_RADIO_CARRIER &&
new_state->availability == 3) {
struct gsm_bts_trx *trx = obj;
if (net_listen_testnr) {
u_int8_t phys_config[] = { 0x02, 0x0a, 0x00, 0x01, 0x02 };
abis_nm_perform_test(trx->bts, 2, 0, 0, 0xff,
abis_nm_perform_test(trx->bts, 2, 0, trx->nr, 0xff,
net_listen_testnr, 1,
phys_config, sizeof(phys_config));
} else if (software) {
int rc;
printf("Attempting software upload with '%s'\n", software);
rc = abis_nm_software_load(trx->bts, software, 19, 0, swload_cbfn, trx->bts);
rc = abis_nm_software_load(trx->bts, trx->nr, software, 19, 0, swload_cbfn, trx);
if (rc < 0) {
fprintf(stderr, "Failed to start software load\n");
exit(-3);
@@ -608,7 +612,6 @@ static void print_help(void)
printf(" -d --software firmware\n");
printf(" -f --firmware firmware Provide firmware information\n");
printf(" -w --write-firmware. This will dump the firmware parts to the filesystem. Use with -f.\n");
printf(" -t --trx NR. The TRX to use for the Unit ID and NVRAM attributes.\n");
}
int main(int argc, char **argv)
@@ -643,11 +646,10 @@ int main(int argc, char **argv)
{ "software", 1, 0, 'd' },
{ "firmware", 1, 0, 'f' },
{ "write-firmware", 0, 0, 'w' },
{ "trx", 1, 0, 't' },
{ 0, 0, 0, 0 },
};
c = getopt_long(argc, argv, "u:o:rn:l:hs:d:f:wt:", long_options,
c = getopt_long(argc, argv, "u:o:rn:l:hs:d:f:w", long_options,
&option_index);
if (c == -1)
@@ -689,9 +691,6 @@ int main(int argc, char **argv)
case 'w':
dump_files = 1;
break;
case 't':
trx_nr = atoi(optarg);
break;
case 'h':
print_usage();
print_help();

View File

@@ -23,6 +23,7 @@
*/
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <endian.h>
#include <errno.h>
@@ -152,7 +153,7 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
*/
#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 &&
(endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port)
(endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port)
? DEST_BTS : DEST_NETWORK;
proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP;
@@ -176,7 +177,7 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
}
}
/* throw away dummy message */
/* throw away the dummy message */
if (rc == 1 && buf[0] == DUMMY_LOAD) {
LOGP(DMGCP, LOGL_NOTICE, "Filtered dummy on 0x%x\n",
ENDPOINT_NUMBER(endp));
@@ -189,17 +190,19 @@ static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
else
++endp->in_remote;
/* dispatch */
/* For loop toggle the destination and then dispatch. */
if (cfg->audio_loop)
dest = !dest;
if (dest == DEST_NETWORK) {
patch_payload(endp->net_payload_type, buf, rc);
if (proto == PROTO_RTP)
patch_payload(endp->net_payload_type, buf, rc);
return udp_send(fd->fd, &endp->remote,
proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp,
buf, rc);
} else {
patch_payload(endp->bts_payload_type, buf, rc);
if (proto == PROTO_RTP)
patch_payload(endp->bts_payload_type, buf, rc);
return udp_send(fd->fd, &endp->bts,
proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp,
buf, rc);
@@ -230,6 +233,14 @@ static int create_bind(const char *source_addr, struct bsc_fd *fd, int port)
return 0;
}
static int set_ip_tos(int fd, int tos)
{
int ret;
ret = setsockopt(fd, IPPROTO_IP, IP_TOS,
&tos, sizeof(tos));
return ret != 0;
}
static int bind_rtp(struct mgcp_endpoint *endp)
{
struct mgcp_config *cfg = endp->cfg;
@@ -246,6 +257,9 @@ static int bind_rtp(struct mgcp_endpoint *endp)
goto cleanup1;
}
set_ip_tos(endp->local_rtp.fd, cfg->endp_tos);
set_ip_tos(endp->local_rtcp.fd, cfg->endp_tos);
endp->local_rtp.cb = rtp_data_cb;
endp->local_rtp.data = endp;
endp->local_rtp.when = BSC_FD_READ;

View File

@@ -135,7 +135,7 @@ static struct msgb *mgcp_msgb_alloc(void)
struct msgb *msg;
msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
if (!msg)
LOGP(DMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
LOGP(DMGCP, LOGL_ERROR, "Failed to msgb for MGCP data.\n");
return msg;
}

View File

@@ -57,6 +57,7 @@ static int config_write_mgcp(struct vty *vty)
vty_out(vty, " bind port %u%s", g_cfg->source_port, VTY_NEWLINE);
vty_out(vty, " bind early %u%s", !!g_cfg->early_bind, VTY_NEWLINE);
vty_out(vty, " rtp base %u%s", g_cfg->rtp_base_port, VTY_NEWLINE);
vty_out(vty, " rtp ip-tos %d%s", g_cfg->endp_tos, VTY_NEWLINE);
if (g_cfg->audio_payload != -1)
vty_out(vty, " sdp audio payload number %d%s", g_cfg->audio_payload, VTY_NEWLINE);
if (g_cfg->audio_name)
@@ -103,7 +104,7 @@ DEFUN(cfg_mgcp,
DEFUN(cfg_mgcp_local_ip,
cfg_mgcp_local_ip_cmd,
"local ip IP",
"local ip A.B.C.D",
"Set the IP to be used in SDP records")
{
if (g_cfg->local_ip)
@@ -114,7 +115,7 @@ DEFUN(cfg_mgcp_local_ip,
DEFUN(cfg_mgcp_bts_ip,
cfg_mgcp_bts_ip_cmd,
"bts ip IP",
"bts ip A.B.C.D",
"Set the IP of the BTS for RTP forwarding")
{
if (g_cfg->bts_ip)
@@ -126,7 +127,7 @@ DEFUN(cfg_mgcp_bts_ip,
DEFUN(cfg_mgcp_bind_ip,
cfg_mgcp_bind_ip_cmd,
"bind ip IP",
"bind ip A.B.C.D",
"Bind the MGCP to this local addr")
{
if (g_cfg->source_addr)
@@ -141,11 +142,6 @@ DEFUN(cfg_mgcp_bind_port,
"Bind the MGCP to this port")
{
unsigned int port = atoi(argv[0]);
if (port > 65534) {
vty_out(vty, "%% wrong bind port '%s'%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
g_cfg->source_port = port;
return CMD_SUCCESS;
}
@@ -156,11 +152,6 @@ DEFUN(cfg_mgcp_bind_early,
"Bind all RTP ports early")
{
unsigned int bind = atoi(argv[0]);
if (bind != 0 && bind != 1) {
vty_out(vty, "%% param must be 0 or 1.%s", VTY_NEWLINE);
return CMD_WARNING;
}
g_cfg->early_bind = bind == 1;
return CMD_SUCCESS;
}
@@ -171,26 +162,26 @@ DEFUN(cfg_mgcp_rtp_base_port,
"Base port to use")
{
unsigned int port = atoi(argv[0]);
if (port > 65534) {
vty_out(vty, "%% wrong base port '%s'%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
g_cfg->rtp_base_port = port;
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_rtp_ip_tos,
cfg_mgcp_rtp_ip_tos_cmd,
"rtp ip-tos <0-255>",
"Set the IP_TOS socket attribute on the RTP/RTCP sockets.\n" "The TOS value.")
{
int tos = atoi(argv[0]);
g_cfg->endp_tos = tos;
return CMD_SUCCESS;
}
DEFUN(cfg_mgcp_sdp_payload_number,
cfg_mgcp_sdp_payload_number_cmd,
"sdp audio payload number <1-255>",
"Set the audio codec to use")
{
unsigned int payload = atoi(argv[0]);
if (payload > 255) {
vty_out(vty, "%% wrong payload number '%s'%s", argv[0], VTY_NEWLINE);
return CMD_WARNING;
}
g_cfg->audio_payload = payload;
return CMD_SUCCESS;
}
@@ -227,7 +218,7 @@ DEFUN(cfg_mgcp_number_endp,
DEFUN(cfg_mgcp_forward_ip,
cfg_mgcp_forward_ip_cmd,
"forward audio ip IP",
"forward audio ip A.B.C.D",
"Forward packets from and to the IP. This disables most of the MGCP feature.")
{
if (g_cfg->forward_ip)
@@ -269,6 +260,7 @@ int mgcp_vty_init(void)
install_element(MGCP_NODE, &cfg_mgcp_bind_port_cmd);
install_element(MGCP_NODE, &cfg_mgcp_bind_early_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_base_port_cmd);
install_element(MGCP_NODE, &cfg_mgcp_rtp_ip_tos_cmd);
install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_number_cmd);
install_element(MGCP_NODE, &cfg_mgcp_sdp_payload_name_cmd);
install_element(MGCP_NODE, &cfg_mgcp_loop_cmd);
@@ -306,8 +298,8 @@ int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg)
/*
* This application supports two modes.
* 1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX
* 2.) plain forwarding of RTP packets on the endpoints.
* 1.) a true MGCP gateway with support for AUEP, CRCX, MDCX, DLCX
* 2.) plain forwarding of RTP packets on the endpoints.
* both modes are mutual exclusive
*/
if (g_cfg->forward_ip) {

View File

@@ -23,6 +23,7 @@
*/
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <errno.h>
@@ -44,17 +45,21 @@
#include <openbsc/telnet_interface.h>
#include <osmocore/talloc.h>
#include <osmocore/gsm0808.h>
#include <vty/vty.h>
#include <sccp/sccp.h>
#define SCCP_CLOSE_TIME 20
#define SCCP_CLOSE_TIME_TIMEOUT 19
struct log_target *stderr_target;
static const char *config_file = "bsc-nat.cfg";
static struct in_addr local_addr;
static struct bsc_msc_connection *msc_con;
static struct bsc_fd bsc_listen;
static const char *msc_ip = NULL;
static struct timer_list sccp_close;
static struct bsc_nat *nat;
@@ -76,7 +81,8 @@ struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num)
* below are stubs we need to link
*/
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
struct abis_om_obj_inst *obj_ins)
{
return -1;
}
@@ -91,7 +97,7 @@ int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
static void queue_for_msc(struct bsc_msc_connection *con, struct msgb *msg)
{
if (write_queue_enqueue(&msc_con->write_queue, msg) != 0) {
if (write_queue_enqueue(&nat->msc_con->write_queue, msg) != 0) {
LOGP(DINP, LOGL_ERROR, "Failed to enqueue the write.\n");
msgb_free(msg);
}
@@ -206,7 +212,7 @@ static void nat_send_rlsd(struct sccp_connections *conn)
ipaccess_prepend_header(msg, IPAC_PROTO_SCCP);
queue_for_msc(msc_con, msg);
queue_for_msc(nat->msc_con, msg);
}
static void nat_send_rlc(struct sccp_source_reference *src,
@@ -229,7 +235,7 @@ static void nat_send_rlc(struct sccp_source_reference *src,
ipaccess_prepend_header(msg, IPAC_PROTO_SCCP);
queue_for_msc(msc_con, msg);
queue_for_msc(nat->msc_con, msg);
}
static void send_mgcp_reset(struct bsc_connection *bsc)
@@ -252,7 +258,17 @@ static void initialize_msc_if_needed()
return;
nat->first_contact = 1;
msc_send_reset(msc_con);
msc_send_reset(nat->msc_con);
}
static void send_id_get_response()
{
struct msgb *msg = bsc_msc_id_get_resp(nat->token);
if (!msg)
return;
ipaccess_prepend_header(msg, IPAC_PROTO_IPACCESS);
queue_for_msc(nat->msc_con, msg);
}
/*
@@ -279,6 +295,83 @@ static void bsc_send_data(struct bsc_connection *bsc, const u_int8_t *data, unsi
bsc_write(bsc, msg, proto);
}
static void bsc_send_con_refuse(struct bsc_connection *bsc,
struct bsc_nat_parsed *parsed, int con_type)
{
struct msgb *payload;
struct msgb *refuse;
if (con_type == NAT_CON_TYPE_LU)
payload = gsm48_create_loc_upd_rej(GSM48_REJECT_PLMN_NOT_ALLOWED);
else if (con_type == NAT_CON_TYPE_CM_SERV_REQ)
payload = gsm48_create_mm_serv_rej(GSM48_REJECT_PLMN_NOT_ALLOWED);
/*
* Some BSCs do not handle the payload inside a SCCP CREF msg
* so we will need to:
* 1.) Allocate a local connection and mark it as local..
* 2.) queue data for downstream.. and the RLC should delete everything
*/
if (payload) {
struct msgb *cc, *udt, *rlsd;
struct sccp_connections *con;
con = create_sccp_src_ref(bsc, parsed);
if (!con)
goto send_refuse;
/* declare it local and assign a unique remote_ref */
con->con_type = NAT_CON_TYPE_LOCAL_REJECT;
con->con_local = 1;
con->has_remote_ref = 1;
con->remote_ref = con->patched_ref;
/* 1. create a confirmation */
cc = sccp_create_cc(&con->remote_ref, &con->real_ref);
if (!cc)
goto send_refuse;
/* 2. create the DT1 */
gsm0808_prepend_dtap_header(payload, 0);
udt = sccp_create_dt1(&con->real_ref, payload->data, payload->len);
if (!udt) {
msgb_free(cc);
goto send_refuse;
}
/* 3. send a RLSD */
rlsd = sccp_create_rlsd(&con->remote_ref, &con->real_ref,
SCCP_RELEASE_CAUSE_END_USER_ORIGINATED);
if (!rlsd) {
msgb_free(cc);
msgb_free(udt);
goto send_refuse;
}
bsc_write(bsc, cc, IPAC_PROTO_SCCP);
bsc_write(bsc, udt, IPAC_PROTO_SCCP);
bsc_write(bsc, rlsd, IPAC_PROTO_SCCP);
msgb_free(payload);
return;
}
send_refuse:
if (payload)
msgb_free(payload);
refuse = sccp_create_refuse(parsed->src_local_ref,
SCCP_REFUSAL_SCCP_FAILURE, NULL, 0);
if (!refuse) {
LOGP(DNAT, LOGL_ERROR,
"Creating refuse msg failed for SCCP 0x%x on BSC Nr: %d.\n",
sccp_src_ref_to_int(parsed->src_local_ref), bsc->cfg->nr);
return;
}
bsc_write(bsc, refuse, IPAC_PROTO_SCCP);
}
static int forward_sccp_to_bts(struct msgb *msg)
{
struct sccp_connections *con;
@@ -341,7 +434,7 @@ static int forward_sccp_to_bts(struct msgb *msg)
/* Exchange src/dest for the reply */
nat_send_rlc(parsed->dest_local_ref, parsed->src_local_ref);
} else if (!con)
LOGP(DNAT, LOGL_ERROR, "Unknown connection for msg type: 0x%x.\n", parsed->sccp_type);
LOGP(DNAT, LOGL_ERROR, "Unknown connection for msg type: 0x%x from the MSC.\n", parsed->sccp_type);
}
talloc_free(parsed);
@@ -422,7 +515,7 @@ static void msc_send_reset(struct bsc_msc_connection *msc_con)
msg->l2h = msgb_put(msg, sizeof(reset));
memcpy(msg->l2h, reset, msgb_l2len(msg));
queue_for_msc(msc_con, msg);
queue_for_msc(nat->msc_con, msg);
LOGP(DMSC, LOGL_NOTICE, "Scheduled GSM0808 reset msg for the MSC.\n");
}
@@ -439,7 +532,7 @@ static int ipaccess_msc_read_cb(struct bsc_fd *bfd)
else
LOGP(DNAT, LOGL_ERROR, "Failed to parse ip access message: %d\n", error);
bsc_msc_lost(msc_con);
bsc_msc_lost(nat->msc_con);
return -1;
}
@@ -450,9 +543,12 @@ static int ipaccess_msc_read_cb(struct bsc_fd *bfd)
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)
if (hh->proto == IPAC_PROTO_IPACCESS) {
if (msg->l2h[0] == IPAC_MSGT_ID_ACK)
initialize_msc_if_needed();
else if (msg->l2h[0] == IPAC_MSGT_ID_GET)
send_id_get_response();
} else if (hh->proto == IPAC_PROTO_SCCP)
forward_sccp_to_bts(msg);
msgb_free(msg);
@@ -556,7 +652,10 @@ static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc
static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
{
struct sccp_connections *con;
int con_found = 0;
int con_filter = 0;
struct bsc_connection *con_bsc = NULL;
int con_type;
struct bsc_nat_parsed *parsed;
/* Parse and filter messages */
@@ -584,11 +683,17 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
/* modify the SCCP entries */
if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
struct sccp_connections *con;
switch (parsed->sccp_type) {
case SCCP_MSG_TYPE_CR:
if (create_sccp_src_ref(bsc, msg, parsed) != 0)
if (bsc_nat_filter_sccp_cr(bsc, msg, parsed, &con_type) != 0)
goto exit3;
if (!create_sccp_src_ref(bsc, parsed))
goto exit2;
con = patch_sccp_src_ref_to_msc(msg, parsed, bsc);
con->con_type = con_type;
con_found = 1;
con_bsc = con->bsc;
break;
case SCCP_MSG_TYPE_RLSD:
case SCCP_MSG_TYPE_CREF:
@@ -596,9 +701,19 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
case SCCP_MSG_TYPE_CC:
case SCCP_MSG_TYPE_IT:
con = patch_sccp_src_ref_to_msc(msg, parsed, bsc);
if (con) {
con_found = 1;
con_bsc = con->bsc;
con_filter = con->con_local;
}
break;
case SCCP_MSG_TYPE_RLC:
con = patch_sccp_src_ref_to_msc(msg, parsed, bsc);
if (con) {
con_found = 1;
con_bsc = con->bsc;
con_filter = con->con_local;
}
remove_sccp_src_ref(bsc, msg, parsed);
break;
case SCCP_MSG_TYPE_UDT:
@@ -619,14 +734,18 @@ static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
goto exit2;
}
if (con && con->bsc != bsc) {
if (con_found && con_bsc != bsc) {
LOGP(DNAT, LOGL_ERROR, "The connection belongs to a different BTS: input: %d con: %d\n",
bsc->cfg->nr, con->bsc->cfg->nr);
bsc->cfg->nr, con_bsc->cfg->nr);
goto exit2;
}
/* do not forward messages to the MSC */
if (con_filter)
goto exit2;
/* send the non-filtered but maybe modified msg */
queue_for_msc(msc_con, msg);
queue_for_msc(nat->msc_con, msg);
talloc_free(parsed);
return 0;
@@ -653,6 +772,13 @@ exit2:
talloc_free(parsed);
msgb_free(msg);
return -1;
exit3:
/* send a SCCP Connection Refused */
bsc_send_con_refuse(bsc, parsed, con_type);
talloc_free(parsed);
msgb_free(msg);
return -1;
}
static int ipaccess_bsc_read_cb(struct bsc_fd *bfd)
@@ -716,17 +842,17 @@ static int ipaccess_bsc_write_cb(struct bsc_fd *bfd, struct msgb *msg)
static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what)
{
struct bsc_connection *bsc;
int ret;
int fd, rc, on;
struct sockaddr_in sa;
socklen_t sa_len = sizeof(sa);
if (!(what & BSC_FD_READ))
return 0;
ret = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len);
if (ret < 0) {
fd = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len);
if (fd < 0) {
perror("accept");
return ret;
return fd;
}
/* count the reconnect */
@@ -735,12 +861,22 @@ static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what)
/*
* if we are not connected to a msc... just close the socket
*/
if (!msc_con->is_connected) {
if (!nat->msc_con->is_connected) {
LOGP(DNAT, LOGL_NOTICE, "Disconnecting BSC due lack of MSC connection.\n");
close(ret);
close(fd);
return 0;
}
on = 1;
rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
if (rc != 0)
LOGP(DNAT, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
rc = setsockopt(fd, IPPROTO_IP, IP_TOS,
&nat->bsc_ip_tos, sizeof(nat->bsc_ip_tos));
if (rc != 0)
LOGP(DNAT, LOGL_ERROR, "Failed to set IP_TOS: %s\n", strerror(errno));
/* todo... do something with the connection */
/* todo... use GNUtls to see if we want to trust this as a BTS */
@@ -750,24 +886,24 @@ static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what)
bsc = bsc_connection_alloc(nat);
if (!bsc) {
LOGP(DNAT, LOGL_ERROR, "Failed to allocate BSC struct.\n");
close(ret);
close(fd);
return -1;
}
bsc->write_queue.bfd.data = bsc;
bsc->write_queue.bfd.fd = ret;
bsc->write_queue.bfd.fd = fd;
bsc->write_queue.read_cb = ipaccess_bsc_read_cb;
bsc->write_queue.write_cb = ipaccess_bsc_write_cb;
bsc->write_queue.bfd.when = BSC_FD_READ;
if (bsc_register_fd(&bsc->write_queue.bfd) < 0) {
LOGP(DNAT, LOGL_ERROR, "Failed to register BSC fd.\n");
close(ret);
close(fd);
talloc_free(bsc);
return -2;
}
LOGP(DNAT, LOGL_NOTICE, "BSC connection on %d with IP: %s\n",
ret, inet_ntoa(sa.sin_addr));
fd, inet_ntoa(sa.sin_addr));
llist_add(&bsc->list_entry, &nat->bsc_connections);
send_id_ack(bsc);
send_id_req(bsc);
@@ -899,6 +1035,29 @@ static void signal_handler(int signal)
}
}
static void sccp_close_unconfirmed(void *_data)
{
struct sccp_connections *conn, *tmp1;
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
llist_for_each_entry_safe(conn, tmp1, &nat->sccp_connections, list_entry) {
if (conn->has_remote_ref)
continue;
int diff = (now.tv_sec - conn->creation_time.tv_sec) / 60;
if (diff < SCCP_CLOSE_TIME_TIMEOUT)
continue;
LOGP(DNAT, LOGL_ERROR, "SCCP connection 0x%x/0x%x was never confirmed.\n",
sccp_src_ref_to_int(&conn->real_ref),
sccp_src_ref_to_int(&conn->patched_ref));
sccp_connection_destroy(conn);
}
bsc_schedule_timer(&sccp_close, SCCP_CLOSE_TIME, 0);
}
extern void *tall_msgb_ctx;
extern void *tall_ctr_ctx;
static void talloc_init_ctx()
@@ -955,16 +1114,16 @@ int main(int argc, char** argv)
return -4;
/* connect to the MSC */
msc_con = bsc_msc_create(nat->msc_ip, nat->msc_port);
if (!msc_con) {
nat->msc_con = bsc_msc_create(nat->msc_ip, nat->msc_port, 0);
if (!nat->msc_con) {
fprintf(stderr, "Creating a bsc_msc_connection failed.\n");
exit(1);
}
msc_con->connection_loss = msc_connection_was_lost;
msc_con->write_queue.read_cb = ipaccess_msc_read_cb;
msc_con->write_queue.write_cb = ipaccess_msc_write_cb;;
bsc_msc_connect(msc_con);
nat->msc_con->connection_loss = msc_connection_was_lost;
nat->msc_con->write_queue.read_cb = ipaccess_msc_read_cb;
nat->msc_con->write_queue.write_cb = ipaccess_msc_write_cb;;
bsc_msc_connect(nat->msc_con);
/* wait for the BSC */
if (listen_for_bsc(&bsc_listen, &local_addr, 5000) < 0) {
@@ -976,6 +1135,11 @@ int main(int argc, char** argv)
signal(SIGUSR1, &signal_handler);
signal(SIGPIPE, SIG_IGN);
/* recycle timer */
sccp_close.cb = sccp_close_unconfirmed;
sccp_close.data = NULL;
bsc_schedule_timer(&sccp_close, SCCP_CLOSE_TIME, 0);
while (1) {
bsc_select_main(0);
}

View File

@@ -46,6 +46,8 @@ struct bsc_nat *bsc_nat_alloc(void)
INIT_LLIST_HEAD(&nat->sccp_connections);
INIT_LLIST_HEAD(&nat->bsc_connections);
INIT_LLIST_HEAD(&nat->bsc_configs);
INIT_LLIST_HEAD(&nat->access_lists);
nat->stats.sccp.conn = counter_alloc("nat.sccp.conn");
nat->stats.sccp.calls = counter_alloc("nat.sccp.calls");
nat->stats.bsc.reconn = counter_alloc("nat.bsc.conn");
@@ -193,3 +195,297 @@ int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int proto)
return 0;
}
static int lst_check_allow(struct bsc_nat_acc_lst *lst, const char *mi_string)
{
struct bsc_nat_acc_lst_entry *entry;
llist_for_each_entry(entry, &lst->fltr_list, list) {
if (!entry->imsi_allow)
continue;
if (regexec(&entry->imsi_allow_re, mi_string, 0, NULL, 0) == 0)
return 0;
}
return 1;
}
static int lst_check_deny(struct bsc_nat_acc_lst *lst, const char *mi_string)
{
struct bsc_nat_acc_lst_entry *entry;
llist_for_each_entry(entry, &lst->fltr_list, list) {
if (!entry->imsi_deny)
continue;
if (regexec(&entry->imsi_deny_re, mi_string, 0, NULL, 0) == 0)
return 0;
}
return 1;
}
/* apply white/black list */
static int auth_imsi(struct bsc_connection *bsc, const char *mi_string)
{
/*
* Now apply blacklist/whitelist of the BSC and the NAT.
* 1.) Reject if the IMSI is not allowed at the BSC
* 2.) Allow directly if the IMSI is allowed at the BSC
* 3.) Reject if the IMSI not allowed at the global level.
* 4.) Allow directly if the IMSI is allowed at the global level
*/
struct bsc_nat_acc_lst *nat_lst = NULL;
struct bsc_nat_acc_lst *bsc_lst = NULL;
bsc_lst = bsc_nat_acc_lst_find(bsc->nat, bsc->cfg->acc_lst_name);
nat_lst = bsc_nat_acc_lst_find(bsc->nat, bsc->nat->acc_lst_name);
if (bsc_lst) {
/* 1. BSC deny */
if (lst_check_deny(bsc_lst, mi_string) == 0) {
LOGP(DNAT, LOGL_ERROR,
"Filtering %s by imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr);
return -2;
}
/* 2. BSC allow */
if (lst_check_allow(bsc_lst, mi_string) == 0)
return 0;
}
/* 3. NAT deny */
if (nat_lst) {
if (lst_check_deny(nat_lst, mi_string) == 0) {
LOGP(DNAT, LOGL_ERROR,
"Filtering %s by nat imsi_deny on bsc nr: %d.\n", mi_string, bsc->cfg->nr);
return -3;
}
}
return 0;
}
static int _cr_check_loc_upd(struct bsc_connection *bsc, uint8_t *data, unsigned int length)
{
u_int8_t mi_type;
struct gsm48_loc_upd_req *lu;
char mi_string[GSM48_MI_SIZE];
if (length < sizeof(*lu)) {
LOGP(DNAT, LOGL_ERROR,
"LU does not fit. Length is %d \n", length);
return -1;
}
lu = (struct gsm48_loc_upd_req *) data;
mi_type = lu->mi[0] & GSM_MI_TYPE_MASK;
/*
* We can only deal with the IMSI. This will fail for a phone that
* will send the TMSI of a previous network to us.
*/
if (mi_type != GSM_MI_TYPE_IMSI)
return 0;
gsm48_mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len);
return auth_imsi(bsc, mi_string);
}
static int _cr_check_cm_serv_req(struct bsc_connection *bsc, uint8_t *data, unsigned int length)
{
static const uint32_t classmark_offset =
offsetof(struct gsm48_service_request, classmark);
char mi_string[GSM48_MI_SIZE];
uint8_t mi_type;
int rc;
struct gsm48_service_request *req;
/* unfortunately in Phase1 the classmark2 length is variable */
if (length < sizeof(*req)) {
LOGP(DNAT, LOGL_ERROR,
"CM Serv Req does not fit. Length is %d\n", length);
return -1;
}
req = (struct gsm48_service_request *) data;
rc = gsm48_extract_mi((uint8_t *) &req->classmark,
length - classmark_offset, mi_string, &mi_type);
if (rc < 0) {
LOGP(DNAT, LOGL_ERROR, "Failed to parse the classmark2/mi. error: %d\n", rc);
return -1;
}
/* we have to let the TMSI or such pass */
if (mi_type != GSM_MI_TYPE_IMSI)
return 0;
return auth_imsi(bsc, mi_string);
}
static int _cr_check_pag_resp(struct bsc_connection *bsc, uint8_t *data, unsigned int length)
{
struct gsm48_pag_resp *resp;
char mi_string[GSM48_MI_SIZE];
u_int8_t mi_type;
if (length < sizeof(*resp)) {
LOGP(DNAT, LOGL_ERROR, "PAG RESP does not fit. Length was %d.\n", length);
return -1;
}
resp = (struct gsm48_pag_resp *) data;
if (gsm48_paging_extract_mi(resp, length, mi_string, &mi_type) < 0) {
LOGP(DNAT, LOGL_ERROR, "Failed to extract the MI.\n");
return -1;
}
/* we need to let it pass for now */
if (mi_type != GSM_MI_TYPE_IMSI)
return 0;
return auth_imsi(bsc, mi_string);
}
/* Filter out CR data... */
int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed, int *con_type)
{
struct tlv_parsed tp;
struct gsm48_hdr *hdr48;
int hdr48_len;
int len;
*con_type = NAT_CON_TYPE_NONE;
if (parsed->gsm_type != BSS_MAP_MSG_COMPLETE_LAYER_3) {
LOGP(DNAT, LOGL_ERROR,
"Rejecting CR message due wrong GSM Type %d\n", parsed->gsm_type);
return -1;
}
/* the parsed has had some basic l3 length check */
len = msg->l3h[1];
if (msgb_l3len(msg) - 3 < len) {
LOGP(DNAT, LOGL_ERROR,
"The CR Data has not enough space...\n");
return -1;
}
msg->l4h = &msg->l3h[3];
len -= 1;
tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h, len, 0, 0);
if (!TLVP_PRESENT(&tp, GSM0808_IE_LAYER_3_INFORMATION)) {
LOGP(DNAT, LOGL_ERROR, "CR Data does not contain layer3 information.\n");
return -1;
}
hdr48_len = TLVP_LEN(&tp, GSM0808_IE_LAYER_3_INFORMATION);
if (hdr48_len < sizeof(*hdr48)) {
LOGP(DNAT, LOGL_ERROR, "GSM48 header does not fit.\n");
return -1;
}
hdr48 = (struct gsm48_hdr *) TLVP_VAL(&tp, GSM0808_IE_LAYER_3_INFORMATION);
if (hdr48->proto_discr == GSM48_PDISC_MM &&
hdr48->msg_type == GSM48_MT_MM_LOC_UPD_REQUEST) {
*con_type = NAT_CON_TYPE_LU;
return _cr_check_loc_upd(bsc, &hdr48->data[0], hdr48_len - sizeof(*hdr48));
} else if (hdr48->proto_discr == GSM48_PDISC_MM &&
hdr48->msg_type == GSM48_MT_MM_CM_SERV_REQ) {
*con_type = NAT_CON_TYPE_CM_SERV_REQ;
return _cr_check_cm_serv_req(bsc, &hdr48->data[0], hdr48_len - sizeof(*hdr48));
} else if (hdr48->proto_discr == GSM48_PDISC_RR &&
hdr48->msg_type == GSM48_MT_RR_PAG_RESP) {
*con_type = NAT_CON_TYPE_PAG_RESP;
return _cr_check_pag_resp(bsc, &hdr48->data[0], hdr48_len - sizeof(*hdr48));
} else {
/* We only want to filter the above, let other things pass */
*con_type = NAT_CON_TYPE_OTHER;
return 0;
}
}
void bsc_parse_reg(void *ctx, regex_t *reg, char **imsi, int argc, const char **argv)
{
if (*imsi) {
talloc_free(*imsi);
*imsi = NULL;
}
regfree(reg);
if (argc > 0) {
*imsi = talloc_strdup(ctx, argv[0]);
regcomp(reg, argv[0], 0);
}
}
static const char *con_types [] = {
[NAT_CON_TYPE_NONE] = "n/a",
[NAT_CON_TYPE_LU] = "Location Update",
[NAT_CON_TYPE_CM_SERV_REQ] = "CM Serv Req",
[NAT_CON_TYPE_PAG_RESP] = "Paging Response",
[NAT_CON_TYPE_LOCAL_REJECT] = "Local Reject",
[NAT_CON_TYPE_OTHER] = "Other",
};
const char *bsc_con_type_to_string(int type)
{
return con_types[type];
}
struct bsc_nat_acc_lst *bsc_nat_acc_lst_find(struct bsc_nat *nat, const char *name)
{
struct bsc_nat_acc_lst *lst;
if (!name)
return NULL;
llist_for_each_entry(lst, &nat->access_lists, list)
if (strcmp(lst->name, name) == 0)
return lst;
return NULL;
}
struct bsc_nat_acc_lst *bsc_nat_acc_lst_get(struct bsc_nat *nat, const char *name)
{
struct bsc_nat_acc_lst *lst;
lst = bsc_nat_acc_lst_find(nat, name);
if (lst)
return lst;
lst = talloc_zero(nat, struct bsc_nat_acc_lst);
if (!lst) {
LOGP(DNAT, LOGL_ERROR, "Failed to allocate access list");
return NULL;
}
INIT_LLIST_HEAD(&lst->fltr_list);
lst->name = talloc_strdup(lst, name);
llist_add_tail(&lst->list, &nat->access_lists);
return lst;
}
void bsc_nat_acc_lst_delete(struct bsc_nat_acc_lst *lst)
{
llist_del(&lst->list);
talloc_free(lst);
}
struct bsc_nat_acc_lst_entry *bsc_nat_acc_lst_entry_create(struct bsc_nat_acc_lst *lst)
{
struct bsc_nat_acc_lst_entry *entry;
entry = talloc_zero(lst, struct bsc_nat_acc_lst_entry);
if (!entry)
return NULL;
llist_add_tail(&entry->list, &lst->fltr_list);
return entry;
}

View File

@@ -24,6 +24,7 @@
#include <vty/vty.h>
#include <openbsc/bsc_nat.h>
#include <openbsc/bsc_msc.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/mgcp.h>
#include <openbsc/vty.h>
@@ -48,18 +49,40 @@ static struct cmd_node bsc_node = {
1,
};
static void write_acc_lst(struct vty *vty, struct bsc_nat_acc_lst *lst)
{
struct bsc_nat_acc_lst_entry *entry;
llist_for_each_entry(entry, &lst->fltr_list, list) {
if (entry->imsi_allow)
vty_out(vty, " access-list %s imsi-allow %s%s",
lst->name, entry->imsi_allow, VTY_NEWLINE);
if (entry->imsi_deny)
vty_out(vty, " access-list %s imsi-deny %s%s",
lst->name, entry->imsi_deny, VTY_NEWLINE);
}
}
static int config_write_nat(struct vty *vty)
{
struct bsc_nat_acc_lst *lst;
vty_out(vty, "nat%s", VTY_NEWLINE);
if (_nat->imsi_allow)
vty_out(vty, " imsi allow %s%s", _nat->imsi_allow, VTY_NEWLINE);
if (_nat->imsi_deny)
vty_out(vty, " insi deny %s%s", _nat->imsi_deny, VTY_NEWLINE);
vty_out(vty, " msc ip %s%s", _nat->msc_ip, VTY_NEWLINE);
vty_out(vty, " msc port %d%s", _nat->msc_port, VTY_NEWLINE);
vty_out(vty, " timeout auth %d%s", _nat->auth_timeout, VTY_NEWLINE);
vty_out(vty, " timeout ping %d%s", _nat->ping_timeout, VTY_NEWLINE);
vty_out(vty, " timeout pong %d%s", _nat->pong_timeout, VTY_NEWLINE);
if (_nat->token)
vty_out(vty, " token %s%s", _nat->token, VTY_NEWLINE);
vty_out(vty, " ip-tos %d%s", _nat->bsc_ip_tos, VTY_NEWLINE);
if (_nat->acc_lst_name)
vty_out(vty, " access-list-name %s%s", _nat->acc_lst_name, VTY_NEWLINE);
llist_for_each_entry(lst, &_nat->access_lists, list) {
write_acc_lst(vty, lst);
}
return CMD_SUCCESS;
}
@@ -68,11 +91,11 @@ static void config_write_bsc_single(struct vty *vty, struct bsc_config *bsc)
vty_out(vty, " bsc %u%s", bsc->nr, VTY_NEWLINE);
vty_out(vty, " token %s%s", bsc->token, VTY_NEWLINE);
vty_out(vty, " location_area_code %u%s", bsc->lac, VTY_NEWLINE);
if (bsc->imsi_allow)
vty_out(vty, " imsi allow %s%s", bsc->imsi_allow, VTY_NEWLINE);
if (bsc->imsi_deny)
vty_out(vty, " imsi deny %s%s", bsc->imsi_deny, VTY_NEWLINE);
vty_out(vty, " paging forbidden %d%s", bsc->forbid_paging, VTY_NEWLINE);
if (bsc->description)
vty_out(vty, " description %s%s", bsc->description, VTY_NEWLINE);
if (bsc->acc_lst_name)
vty_out(vty, " access-list-name %s%s", bsc->acc_lst_name, VTY_NEWLINE);
}
static int config_write_bsc(struct vty *vty)
@@ -92,7 +115,7 @@ DEFUN(show_sccp, show_sccp_cmd, "show sccp connections",
vty_out(vty, "Listing all opening SCCP connections%s", VTY_NEWLINE);
llist_for_each_entry(con, &_nat->sccp_connections, list_entry) {
vty_out(vty, "For BSC Nr: %d lac: %d; BSC ref: 0x%x; MUX ref: 0x%x; Network has ref: %d ref: 0x%x MSC/BSC mux: 0x%x/0x%x%s",
vty_out(vty, "For BSC Nr: %d lac: %d; BSC ref: 0x%x; MUX ref: 0x%x; Network has ref: %d ref: 0x%x MSC/BSC mux: 0x%x/0x%x type: %s%s",
con->bsc->cfg ? con->bsc->cfg->nr : -1,
con->bsc->cfg ? con->bsc->cfg->lac : -1,
sccp_src_ref_to_int(&con->real_ref),
@@ -100,6 +123,7 @@ DEFUN(show_sccp, show_sccp_cmd, "show sccp connections",
con->has_remote_ref,
sccp_src_ref_to_int(&con->remote_ref),
con->msc_timeslot, con->bsc_timeslot,
bsc_con_type_to_string(con->con_type),
VTY_NEWLINE);
}
@@ -132,12 +156,16 @@ DEFUN(show_bsc_cfg, show_bsc_cfg_cmd, "show bsc config",
llist_for_each_entry(conf, &_nat->bsc_configs, entry) {
vty_out(vty, "BSC token: '%s' lac: %u nr: %u%s",
conf->token, conf->lac, conf->nr, VTY_NEWLINE);
vty_out(vty, " imsi_allow: '%s' imsi_deny: '%s'%s",
conf->imsi_allow ? conf->imsi_allow: "any",
conf->imsi_deny ? conf->imsi_deny : "none",
VTY_NEWLINE);
if (conf->acc_lst_name)
vty_out(vty, " access-list: %s%s",
conf->acc_lst_name, VTY_NEWLINE);
vty_out(vty, " paging forbidden: %d%s",
conf->forbid_paging, VTY_NEWLINE);
if (conf->description)
vty_out(vty, " description: %s%s", conf->description, VTY_NEWLINE);
else
vty_out(vty, " No description.%s", VTY_NEWLINE);
}
return CMD_SUCCESS;
@@ -181,6 +209,22 @@ DEFUN(show_stats,
return CMD_SUCCESS;
}
DEFUN(show_msc,
show_msc_cmd,
"show msc connection",
SHOW_STR "Show the status of the MSC connection.")
{
if (!_nat->msc_con) {
vty_out(vty, "The MSC is not yet configured.\n");
return CMD_WARNING;
}
vty_out(vty, "MSC on %s:%d is connected: %d%s\n",
_nat->msc_con->ip, _nat->msc_con->port,
_nat->msc_con->is_connected, VTY_NEWLINE);
return CMD_SUCCESS;
}
DEFUN(close_bsc,
close_bsc_cmd,
"close bsc connection BSC_NR",
@@ -207,43 +251,9 @@ DEFUN(cfg_nat, cfg_nat_cmd, "nat", "Configute the NAT")
return CMD_SUCCESS;
}
static void parse_reg(void *ctx, regex_t *reg, char **imsi, int argc, const char **argv)
{
if (*imsi) {
talloc_free(*imsi);
*imsi = NULL;
}
regfree(reg);
if (argc > 0) {
*imsi = talloc_strdup(ctx, argv[0]);
regcomp(reg, argv[0], 0);
}
}
DEFUN(cfg_nat_imsi_allow,
cfg_nat_imsi_allow_cmd,
"imsi allow [REGEXP]",
"Allow matching IMSIs to talk to the MSC. "
"The defualt is to allow everyone.")
{
parse_reg(_nat, &_nat->imsi_allow_re, &_nat->imsi_allow, argc, argv);
return CMD_SUCCESS;
}
DEFUN(cfg_nat_imsi_deny,
cfg_nat_imsi_deny_cmd,
"imsi deny [REGEXP]",
"Deny matching IMSIs to talk to the MSC. "
"The defualt is to not deny.")
{
parse_reg(_nat, &_nat->imsi_deny_re, &_nat->imsi_deny, argc, argv);
return CMD_SUCCESS;
}
DEFUN(cfg_nat_msc_ip,
cfg_nat_msc_ip_cmd,
"msc ip IP",
"msc ip A.B.C.D",
"Set the IP address of the MSC.")
{
bsc_nat_set_msc_ip(_nat, argv[0]);
@@ -286,6 +296,36 @@ DEFUN(cfg_nat_pong_time,
return CMD_SUCCESS;
}
DEFUN(cfg_nat_token, cfg_nat_token_cmd,
"token TOKEN",
"Set a token for the NAT")
{
if (_nat->token)
talloc_free(_nat->token);
_nat->token = talloc_strdup(_nat, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_nat_bsc_ip_tos, cfg_nat_bsc_ip_tos_cmd,
"ip-tos <0-255>",
"Set the IP_TOS for the BSCs to use\n" "Set the IP_TOS attribute")
{
_nat->bsc_ip_tos = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_nat_acc_lst_name,
cfg_nat_acc_lst_name_cmd,
"access-list-name NAME",
"Set the name of the access list to use.\n"
"The name of the to be used access list.")
{
if (_nat->acc_lst_name)
talloc_free(_nat->acc_lst_name);
_nat->acc_lst_name = talloc_strdup(_nat, argv[0]);
return CMD_SUCCESS;
}
/* per BSC configuration */
DEFUN(cfg_bsc, cfg_bsc_cmd, "bsc BSC_NR", "Select a BSC to configure")
{
@@ -329,12 +369,6 @@ DEFUN(cfg_bsc_lac, cfg_bsc_lac_cmd, "location_area_code <0-65535>",
int lac = atoi(argv[0]);
if (lac < 0 || lac > 0xffff) {
vty_out(vty, "%% LAC %d is not in the valid range (0-65535)%s",
lac, VTY_NEWLINE);
return CMD_WARNING;
}
if (lac == GSM_LAC_RESERVED_DETACHED || lac == GSM_LAC_RESERVED_ALL_BTS) {
vty_out(vty, "%% LAC %d is reserved by GSM 04.08%s",
lac, VTY_NEWLINE);
@@ -354,27 +388,77 @@ DEFUN(cfg_bsc_lac, cfg_bsc_lac_cmd, "location_area_code <0-65535>",
return CMD_SUCCESS;
}
DEFUN(cfg_bsc_imsi_allow,
cfg_bsc_imsi_allow_cmd,
"imsi allow [REGEXP]",
"Allow IMSIs with the following network to talk to the MSC."
"The default is to allow everyone)")
DEFUN(cfg_lst_imsi_allow,
cfg_lst_imsi_allow_cmd,
"access-list NAME imsi-allow [REGEXP]",
"Allow IMSIs matching the REGEXP\n"
"The name of the access-list\n"
"The regexp of allowed IMSIs\n")
{
struct bsc_config *conf = vty->index;
struct bsc_nat_acc_lst *acc;
struct bsc_nat_acc_lst_entry *entry;
parse_reg(conf, &conf->imsi_allow_re, &conf->imsi_allow, argc, argv);
acc = bsc_nat_acc_lst_get(_nat, argv[0]);
if (!acc)
return CMD_WARNING;
entry = bsc_nat_acc_lst_entry_create(acc);
if (!entry)
return CMD_WARNING;
bsc_parse_reg(acc, &entry->imsi_allow_re, &entry->imsi_allow, argc - 1, &argv[1]);
return CMD_SUCCESS;
}
DEFUN(cfg_bsc_imsi_deny,
cfg_bsc_imsi_deny_cmd,
"imsi deny [REGEXP]",
"Deny IMSIs with the following network to talk to the MSC."
"The default is to not deny anyone.)")
DEFUN(cfg_lst_imsi_deny,
cfg_lst_imsi_deny_cmd,
"access-list NAME imsi-deny [REGEXP]",
"Allow IMSIs matching the REGEXP\n"
"The name of the access-list\n"
"The regexp of to be denied IMSIs\n")
{
struct bsc_nat_acc_lst *acc;
struct bsc_nat_acc_lst_entry *entry;
acc = bsc_nat_acc_lst_get(_nat, argv[0]);
if (!acc)
return CMD_WARNING;
entry = bsc_nat_acc_lst_entry_create(acc);
if (!entry)
return CMD_WARNING;
bsc_parse_reg(acc, &entry->imsi_deny_re, &entry->imsi_deny, argc - 1, &argv[1]);
return CMD_SUCCESS;
}
/* naming to follow Zebra... */
DEFUN(cfg_lst_no,
cfg_lst_no_cmd,
"no access-list NAME",
NO_STR "Remove an access-list by name\n"
"The access-list to remove\n")
{
struct bsc_nat_acc_lst *acc;
acc = bsc_nat_acc_lst_find(_nat, argv[0]);
if (!acc)
return CMD_WARNING;
bsc_nat_acc_lst_delete(acc);
return CMD_SUCCESS;
}
DEFUN(cfg_bsc_acc_lst_name,
cfg_bsc_acc_lst_name_cmd,
"access-list-name NAME",
"Set the name of the access list to use.\n"
"The name of the to be used access list.")
{
struct bsc_config *conf = vty->index;
parse_reg(conf, &conf->imsi_deny_re, &conf->imsi_deny, argc, argv);
if (conf->acc_lst_name)
talloc_free(conf->acc_lst_name);
conf->acc_lst_name = talloc_strdup(conf, argv[0]);
return CMD_SUCCESS;
}
@@ -393,6 +477,37 @@ DEFUN(cfg_bsc_paging,
return CMD_SUCCESS;
}
DEFUN(cfg_bsc_desc,
cfg_bsc_desc_cmd,
"description DESC",
"Provide a description for the given BSC.")
{
struct bsc_config *conf = vty->index;
if (conf->description)
talloc_free(conf->description);
conf->description = talloc_strdup(conf, argv[0]);
return CMD_SUCCESS;
}
DEFUN(test_regex, test_regex_cmd,
"test regex PATTERN STRING",
"Check if the string is matching the current pattern.")
{
regex_t reg;
char *str = NULL;
memset(&reg, 0, sizeof(reg));
bsc_parse_reg(_nat, &reg, &str, 1, argv);
vty_out(vty, "String matches allow pattern: %d%s",
regexec(&reg, argv[1], 0, NULL, 0) == 0, VTY_NEWLINE);
talloc_free(str);
regfree(&reg);
return CMD_SUCCESS;
}
int bsc_nat_vty_init(struct bsc_nat *nat)
{
_nat = nat;
@@ -406,6 +521,8 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
install_element(VIEW_NODE, &show_bsc_cfg_cmd);
install_element(VIEW_NODE, &show_stats_cmd);
install_element(VIEW_NODE, &close_bsc_cmd);
install_element(VIEW_NODE, &show_msc_cmd);
install_element(VIEW_NODE, &test_regex_cmd);
openbsc_vty_add_cmds();
@@ -413,13 +530,19 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
install_element(CONFIG_NODE, &cfg_nat_cmd);
install_node(&nat_node, config_write_nat);
install_default(NAT_NODE);
install_element(NAT_NODE, &cfg_nat_imsi_allow_cmd);
install_element(NAT_NODE, &cfg_nat_imsi_deny_cmd);
install_element(NAT_NODE, &cfg_nat_msc_ip_cmd);
install_element(NAT_NODE, &cfg_nat_msc_port_cmd);
install_element(NAT_NODE, &cfg_nat_auth_time_cmd);
install_element(NAT_NODE, &cfg_nat_ping_time_cmd);
install_element(NAT_NODE, &cfg_nat_pong_time_cmd);
install_element(NAT_NODE, &cfg_nat_token_cmd);
install_element(NAT_NODE, &cfg_nat_bsc_ip_tos_cmd);
install_element(NAT_NODE, &cfg_nat_acc_lst_name_cmd);
/* access-list */
install_element(NAT_NODE, &cfg_lst_imsi_allow_cmd);
install_element(NAT_NODE, &cfg_lst_imsi_deny_cmd);
install_element(NAT_NODE, &cfg_lst_no_cmd);
/* BSC subgroups */
install_element(NAT_NODE, &cfg_bsc_cmd);
@@ -427,9 +550,9 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
install_default(BSC_NODE);
install_element(BSC_NODE, &cfg_bsc_token_cmd);
install_element(BSC_NODE, &cfg_bsc_lac_cmd);
install_element(BSC_NODE, &cfg_bsc_imsi_allow_cmd);
install_element(BSC_NODE, &cfg_bsc_imsi_deny_cmd);
install_element(BSC_NODE, &cfg_bsc_paging_cmd);
install_element(BSC_NODE, &cfg_bsc_desc_cmd);
install_element(BSC_NODE, &cfg_bsc_acc_lst_name_cmd);
mgcp_vty_init();

View File

@@ -28,6 +28,7 @@
#include <osmocore/talloc.h>
#include <string.h>
#include <time.h>
static int equal(struct sccp_source_reference *ref1, struct sccp_source_reference *ref2)
{
@@ -81,7 +82,8 @@ static int assign_src_local_reference(struct sccp_source_reference *ref, struct
return -1;
}
int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed)
struct sccp_connections *create_sccp_src_ref(struct bsc_connection *bsc,
struct bsc_nat_parsed *parsed)
{
struct sccp_connections *conn;
@@ -97,12 +99,14 @@ int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc
if (assign_src_local_reference(&conn->patched_ref, bsc->nat) != 0) {
LOGP(DNAT, LOGL_ERROR, "BSC %d reused src ref: %d and we failed to generate a new id.\n",
bsc->cfg->nr, sccp_src_ref_to_int(parsed->src_local_ref));
bsc_mgcp_dlcx(conn);
llist_del(&conn->list_entry);
talloc_free(conn);
return -1;
return NULL;
} else {
clock_gettime(CLOCK_MONOTONIC, &conn->creation_time);
bsc_mgcp_dlcx(conn);
return 0;
return conn;
}
}
@@ -110,15 +114,16 @@ int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc
conn = talloc_zero(bsc->nat, struct sccp_connections);
if (!conn) {
LOGP(DNAT, LOGL_ERROR, "Memory allocation failure.\n");
return -1;
return NULL;
}
conn->bsc = bsc;
clock_gettime(CLOCK_MONOTONIC, &conn->creation_time);
conn->real_ref = *parsed->src_local_ref;
if (assign_src_local_reference(&conn->patched_ref, bsc->nat) != 0) {
LOGP(DNAT, LOGL_ERROR, "Failed to assign a ref.\n");
talloc_free(conn);
return -1;
return NULL;
}
bsc_mgcp_init(conn);
@@ -130,7 +135,7 @@ int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc
sccp_src_ref_to_int(&conn->real_ref),
sccp_src_ref_to_int(&conn->patched_ref), bsc);
return 0;
return conn;
}
int update_sccp_src_ref(struct sccp_connections *sccp, struct bsc_nat_parsed *parsed)

View File

@@ -381,7 +381,7 @@ void paging_request_stop(struct gsm_bts *_bts, struct gsm_subscriber *subscr,
break;
/* Stop paging */
if (bts != _bts)
if (bts != _bts)
_paging_request_stop(bts, subscr, NULL);
} while (1);
}

View File

@@ -316,8 +316,16 @@ static int append_gprs_cell_opt(struct bitvec *bv,
bitvec_set_bit(bv, 1);
bitvec_set_uint(bv, gco->bs_cv_max, 4);
/* hard-code no PAN_{DEC,INC,MAX} */
bitvec_set_bit(bv, 0);
if (0) {
/* hard-code no PAN_{DEC,INC,MAX} */
bitvec_set_bit(bv, 0);
} else {
/* copied from ip.access BSC protocol trace */
bitvec_set_bit(bv, 1);
bitvec_set_uint(bv, 1, 3); /* DEC */
bitvec_set_uint(bv, 1, 3); /* INC */
bitvec_set_uint(bv, 15, 3); /* MAX */
}
if (!gco->ext_info_present) {
/* no extension information */

View File

@@ -638,7 +638,7 @@ static void _sccp_set_connection_state(struct sccp_connection *connection, int n
connection->state_cb(connection, old_state);
}
static int _sccp_send_refuse(struct sccp_source_reference *src_ref, int cause)
struct msgb *sccp_create_refuse(struct sccp_source_reference *src_ref, int cause, uint8_t *inp, int length)
{
struct msgb *msgb;
struct sccp_connection_refused *ref;
@@ -646,6 +646,11 @@ static int _sccp_send_refuse(struct sccp_source_reference *src_ref, int cause)
msgb = msgb_alloc_headroom(SCCP_MSG_SIZE,
SCCP_MSG_HEADROOM, "sccp ref");
if (!msgb) {
LOGP(DSCCP, LOGL_ERROR, "Failed to allocate refusal msg.\n");
return NULL;
}
msgb->l2h = &msgb->data[0];
ref = (struct sccp_connection_refused *) msgb_put(msgb, sizeof(*ref));
@@ -655,40 +660,70 @@ static int _sccp_send_refuse(struct sccp_source_reference *src_ref, int cause)
ref->cause = cause;
ref->optional_start = 1;
if (inp) {
data = msgb_put(msgb, 1 + 1 + length);
data[0] = SCCP_PNC_DATA;
data[1] = length;
memcpy(&data[2], inp, length);
}
data = msgb_put(msgb, 1);
data[0] = SCCP_PNC_END_OF_OPTIONAL;
return msgb;
}
static int _sccp_send_refuse(struct sccp_source_reference *src_ref, int cause)
{
struct msgb *msgb = sccp_create_refuse(src_ref, cause, NULL, 0);
if (!msgb)
return -1;
_send_msg(msgb);
return 0;
}
static int _sccp_send_connection_confirm(struct sccp_connection *connection)
struct msgb *sccp_create_cc(struct sccp_source_reference *src_ref,
struct sccp_source_reference *dst_ref)
{
struct msgb *response;
struct sccp_connection_confirm *confirm;
u_int8_t *optional_data;
if (assign_source_local_reference(connection) != 0)
return -1;
response = msgb_alloc_headroom(SCCP_MSG_SIZE,
SCCP_MSG_HEADROOM, "sccp confirm");
if (!response) {
LOGP(DSCCP, LOGL_ERROR, "Failed to create SCCP Confirm.\n");
return NULL;
}
response->l2h = &response->data[0];
confirm = (struct sccp_connection_confirm *) msgb_put(response, sizeof(*confirm));
confirm->type = SCCP_MSG_TYPE_CC;
memcpy(&confirm->destination_local_reference,
&connection->destination_local_reference,
sizeof(connection->destination_local_reference));
dst_ref, sizeof(*dst_ref));
memcpy(&confirm->source_local_reference,
&connection->source_local_reference,
sizeof(connection->source_local_reference));
src_ref, sizeof(*src_ref));
confirm->proto_class = 2;
confirm->optional_start = 1;
optional_data = (u_int8_t *) msgb_put(response, 1);
optional_data[0] = SCCP_PNC_END_OF_OPTIONAL;
return response;
}
static int _sccp_send_connection_confirm(struct sccp_connection *connection)
{
struct msgb *response;
if (assign_source_local_reference(connection) != 0)
return -1;
response = sccp_create_cc(&connection->source_local_reference,
&connection->destination_local_reference);
if (!response)
return -1;
_send_msg(response);
_sccp_set_connection_state(connection, SCCP_CONNECTION_STATE_ESTABLISHED);
@@ -755,34 +790,49 @@ static int _sccp_send_connection_request(struct sccp_connection *connection,
return 0;
}
static int _sccp_send_connection_data(struct sccp_connection *conn, struct msgb *_data)
struct msgb *sccp_create_dt1(struct sccp_source_reference *dst_ref, uint8_t *inp_data, uint8_t len)
{
struct msgb *msgb;
struct sccp_data_form1 *dt1;
u_int8_t *data;
int extra_size;
msgb = msgb_alloc_headroom(SCCP_MSG_SIZE,
SCCP_MSG_HEADROOM, "sccp dt1");
if (!msgb) {
LOGP(DSCCP, LOGL_ERROR, "Failed to create DT1 msg.\n");
return NULL;
}
msgb->l2h = &msgb->data[0];
dt1 = (struct sccp_data_form1 *) msgb_put(msgb, sizeof(*dt1));
dt1->type = SCCP_MSG_TYPE_DT1;
memcpy(&dt1->destination_local_reference, dst_ref,
sizeof(struct sccp_source_reference));
dt1->segmenting = 0;
/* copy the data */
dt1->variable_start = 1;
data = msgb_put(msgb, 1 + len);
data[0] = len;
memcpy(&data[1], inp_data, len);
return msgb;
}
static int _sccp_send_connection_data(struct sccp_connection *conn, struct msgb *_data)
{
struct msgb *msgb;
if (msgb_l3len(_data) < 2 || msgb_l3len(_data) > 256) {
LOGP(DSCCP, LOGL_ERROR, "data size too big, segmenting unimplemented.\n");
return -1;
}
extra_size = 1 + msgb_l3len(_data);
msgb = msgb_alloc_headroom(SCCP_MSG_SIZE,
SCCP_MSG_HEADROOM, "sccp dt1");
msgb->l2h = &msgb->data[0];
dt1 = (struct sccp_data_form1 *) msgb_put(msgb, sizeof(*dt1));
dt1->type = SCCP_MSG_TYPE_DT1;
memcpy(&dt1->destination_local_reference, &conn->destination_local_reference,
sizeof(struct sccp_source_reference));
dt1->segmenting = 0;
/* copy the data */
dt1->variable_start = 1;
data = msgb_put(msgb, extra_size);
data[0] = extra_size - 1;
memcpy(&data[1], _data->l3h, extra_size - 1);
msgb = sccp_create_dt1(&conn->destination_local_reference,
_data->l3h, msgb_l3len(_data));
if (!msgb)
return -1;
_send_msg(msgb);
return 0;
@@ -811,7 +861,8 @@ static int _sccp_send_connection_it(struct sccp_connection *conn)
return 0;
}
static int _sccp_send_connection_released(struct sccp_connection *conn, int cause)
struct msgb *sccp_create_rlsd(struct sccp_source_reference *src_ref,
struct sccp_source_reference *dst_ref, int cause)
{
struct msgb *msg;
struct sccp_connection_released *rel;
@@ -819,19 +870,36 @@ static int _sccp_send_connection_released(struct sccp_connection *conn, int caus
msg = msgb_alloc_headroom(SCCP_MSG_SIZE, SCCP_MSG_HEADROOM,
"sccp: connection released");
if (!msg) {
LOGP(DSCCP, LOGL_ERROR, "Failed to allocate RLSD.\n");
return NULL;
}
msg->l2h = &msg->data[0];
rel = (struct sccp_connection_released *) msgb_put(msg, sizeof(*rel));
rel->type = SCCP_MSG_TYPE_RLSD;
rel->release_cause = cause;
/* copy the source references */
memcpy(&rel->destination_local_reference, &conn->destination_local_reference,
memcpy(&rel->destination_local_reference, dst_ref,
sizeof(struct sccp_source_reference));
memcpy(&rel->source_local_reference, &conn->source_local_reference,
memcpy(&rel->source_local_reference, src_ref,
sizeof(struct sccp_source_reference));
data = msgb_put(msg, 1);
data[0] = SCCP_PNC_END_OF_OPTIONAL;
return msg;
}
static int _sccp_send_connection_released(struct sccp_connection *conn, int cause)
{
struct msgb *msg;
msg = sccp_create_rlsd(&conn->source_local_reference,
&conn->destination_local_reference,
cause);
if (!msg)
return -1;
_sccp_set_connection_state(conn, SCCP_CONNECTION_STATE_RELEASE);
_send_msg(msg);

View File

@@ -397,17 +397,17 @@ static int generate_si6(u_int8_t *output, struct gsm_bts *bts)
static struct gsm48_si13_info si13_default = {
.cell_opts = {
.nmo = GPRS_NMO_III,
.t3168 = 1500,
.t3192 = 500,
.nmo = GPRS_NMO_II,
.t3168 = 2000,
.t3192 = 200,
.drx_timer_max = 3,
.bs_cv_max = 15,
.ext_info_present = 0,
.ext_info_present = 1,
.ext_info = {
/* The values below are just guesses ! */
.egprs_supported = 0,
.use_egprs_p_ch_req = 1,
.bep_period = 4,
.bep_period = 5,
.pfc_supported = 0,
.dtm_supported = 0,
.bss_paging_coordination = 0,
@@ -415,10 +415,10 @@ static struct gsm48_si13_info si13_default = {
},
.pwr_ctrl_pars = {
.alpha = 10, /* a = 1.0 */
.t_avg_w = 25,
.t_avg_t = 25,
.t_avg_w = 16,
.t_avg_t = 16,
.pc_meas_chan = 0, /* downling measured on CCCH */
.n_avg_i = 15,
.n_avg_i = 8,
},
.bcch_change_mark = 1,
.si_change_field = 0,

View File

@@ -27,6 +27,7 @@
#include <vty/vty.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <osmocore/linuxlist.h>
#include <openbsc/gsm_data.h>
@@ -44,6 +45,32 @@
static struct gsm_network *gsmnet;
static struct value_string gprs_ns_timer_strs[] = {
{ 0, "tns-block" },
{ 1, "tns-block-retries" },
{ 2, "tns-reset" },
{ 3, "tns-reset-retries" },
{ 4, "tns-test" },
{ 5, "tns-alive" },
{ 6, "tns-alive-retries" },
{ 0, NULL }
};
static struct value_string gprs_bssgp_cfg_strs[] = {
{ 0, "blocking-timer" },
{ 1, "blocking-retries" },
{ 2, "unblocking-retries" },
{ 3, "reset-timer" },
{ 4, "reset-retries" },
{ 5, "suspend-timer" },
{ 6, "suspend-retries" },
{ 7, "resume-timer" },
{ 8, "resume-retries" },
{ 9, "capability-update-timer" },
{ 10, "capability-update-retries" },
{ 0, NULL }
};
struct cmd_node net_node = {
GSMNET_NODE,
"%s(network)#",
@@ -321,10 +348,48 @@ static void config_write_trx_single(struct vty *vty, struct gsm_bts_trx *trx)
config_write_ts_single(vty, &trx->ts[i]);
}
static void config_write_bts_gprs(struct vty *vty, struct gsm_bts *bts)
{
unsigned int i;
vty_out(vty, " gprs mode %s%s", bts_gprs_mode_name(bts->gprs.mode),
VTY_NEWLINE);
if (bts->gprs.mode == BTS_GPRS_NONE)
return;
vty_out(vty, " gprs routing area %u%s", bts->gprs.rac,
VTY_NEWLINE);
vty_out(vty, " gprs cell bvci %u%s", bts->gprs.cell.bvci,
VTY_NEWLINE);
for (i = 0; i < ARRAY_SIZE(bts->gprs.cell.timer); i++)
vty_out(vty, " gprs cell timer %s %u%s",
get_value_string(gprs_bssgp_cfg_strs, i),
bts->gprs.cell.timer[i], VTY_NEWLINE);
vty_out(vty, " gprs nsei %u%s", bts->gprs.nse.nsei,
VTY_NEWLINE);
for (i = 0; i < ARRAY_SIZE(bts->gprs.nse.timer); i++)
vty_out(vty, " gprs ns timer %s %u%s",
get_value_string(gprs_ns_timer_strs, i),
bts->gprs.nse.timer[i], VTY_NEWLINE);
for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) {
struct gsm_bts_gprs_nsvc *nsvc =
&bts->gprs.nsvc[i];
struct in_addr ia;
ia.s_addr = htonl(nsvc->remote_ip);
vty_out(vty, " gprs nsvc %u nsvci %u%s", i,
nsvc->nsvci, VTY_NEWLINE);
vty_out(vty, " gprs nsvc %u local udp port %u%s", i,
nsvc->local_port, VTY_NEWLINE);
vty_out(vty, " gprs nsvc %u remote udp port %u%s", i,
nsvc->remote_port, VTY_NEWLINE);
vty_out(vty, " gprs nsvc %u remote ip %s%s", i,
inet_ntoa(ia), VTY_NEWLINE);
}
}
static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
{
struct gsm_bts_trx *trx;
int i;
vty_out(vty, " bts %u%s", bts->nr, VTY_NEWLINE);
vty_out(vty, " type %s%s", btstype2str(bts->type), VTY_NEWLINE);
@@ -359,6 +424,8 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
bts->rach_ldavg_slots, VTY_NEWLINE);
if (bts->si_common.rach_control.cell_bar)
vty_out(vty, " cell barred 1%s", VTY_NEWLINE);
if ((bts->si_common.rach_control.t2 & 0x4) == 0)
vty_out(vty, " rach emergency call allowed 1%s", VTY_NEWLINE);
if (is_ipaccess_bts(bts)) {
vty_out(vty, " ip.access unit_id %u %u%s",
bts->ip_access.site_id, bts->ip_access.bts_id, VTY_NEWLINE);
@@ -368,35 +435,12 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
vty_out(vty, " oml e1 tei %u%s", bts->oml_tei, VTY_NEWLINE);
}
config_write_bts_gprs(vty, bts);
/* if we have a limit, write it */
if (bts->paging.free_chans_need >= 0)
vty_out(vty, " paging free %d%s", bts->paging.free_chans_need, VTY_NEWLINE);
vty_out(vty, " gprs mode %s%s", bts_gprs_mode_name(bts->gprs.mode),
VTY_NEWLINE);
if (bts->gprs.mode != BTS_GPRS_NONE) {
vty_out(vty, " gprs routing area %u%s", bts->gprs.rac,
VTY_NEWLINE);
vty_out(vty, " gprs cell bvci %u%s", bts->gprs.cell.bvci,
VTY_NEWLINE);
vty_out(vty, " gprs nsei %u%s", bts->gprs.nse.nsei,
VTY_NEWLINE);
for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) {
struct gsm_bts_gprs_nsvc *nsvc =
&bts->gprs.nsvc[i];
struct in_addr ia;
ia.s_addr = htonl(nsvc->remote_ip);
vty_out(vty, " gprs nsvc %u nsvci %u%s", i,
nsvc->nsvci, VTY_NEWLINE);
vty_out(vty, " gprs nsvc %u local udp port %u%s", i,
nsvc->local_port, VTY_NEWLINE);
vty_out(vty, " gprs nsvc %u remote udp port %u%s", i,
nsvc->remote_port, VTY_NEWLINE);
vty_out(vty, " gprs nsvc %u remote ip %s%s", i,
inet_ntoa(ia), VTY_NEWLINE);
}
}
llist_for_each_entry(trx, &bts->trx_list, list)
config_write_trx_single(vty, trx);
@@ -480,6 +524,7 @@ static int config_write_net(struct vty *vty)
vty_out(vty, " bsc_token %s%s", gsmnet->bsc_token, VTY_NEWLINE);
vty_out(vty, " msc ip %s%s", gsmnet->msc_ip, VTY_NEWLINE);
vty_out(vty, " msc port %d%s", gsmnet->msc_port, VTY_NEWLINE);
vty_out(vty, " msc ip-tos %d%s", gsmnet->msc_prio, VTY_NEWLINE);
vty_out(vty, " timeout ping %d%s", gsmnet->ping_timeout, VTY_NEWLINE);
vty_out(vty, " timeout pong %d%s", gsmnet->pong_timeout, VTY_NEWLINE);
@@ -679,7 +724,7 @@ static void meas_rep_dump_vty(struct vty *vty, struct gsm_meas_rep *mr,
meas_rep_dump_uni_vty(vty, &mr->ul, prefix, "ul");
}
static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan)
static void lchan_dump_full_vty(struct vty *vty, struct gsm_lchan *lchan)
{
int idx;
@@ -714,37 +759,28 @@ static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan)
meas_rep_dump_vty(vty, &lchan->meas_rep[idx], " ");
}
#if 0
TODO: callref and remote callref of call must be resolved to get gsm_trans object
static void call_dump_vty(struct vty *vty, struct gsm_call *call)
static void lchan_dump_short_vty(struct vty *vty, struct gsm_lchan *lchan)
{
vty_out(vty, "Call Type %u, State %u, Transaction ID %u%s",
call->type, call->state, call->transaction_id, VTY_NEWLINE);
struct gsm_meas_rep *mr;
int idx;
if (call->local_lchan) {
vty_out(vty, "Call Local Channel:%s", VTY_NEWLINE);
lchan_dump_vty(vty, call->local_lchan);
} else
vty_out(vty, "Call has no Local Channel%s", VTY_NEWLINE);
/* we want to report the last measurement report */
idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep),
lchan->meas_rep_idx, 1);
mr = &lchan->meas_rep[idx];
if (call->remote_lchan) {
vty_out(vty, "Call Remote Channel:%s", VTY_NEWLINE);
lchan_dump_vty(vty, call->remote_lchan);
} else
vty_out(vty, "Call has no Remote Channel%s", VTY_NEWLINE);
if (call->called_subscr) {
vty_out(vty, "Called Subscriber:%s", VTY_NEWLINE);
subscr_dump_vty(vty, call->called_subscr);
} else
vty_out(vty, "Call has no Called Subscriber%s", VTY_NEWLINE);
vty_out(vty, "Lchan: %u Timeslot: %u TRX: %u BTS: %u Type: %s - L1 MS Power: %u dBm "
"RXL-FULL-dl: %4d dBm RXL-FULL-ul: %4d dBm%s",
lchan->nr, lchan->ts->nr, lchan->ts->trx->nr,
lchan->ts->trx->bts->nr, gsm_lchant_name(lchan->type),
mr->ms_l1.pwr,
rxlev2dbm(mr->dl.full.rx_lev),
rxlev2dbm(mr->ul.full.rx_lev),
VTY_NEWLINE);
}
#endif
DEFUN(show_lchan,
show_lchan_cmd,
"show lchan [bts_nr] [trx_nr] [ts_nr] [lchan_nr]",
SHOW_STR "Display information about a logical channel\n")
static int lchan_summary(struct vty *vty, int argc, const char **argv,
void (*dump_cb)(struct vty *, struct gsm_lchan *))
{
struct gsm_network *net = gsmnet;
struct gsm_bts *bts;
@@ -789,7 +825,7 @@ DEFUN(show_lchan,
return CMD_WARNING;
}
lchan = &ts->lchan[lchan_nr];
lchan_dump_vty(vty, lchan);
dump_cb(vty, lchan);
return CMD_SUCCESS;
}
for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
@@ -803,7 +839,7 @@ DEFUN(show_lchan,
lchan = &ts->lchan[lchan_nr];
if (lchan->type == GSM_LCHAN_NONE)
continue;
lchan_dump_vty(vty, lchan);
dump_cb(vty, lchan);
}
}
}
@@ -812,6 +848,23 @@ DEFUN(show_lchan,
return CMD_SUCCESS;
}
DEFUN(show_lchan,
show_lchan_cmd,
"show lchan [bts_nr] [trx_nr] [ts_nr] [lchan_nr]",
SHOW_STR "Display information about a logical channel\n")
{
return lchan_summary(vty, argc, argv, lchan_dump_full_vty);
}
DEFUN(show_lchan_summary,
show_lchan_summary_cmd,
"show lchan summary [bts_nr] [trx_nr] [ts_nr] [lchan_nr]",
SHOW_STR "Display a short summary about a logical channel\n")
{
return lchan_summary(vty, argc, argv, lchan_dump_short_vty);
}
static void e1drv_dump_vty(struct vty *vty, struct e1inp_driver *drv)
{
vty_out(vty, "E1 Input Driver %s%s", drv->name, VTY_NEWLINE);
@@ -1319,7 +1372,7 @@ DEFUN(cfg_net_pag_any_tch,
DEFUN(cfg_net_msc_ip,
cfg_net_msc_ip_cmd,
"msc ip IP",
"msc ip A.B.C.D",
"Set the MSC/MUX IP address.")
{
if (gsmnet->msc_ip)
@@ -1337,6 +1390,15 @@ DEFUN(cfg_net_msc_port,
return CMD_SUCCESS;
}
DEFUN(cfg_net_msc_prio,
cfg_net_msc_prio_cmd,
"msc ip-tos <0-255>",
"Set the IP_TOS socket attribite")
{
gsmnet->msc_prio = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_ping_time,
cfg_net_ping_time_cmd,
"timeout ping NR",
@@ -1661,6 +1723,20 @@ DEFUN(cfg_bts_cell_barred, cfg_bts_cell_barred_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_bts_rach_ec_allowed, cfg_bts_rach_ec_allowed_cmd,
"rach emergency call allowed (0|1)",
"Should this cell allow emergency calls?")
{
struct gsm_bts *bts = vty->index;
if (atoi(argv[0]) == 0)
bts->si_common.rach_control.t2 |= 0x4;
else
bts->si_common.rach_control.t2 &= ~0x4;
return CMD_SUCCESS;
}
DEFUN(cfg_bts_ms_max_power, cfg_bts_ms_max_power_cmd,
"ms max power <0-40>",
"Maximum transmit power of the MS")
@@ -1808,13 +1884,61 @@ DEFUN(cfg_bts_gprs_nsvc_rip, cfg_bts_gprs_nsvc_rip_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_bts_pag_free, cfg_bts_pag_free_cmd,
"paging free FREE_NR",
"Only page when having a certain amount of free slots. -1 to disable")
#define GPRS_TEXT "GPRS Packet Network\n"
#define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries)"
#define NS_TIMERS_HELP \
"(un)blocking Timer (Tns-block) timeout\n" \
"(un)blocking Timer (Tns-block) number of retries\n" \
"Reset Timer (Tns-reset) timeout\n" \
"Reset Timer (Tns-reset) number of retries\n" \
"Test Timer (Tns-test) timeout\n" \
DEFUN(cfg_bts_gprs_ns_timer, cfg_bts_gprs_ns_timer_cmd,
"gprs ns timer " NS_TIMERS " <0-255>",
GPRS_TEXT "Network Service\n"
"Network Service Timer\n"
NS_TIMERS_HELP "Timer Value\n")
{
struct gsm_bts *bts = vty->index;
int idx = get_string_value(gprs_ns_timer_strs, argv[0]);
int val = atoi(argv[1]);
if (bts->gprs.mode == BTS_GPRS_NONE) {
vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
return CMD_WARNING;
}
if (idx < 0 || idx >= ARRAY_SIZE(bts->gprs.nse.timer))
return CMD_WARNING;
bts->gprs.nse.timer[idx] = val;
return CMD_SUCCESS;
}
#define BSSGP_TIMERS "(blocking-timer|blocking-retries|unblocking-retries|reset-timer|reset-retries|suspend-timer|suspend-retries|resume-timer|resume-retries|capability-update-timer|capability-update-retries)"
#define BSSGP_TIMERS_HELP ""
DEFUN(cfg_bts_gprs_cell_timer, cfg_bts_gprs_cell_timer_cmd,
"gprs cell timer " BSSGP_TIMERS " <0-255>",
GPRS_TEXT "Cell / BSSGP\n"
"Cell/BSSGP Timer\n"
BSSGP_TIMERS_HELP "Timer Value\n")
{
struct gsm_bts *bts = vty->index;
int idx = get_string_value(gprs_bssgp_cfg_strs, argv[0]);
int val = atoi(argv[1]);
if (bts->gprs.mode == BTS_GPRS_NONE) {
vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
return CMD_WARNING;
}
if (idx < 0 || idx >= ARRAY_SIZE(bts->gprs.cell.timer))
return CMD_WARNING;
bts->gprs.cell.timer[idx] = val;
bts->paging.free_chans_need = atoi(argv[0]);
return CMD_SUCCESS;
}
@@ -1845,6 +1969,15 @@ DEFUN(cfg_bts_gprs_mode, cfg_bts_gprs_mode_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_bts_pag_free, cfg_bts_pag_free_cmd,
"paging free FREE_NR",
"Only page when having a certain amount of free slots. -1 to disable")
{
struct gsm_bts *bts = vty->index;
bts->paging.free_chans_need = atoi(argv[0]);
return CMD_SUCCESS;
}
/* per TRX configuration */
DEFUN(cfg_trx,
@@ -2037,6 +2170,7 @@ int bsc_vty_init(struct gsm_network *net)
install_element(VIEW_NODE, &show_trx_cmd);
install_element(VIEW_NODE, &show_ts_cmd);
install_element(VIEW_NODE, &show_lchan_cmd);
install_element(VIEW_NODE, &show_lchan_summary_cmd);
install_element(VIEW_NODE, &show_e1drv_cmd);
install_element(VIEW_NODE, &show_e1line_cmd);
@@ -2089,6 +2223,7 @@ int bsc_vty_init(struct gsm_network *net)
install_element(GSMNET_NODE, &cfg_net_pag_any_tch_cmd);
install_element(GSMNET_NODE, &cfg_net_msc_ip_cmd);
install_element(GSMNET_NODE, &cfg_net_msc_port_cmd);
install_element(GSMNET_NODE, &cfg_net_msc_prio_cmd);
install_element(GSMNET_NODE, &cfg_net_ping_time_cmd);
install_element(GSMNET_NODE, &cfg_net_pong_time_cmd);
@@ -2111,13 +2246,16 @@ int bsc_vty_init(struct gsm_network *net)
install_element(BTS_NODE, &cfg_bts_rach_nm_b_thresh_cmd);
install_element(BTS_NODE, &cfg_bts_rach_nm_ldavg_cmd);
install_element(BTS_NODE, &cfg_bts_cell_barred_cmd);
install_element(BTS_NODE, &cfg_bts_rach_ec_allowed_cmd);
install_element(BTS_NODE, &cfg_bts_ms_max_power_cmd);
install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd);
install_element(BTS_NODE, &cfg_bts_cell_resel_hyst_cmd);
install_element(BTS_NODE, &cfg_bts_rxlev_acc_min_cmd);
install_element(BTS_NODE, &cfg_bts_gprs_mode_cmd);
install_element(BTS_NODE, &cfg_bts_gprs_ns_timer_cmd);
install_element(BTS_NODE, &cfg_bts_gprs_rac_cmd);
install_element(BTS_NODE, &cfg_bts_gprs_bvci_cmd);
install_element(BTS_NODE, &cfg_bts_gprs_cell_timer_cmd);
install_element(BTS_NODE, &cfg_bts_gprs_nsei_cmd);
install_element(BTS_NODE, &cfg_bts_gprs_nsvci_cmd);
install_element(BTS_NODE, &cfg_bts_gprs_nsvc_lport_cmd);

View File

@@ -27,6 +27,7 @@
#include <vty/vty.h>
#include <openbsc/gsm_data.h>
#include <openbsc/bsc_msc.h>
#include <openbsc/vty.h>
#include <sccp/sccp.h>
@@ -42,7 +43,7 @@ DEFUN(show_bsc, show_bsc_cmd, "show bsc",
vty_out(vty, "BSC Information%s", VTY_NEWLINE);
llist_for_each_entry(con, bsc_sccp_connections(), active_connections) {
vty_out(vty, " Connection: LCHAN: %p sec LCHAN: %p SCCP src: %d dest: %d%s",
vty_out(vty, " Connection: LCHAN: %p sec LCHAN: 0x%p SCCP src: 0x%x dest: 0x%x%s",
con->lchan, con->secondary_lchan,
con->sccp ? (int) sccp_src_ref_to_int(&con->sccp->source_local_reference) : -1,
con->sccp ? (int) sccp_src_ref_to_int(&con->sccp->destination_local_reference) : -1,
@@ -63,6 +64,24 @@ DEFUN(show_stats,
return CMD_SUCCESS;
}
DEFUN(show_msc,
show_msc_cmd,
"show msc connection",
SHOW_STR "Show the status of the MSC connection.")
{
if (!gsmnet->msc_con) {
vty_out(vty, "The MSC is not yet configured.\n");
return CMD_WARNING;
}
vty_out(vty, "MSC on %s:%d is connected: %d%s\n",
gsmnet->msc_con->ip, gsmnet->msc_con->port,
gsmnet->msc_con->is_connected, VTY_NEWLINE);
return CMD_SUCCESS;
}
int bsc_vty_init_extra(struct gsm_network *net)
{
gsmnet = net;
@@ -70,6 +89,7 @@ int bsc_vty_init_extra(struct gsm_network *net)
/* get runtime information */
install_element(VIEW_NODE, &show_bsc_cmd);
install_element(VIEW_NODE, &show_stats_cmd);
install_element(VIEW_NODE, &show_msc_cmd);
return 0;
}

View File

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

View File

@@ -108,6 +108,28 @@ static const u_int8_t mgcp_msg[] = {
0x20, 0x20, 0x20,
};
/* location updating request */
static const u_int8_t bss_lu[] = {
0x00, 0x2e, 0xfd,
0x01, 0x91, 0x45, 0x14, 0x02, 0x02, 0x04, 0x02,
0x42, 0xfe, 0x0f, 0x21, 0x00, 0x1f, 0x57, 0x05,
0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x14, 0xc3,
0x50, 0x17, 0x12, 0x05, 0x08, 0x70, 0x72, 0xf4,
0x80, 0xff, 0xfe, 0x30, 0x08, 0x29, 0x44, 0x50,
0x12, 0x03, 0x24, 0x01, 0x95, 0x00
};
/* paging response */
static const uint8_t pag_resp[] = {
0x00, 0x2c, 0xfd, 0x01, 0xe5, 0x68,
0x14, 0x02, 0x02, 0x04, 0x02, 0x42, 0xfe, 0x0f,
0x1f, 0x00, 0x1d, 0x57, 0x05, 0x08, 0x00, 0x72,
0xf4, 0x80, 0x20, 0x16, 0xc3, 0x50, 0x17, 0x10,
0x06, 0x27, 0x01, 0x03, 0x30, 0x18, 0x96, 0x08,
0x29, 0x26, 0x30, 0x32, 0x11, 0x42, 0x01, 0x19,
0x00
};
struct filter_result {
const u_int8_t *data;
const u_int16_t length;
@@ -251,10 +273,10 @@ static void copy_to_msg(struct msgb *msg, const u_int8_t *data, unsigned int len
/* test conn tracking once */
static void test_contrack()
{
int rc;
struct bsc_nat *nat;
struct bsc_connection *con;
struct sccp_connections *con_found;
struct sccp_connections *rc_con;
struct bsc_nat_parsed *parsed;
struct msgb *msg;
@@ -272,8 +294,8 @@ static void test_contrack()
fprintf(stderr, "Con should not exist %p\n", con_found);
abort();
}
rc = create_sccp_src_ref(con, msg, parsed);
if (rc != 0) {
rc_con = create_sccp_src_ref(con, parsed);
if (!rc_con) {
fprintf(stderr, "Failed to create a ref\n");
abort();
}
@@ -282,6 +304,10 @@ static void test_contrack()
fprintf(stderr, "Failed to find the con: %p\n", con_found);
abort();
}
if (con_found != rc_con) {
fprintf(stderr, "Failed to find the right connection.\n");
abort();
}
if (memcmp(msg->data, bsc_cr_patched, sizeof(bsc_cr_patched)) != 0) {
fprintf(stderr, "Failed to patch the BSC CR msg.\n");
abort();
@@ -540,6 +566,135 @@ static void test_mgcp_parse(void)
}
}
struct cr_filter {
const u_int8_t *data;
int length;
int result;
int contype;
const char *bsc_imsi_allow;
const char *bsc_imsi_deny;
const char *nat_imsi_deny;
};
static struct cr_filter cr_filter[] = {
{
.data = bssmap_cr,
.length = sizeof(bssmap_cr),
.result = 0,
.contype = NAT_CON_TYPE_CM_SERV_REQ,
},
{
.data = bss_lu,
.length = sizeof(bss_lu),
.result = 0,
.contype = NAT_CON_TYPE_LU,
},
{
.data = pag_resp,
.length = sizeof(pag_resp),
.result = 0,
.contype = NAT_CON_TYPE_PAG_RESP,
},
{
/* nat deny is before blank/null BSC */
.data = bss_lu,
.length = sizeof(bss_lu),
.result = -3,
.nat_imsi_deny = "[0-9]*",
.contype = NAT_CON_TYPE_LU,
},
{
/* BSC allow is before NAT deny */
.data = bss_lu,
.length = sizeof(bss_lu),
.result = 0,
.nat_imsi_deny = "[0-9]*",
.bsc_imsi_allow = "2440[0-9]*",
.contype = NAT_CON_TYPE_LU,
},
{
/* BSC allow is before NAT deny */
.data = bss_lu,
.length = sizeof(bss_lu),
.result = 0,
.bsc_imsi_allow = "[0-9]*",
.nat_imsi_deny = "[0-9]*",
.contype = NAT_CON_TYPE_LU,
},
{
/* filter as deny is first */
.data = bss_lu,
.length = sizeof(bss_lu),
.result = -2,
.bsc_imsi_deny = "[0-9]*",
.bsc_imsi_allow = "[0-9]*",
.nat_imsi_deny = "[0-9]*",
.contype = NAT_CON_TYPE_LU,
},
};
static void test_cr_filter()
{
int i, res, contype;
struct msgb *msg = msgb_alloc(4096, "test_cr_filter");
struct bsc_nat_parsed *parsed;
struct bsc_nat_acc_lst *nat_lst, *bsc_lst;
struct bsc_nat_acc_lst_entry *nat_entry, *bsc_entry;
struct bsc_nat *nat = bsc_nat_alloc();
struct bsc_connection *bsc = bsc_connection_alloc(nat);
bsc->cfg = bsc_config_alloc(nat, "foo", 1234);
bsc->cfg->acc_lst_name = "bsc";
nat->acc_lst_name = "nat";
nat_lst = bsc_nat_acc_lst_get(nat, "nat");
bsc_lst = bsc_nat_acc_lst_get(nat, "bsc");
bsc_entry = bsc_nat_acc_lst_entry_create(bsc_lst);
nat_entry = bsc_nat_acc_lst_entry_create(nat_lst);
for (i = 0; i < ARRAY_SIZE(cr_filter); ++i) {
msgb_reset(msg);
copy_to_msg(msg, cr_filter[i].data, cr_filter[i].length);
nat_lst = bsc_nat_acc_lst_get(nat, "nat");
bsc_lst = bsc_nat_acc_lst_get(nat, "bsc");
bsc_parse_reg(nat_entry, &nat_entry->imsi_deny_re, &nat_entry->imsi_deny,
cr_filter[i].nat_imsi_deny ? 1 : 0,
&cr_filter[i].nat_imsi_deny);
bsc_parse_reg(bsc_entry, &bsc_entry->imsi_allow_re, &bsc_entry->imsi_allow,
cr_filter[i].bsc_imsi_allow ? 1 : 0,
&cr_filter[i].bsc_imsi_allow);
bsc_parse_reg(bsc_entry, &bsc_entry->imsi_deny_re, &bsc_entry->imsi_deny,
cr_filter[i].bsc_imsi_deny ? 1 : 0,
&cr_filter[i].bsc_imsi_deny);
parsed = bsc_nat_parse(msg);
if (!parsed) {
fprintf(stderr, "FAIL: Failed to parse the message\n");
abort();
}
res = bsc_nat_filter_sccp_cr(bsc, msg, parsed, &contype);
if (res != cr_filter[i].result) {
fprintf(stderr, "FAIL: Wrong result %d for test %d.\n", res, i);
abort();
}
if (contype != cr_filter[i].contype) {
fprintf(stderr, "FAIL: Wrong contype %d for test %d.\n", res, contype);
abort();
}
talloc_free(parsed);
}
msgb_free(msg);
}
int main(int argc, char **argv)
{
struct log_target *stderr_target;
@@ -556,6 +711,7 @@ int main(int argc, char **argv)
test_mgcp_find();
test_mgcp_rewrite();
test_mgcp_parse();
test_cr_filter();
return 0;
}