Compare commits

..

1029 Commits

Author SHA1 Message Date
Ivan Kluchnikov
e77bfb9e22 debian: Update changelog to 0.14.0-fw.2 2015-08-20 20:18:32 +03:00
Holger Hans Peter Freyther
3ef203ee0a sms: Do not go through the routing a second time
If we have tried SMPP first and it was not routable, and then
tried the local delivery there is no point in trying SMPP with
the same parameters again. Leave early and return unknown sub
to the caller.
2015-08-20 19:19:39 +03:00
Holger Hans Peter Freyther
85a304a4fe sms: Add a way to always route SMS through SMPP systems
default-route would only be looked at after there has been
no subscriber in the local database. Depending on the setup
this is not what one wants. This has been discussed at the
OsmoDevCon and there have been hacks in some branches. Let's
introduce a VTY command to select if SMPP should be consulted
first and then fallback to the current behavior.
2015-08-20 19:19:18 +03:00
Holger Hans Peter Freyther
8a62c50218 sms: Simplify the return handling for SMPP routes/unroutable 2015-08-20 19:18:52 +03:00
Holger Hans Peter Freyther
78de2aea7b sms: Put the try_deliver into the header file
Even if it is using BSC/NITB types let's put it in the header
file than just declaring it at a place that could bitrot in a
way that doesn't lead a warning.
2015-08-20 19:17:07 +03:00
Holger Hans Peter Freyther
dc6da14be3 sms: Move the routing of the sms to a separate function
The "default-route" for SMPP will be used after a local
subscriber look-up. Sometimes we want to route everything
to SMPP. Make this possible by changing this routine.
2015-08-20 19:16:27 +03:00
Ivan Kluchnikov
0a8e5f4f86 fix: extension-prefix equal to 0 is used as default value 2015-07-30 15:31:39 +03:00
Ivan Kluchnikov
06d0c6da80 debian: Update changelog to 0.14.0-fw.1 2015-07-27 13:59:03 +03:00
Alexander Chemeris
0855c024c4 utils: 'meas_json' utility to convert measurement feed into a JSON feed. 2015-07-27 13:46:41 +03:00
Ivan Kluchnikov
8543953496 sub: Add the ability to set prefix for randomly generated extensions
Prefix is added before randomly generated extension.
Prefix is useful in case of "accept-all" authentication mode is used
and routing based on number prefix is used.
Added optional configuration parameter "extension-prefix".
2015-07-22 21:32:10 +03:00
Ivan Kluchnikov
3cc7d2b50d debian: osmocom-meas-utils should not depend on -dev packages 2015-07-22 21:31:29 +03:00
Alexander Chemeris
0b19f7af80 libbsc: Update a BTS's SIs when ms_max_power is changed from VTY.
Otherwise you have to restart BTS or at least break the RSL connection
to apply the change.
2015-05-30 23:32:16 +03:00
Alexander Chemeris
3ec78f0d49 libbsc: Abstract out SIs update/generation for a BTS into a separate function.
The code to do that doesn't belong to the control interface, so abstract it out
to a separate function gsm_bts_set_system_infos().
2015-05-30 23:31:53 +03:00
Ivan Kluchnikov
a9c6d44035 debian: Add osmocom-meas-utils package 2015-05-30 23:01:10 +03:00
Alexander Chemeris
90459a0507 libmsc: Update 'max_power_red' VTY command.
Changes:
 * Apply change even if the supplied value is odd, just warn that it is rounded.
 * Apply change even if the supplied value is higher than the 24dB maximum
   suggested by the standard, just warn about this.
 * Apply change to the BTS over OML immediately.
2015-05-27 16:28:44 +03:00
Ivan Kluchnikov
ade03887bb debian: build only osmo-nitb package
- enable smpp support
 - disable the gbproxy test (failing)
2015-05-27 16:15:37 +03:00
Ivan Kluchnikov
d38e96df2a gsm_04_08: Use osmo_assert for transt->conn and conn only in case of paging succeeded
setup_trig_pag_evt function can receive parameter conn = NULL, if T3113 expires.
2015-05-26 15:56:20 +03:00
Andreas Eversberg
8d0f77c8ff osmo-nitb support for codec negotiation
The caller's most preferred codec is selected out of the union of codecs,
which both parties support.

Since codec negotiation is done automatically, there is no need to define
codec for TCH/F and TCH/H via VTY anymore.

Conflicts:

	openbsc/src/libmsc/gsm_04_08.c
	openbsc/src/libmsc/vty_interface_layer3.c
2015-05-26 15:55:13 +03:00
Andreas Eversberg
4e3a267055 If requested TCH/H channel is not available, try assigning TCH/F
If MNCC application requests a half rate channel, the channel might not be
available, due to different cell configuration, so the full rate channel
is used instead.
2015-05-26 15:55:13 +03:00
Andreas Eversberg
3b1cd6dd81 Fix: If paging for half rate was requested, use hr, if supported by MS 2015-05-26 15:55:13 +03:00
Andreas Eversberg
1a3dd31c3b Add full AMR multirate IE support with VTY config for MS and BTS side
Conflicts:

	openbsc/include/openbsc/gsm_data_shared.h
	openbsc/src/libbsc/bsc_vty.c
	openbsc/src/libbsc/chan_alloc.c
2015-05-26 15:55:13 +03:00
Andreas Eversberg
dfd8d0cde0 Drop bad speech frames rather than forwarding them via RTP
Some RTP endpoints may not check for bad frame indications, so a frame
that is marked as bad may be still forwarded, which creates anoying noise.
This patch drops these frames. It depends on the other RTP endpoint how
dropped frames are handled. (insert silence, extrapolate speech...)
2015-05-26 15:55:13 +03:00
Andreas Eversberg
f4d336e2c4 Add check for non existing lchan at tch_frame_down()
Traffic cannot sent to BTS, if there is (currently) no logical channel
associated with the transaction.

This happens, if TCH traffic is received from upper layer, but there is
no lchan available before completing immediate assignment, handover or
assignment process.
2015-05-26 15:55:12 +03:00
Andreas Eversberg
ce7437e27c Send RADIO LINK TIMEOUT value via OML attribute to BTS
The same radio link timeout value is used for BTS and MS side.
2015-05-26 15:55:12 +03:00
Andreas Eversberg
b402dad7f1 Add option to set RADIO LINK TIMEOUT value via VTY 2015-05-26 15:55:12 +03:00
Andreas Eversberg
39494b8751 Allow dynamic RTP payload types between application and MNCC interface
Since EFR/AMR/HR codecs use dynamic RTP payload, the payload type can
be set. If it is set, the frame type must be set also, so OpenBSC
knows what frame types are received via RTP.

This modification only affects traffic beween application and MNCC
interface, not the RTP traffic between OpenBSC and BTS.

Conflicts:

	openbsc/src/libtrau/rtp_proxy.c
2015-05-26 15:55:12 +03:00
Andreas Eversberg
bc1aaacf74 Add traffic forwarding via RTP to remote application
Instead of forwarding traffic through MNCC interface, traffic can
be forwarded to a given RTP peer directly. A special MNCC message
is used to control the peer's destination. The traffic can still be
forwarded through MNCC interface when this special MNCC message is
not used.

It also works with E1 based BTSs.

In conjunction with LCR's "rtp-bridge" feature, the RTP traffic
can be directly exchanged with a remote SIP endpoint, so that the
traffic is not forwarded by LCR itself. This way the performance
of handling traffic only depends on OpenBSC and the remote SIP
endpoint. Also the traffic is exchanged with the SIP endpoint
without transcoding, to have maximum performance.

Increment MNCC version to 5.

Conflicts:

	openbsc/tests/gbproxy/gbproxy_test.c
2015-05-26 15:55:12 +03:00
Holger Hans Peter Freyther
4c8e8f990a Merge branch 'zecke/features/gprs-gsup-fixes'
When communicating with a GGSN that is not the OpenGGSN
the PDP context activation does fail. This is because on
the activation of the first PDP context we need to supply
a MSISDN. Extend the protocol, parse the MSISDN and then
send it to the GGSN. The second item is that we have only
forwarded the requested QoS of the subscriber. In most
cases this is 0x0, 0x0, ... which means one requests a
rate 0 byte/sec which the GGSN will not allow. Make it
possible to receive, store and use the subscribed QoS of
the Subscriber.
2015-05-05 21:16:19 +02:00
Holger Hans Peter Freyther
d05e06989d sgsn: Show the QoS that has been assigned 2015-05-05 21:15:55 +02:00
Holger Hans Peter Freyther
f7b3826f03 sgsn: Dump the E164 (encoded) assigned to the subscriber 2015-05-05 21:15:44 +02:00
Holger Hans Peter Freyther
4bd931f96d sgsn: Handle different levels of QoS
If QoS is only three bytes it does not include the allocation/
retention policy. Otherwise it does. Copy it depending on that.
We should have a macro for the clamping to reduce code duplication.

The insanity does come from the MAP data and this seems to be
the easiest in terms of complexity. It is an array of bytes that
is transported from MAPProxy to the SGSN and then simply forwarded.

The case of more than three bytes is neither unit nor manually
tested so far.
2015-05-05 21:15:20 +02:00
Holger Hans Peter Freyther
8cedded88c sgsn: Store subscribed QoS and attempt to use it
sgsn_create_pdp_ctx should use the subscribed QoS. When selecting
the PDP context we inject the QoS to be used into the TLV structure
and use it during the request. Assume a "qos-Subscribed" structure
only with three bytes and prepend the Allocation/Retention policy
to the request.
2015-05-05 21:11:16 +02:00
Holger Hans Peter Freyther
9ba273d365 sgsn: Copy the msisdn to the sgsn_data and use it in PDP activation
The MSISDN should be present for "security" reasons in the first
activation of a PDP context. Take the encoded MSISDN, store it for
future use and then put it into the PDP activation request.

The MM Context contains a field for a decoded MSISDN already. As
we need to forward the data to the GGSN I want to avoid having to
store TON and NPI in another place. Simply store the data in the
encoded form.
2015-05-05 21:09:53 +02:00
Holger Hans Peter Freyther
49c1a7156c gsup: Extract the QoS field
Add roundtrip test for the new QoS IE. It will be consumed in
later commits.
2015-05-05 21:09:20 +02:00
Holger Hans Peter Freyther
b927f1c319 gsup: Extract the new MSISDN string
Extract the new MSISDN IE from the GSUP message and verify that
it is read/written to the message.
2015-05-05 21:08:00 +02:00
Holger Hans Peter Freyther
02d8c472bd gsup: Specify the QoS service for the PDP info
QoS is a mess. In MAP there is qos-Subscribed which is then extended
using ext-QoS-Subscribed, ext2-QoS-Subscribed, ext3-QoS-Subscribed
and maybe even ext4-QoS-Subscribed by now. The MAP ASN1 files defined
how these need to be "linearized". Instead of copying this I have
decided to include the two semantics with/without the Allocation/Retention
policy using the size of the data.
2015-05-05 21:05:25 +02:00
Holger Hans Peter Freyther
e448554568 gsup: Document passing MSISDN as part of the response
When asking the GGSN to create/open a PDP context one needs
to send a MSISDN. The MSISDN can only be provided through the
GSUP interface.
2015-05-05 20:57:32 +02:00
Holger Hans Peter Freyther
337343d159 Merge branch 'zecke/features/acc-list'
Integrate the change and see how it is going. The unit tests
for the NAT look good so we might not have regressions.
2015-05-03 22:34:16 +02:00
Holger Hans Peter Freyther
d26b8fcbe2 bsc: Send a LU Reject in case it has been filtered
In case we filter the request and it was a Location Updating
Procedure we should reject it.
2015-05-03 22:33:35 +02:00
Holger Hans Peter Freyther
ec0cb7c64d bsc: Add access list filtering to the BSC 2015-05-03 22:33:35 +02:00
Holger Hans Peter Freyther
d6332809d8 bsc: Add access lists to the MSC and the BSC
It is a bit arbitary to decide which one is the global
and which one is the local one. We might change it around.
I don't think we want to introduce it based on BTS.
2015-05-03 22:32:43 +02:00
Holger Hans Peter Freyther
c652913674 filter: Move the con_type into the filter_state 2015-05-03 22:09:02 +02:00
Holger Hans Peter Freyther
06a88fa0ae filter: Move from DNAT to DFILTER category 2015-05-03 22:03:39 +02:00
Holger Hans Peter Freyther
4e8176d0c9 filter: Remove bsc_connection from the filter API
Remove the last occurence of NAT datastructures in the filtering
module and add the ctx to the filter request structure.
2015-05-03 22:01:46 +02:00
Holger Hans Peter Freyther
c09f8a3b7f filter: Remove nat_sccp_connection from public API 2015-05-03 21:59:29 +02:00
Holger Hans Peter Freyther
81dbfe412c filter: Remove the bsc_connection from the internal functions 2015-05-03 21:42:29 +02:00
Holger Hans Peter Freyther
71857d7242 filter: Put all the parameters in a struct to avoid order issues
With the "local" and "global" list name we might pick the
wrong argument. Avoid it by passing them as a struct.
2015-05-03 21:42:28 +02:00
Holger Hans Peter Freyther
a0478814bc filter: Remove NAT knowledge from auth_imsi
Push back the parameters we need to pass. auth_imsi doesn't
know anything about the nat now.
2015-05-03 21:42:28 +02:00
Holger Hans Peter Freyther
4ba947bf4b filter: Separate SCCP/BSSAP extraction and gsm48 code
For the BSC we will have the gsm48_hdr and don't need to
find data within SCCP. For legacy reasons we need to
initialize con_type, imsi, reject causes early on and
need to do the same in the filter method.
2015-05-03 21:42:28 +02:00
Holger Hans Peter Freyther
c36a6d5705 filter: More renaming and remove of "NAT" from it 2015-05-03 21:42:28 +02:00
Holger Hans Peter Freyther
14b2cd9f32 filter: Rename BSC to LOCAL and NAT to GLOBAL 2015-05-03 21:42:28 +02:00
Holger Hans Peter Freyther
a1e6bd6768 filter: Remove nat from bsc_nat_acc_lst and replace with msg 2015-05-03 21:42:28 +02:00
Holger Hans Peter Freyther
d7e04b9956 filter: Cease out "struct bsc_nat" from the API
This means we need to require a talloc context and
simply operate on the list. I had considered creating
a structure to hold the list head but I didn't find
any other members so omitted it for now.
2015-05-03 21:42:28 +02:00
Holger Hans Peter Freyther
d04d009f47 filter: Move VTY code into the filter module 2015-05-03 21:42:28 +02:00
Holger Hans Peter Freyther
4579bb1ed7 filter: Move the access list management around 2015-05-03 21:42:27 +02:00
Holger Hans Peter Freyther
973dbaeebd filter: Move the method definition to the filter module
Move the filter methods to the filter module. This is
still only usable for the NAT and the _dt/_cr filter
routines need to move back to the bsc_nat in the long
run.
2015-05-03 21:42:27 +02:00
Holger Hans Peter Freyther
4247cead2b filter: Move the gsm 04.08 filter to a common place
For customer requirements we want to be able to do
filtering on the BSC as well. The same messages need
to be scanned and the same access-lists will be looked
at. In the future we might even split traffic based
on the IMSI. Begin with moving the code to a new top
level directory and then renaming and removing the
nat dependency.
2015-05-03 21:42:27 +02:00
Holger Hans Peter Freyther
38159428d2 mgcp: Fix compiler warning on 64bit builds
ENDPOINT_NUMBER takes the difference of two pointers. On 64bit
builds the difference is a long and the compiler then complains
about the usage of abs. We will never have thousands of endpoints
so silence the warning by casting the ENDPOINT_NUMBER to int.

mgcp_vty.c:1381:34: warning: absolute value function 'abs' given an argument of type 'long' but has parameter of
      type 'int' which may cause truncation of value [-Wabsolute-value]
                        rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp),
                                                      ^
../../include/openbsc/mgcp_internal.h:206:31: note: expanded from macro 'ENDPOINT_NUMBER'
 #define ENDPOINT_NUMBER(endp) abs(endp - endp->tcfg->endpoints)
                              ^
mgcp_vty.c:1381:34: note: use function 'labs' instead
2015-05-02 10:02:38 +02:00
Holger Hans Peter Freyther
4a8b938348 Merge branch 'zecke/features/no-queue'
Let's get bigger exposure of the new implementation
2015-04-29 18:53:40 +02:00
Holger Hans Peter Freyther
d6d7affa6e sub: Remove the queue from the subscriber code
The idea of "subscriber_get_channel" was that different
requests would be coordinated. At the same time we have
seen that the "queue" can get stuck at both 31C3 and the
rhizomatica installations.

Voice calls and SMS do not need coordination. We should
be able to send SMS on a voice channel and switch the MS
from a SDCCH to a TCH in case we establish a voice call.
The SMS code itself needs to coordinate to obey the limit
of one SMS per direction but this should be enforced in
the sms layer and not on the subscriber.

Modify the code to have a simple paging coordination. The
subscriber code will schedule the paging and register who
would like to know about success/failure.

This allowed to greatly simplify the paging response
handling for the transaction code (and in fact we could
move the transaction list into the subscriber structure
now). The code gained to support to cancel the notification
of a request (but not the paging itself yet).

TODO: Cancel paging request in case no one cares about it
anymore.
2015-04-29 18:53:28 +02:00
Holger Hans Peter Freyther
0759b1b952 sub: Remove introspection of the "channel queue"
Over the next commits the queuing of commits will be
completely modified to remove the queue and move the
scheduling/limits to the outer callers.
2015-04-29 18:53:27 +02:00
Holger Hans Peter Freyther
0ae564d9b1 sub: Remove paging requests before dispatching
The dispatching might lead to the removal of more
paging requests and makes "request" invalid. Remove
it before calling the callback.
2015-04-29 18:53:27 +02:00
Holger Hans Peter Freyther
1e28eb83c0 mncc: Select the codec similar to the modify handling
In case the default TCH/F codec is "EFR" and we do an early
assignment from SDCCH to a TCH we would assign the TCH/H
codec. This is because the lchan_type will be neither a
TCH/H nor a TCH/F.

At the same time the _gsm48_lchan_modify code to check for
half vs. full-rate is the other way around. Align both.

It is full-rate if it is not a TCH_H. This will have some
other complications down the way (early assignment on
cells with only TCH/H). So the mode should not depend on
the _current_ channel but the kind of channel we want.
2015-04-29 18:53:27 +02:00
Holger Hans Peter Freyther
b396b69cb2 debian: Do not depend on shared libraries directly
The debian shlibs:depends macro will add the depends
according to the needed libraries for us. We only need
this for the sqlite3 plugin of libdbi-drivers as there
is no direct linkage.
2015-04-29 18:53:08 +02:00
Jacob Erlbeck
ddc0e05604 mgcp/test: Fix mgcp-transcoding assertion (Coverity)
In test_rtp_seq_state an assignment is accidently done within an
assertion.

This commit changes that into a comparison as it was intended.

Fixes: Coverity CID 1295457, 1295458
Sponsored-by: On-Waves ehf
2015-04-29 14:02:40 +02:00
Jacob Erlbeck
5a2484b10e mgcp: Move assignment of src_codec downwards
Currently the src_codec const variable is set to &src_end->codec
before src_end is checked against NULL. Since the assigment is just
an address operation and the memory where it points to is only
accessed after the NULL check, this does not harm technically.
Nevertheless this is potential source for errors if that code is
changed.

This commit moves the definition below the NULL check. This does not
comply with the coding style, but it cannot be split into definition
and a later assignment due to the const qualifier.

Sponsored-by: On-Waves ehf
2015-04-28 09:40:40 +02:00
Holger Hans Peter Freyther
cb43a9ac44 mgcp: Allow to disable transcoding for trunks
We might have compiled transcoding into the MGW but
we don't want to enable it for a given user. Add a new
switch that should allow that.

I had manually tested the allow-transcoding/no allow
VTY interface for the primary interface and a new trunk
using show running-config.
2015-04-24 16:10:54 -04:00
Holger Hans Peter Freyther
c57b5507b2 mgcp: Ignore the case for finding a codec
It is unlikely that GSM, gsm and GsM refer to different codecs.
The mera mvts does send the audio codecs in lower case even if
RFC 3551 has them in upper case (but copy and paste is sometimes
too hard).
2015-04-24 15:07:20 -04:00
Holger Hans Peter Freyther
7f100c9712 nat: Make mode-set patching optional 2015-04-23 20:27:30 -04:00
Holger Hans Peter Freyther
d4b03187c6 sgsn/gtp: Fill out the optional RAT type
Assume we are always a GERAN network right now.
2015-04-23 17:01:17 -04:00
Holger Hans Peter Freyther
8e6ecc9667 misc: Fix warnings about size of size_t in printf
Fixes warnings like:

warning: format '%d' expects argument of type 'int', but argument 3 has type 'long int' [-Wformat]
2015-04-23 17:01:09 -04:00
Holger Hans Peter Freyther
adc17268fc debian: meas2pcap requires libpcap-dev unconditionally 2015-04-23 17:01:03 -04:00
Jacob Erlbeck
7ffa7b095f nitb: Fix IMSI/IMEI buffer handling (Coverity)
Currently the handling of the buffers is not done consistently. Some
code assumes that the whole buffer may be used to store the string
while at other places, the last buffer byte is left untouched in the
assumption that it contains a terminating NUL-character. The latter
is the correct behaviour.

This commit changes to code to not touch the last byte in the buffers
and to rely on the last byte being NUL. So the maximum IMSI/IMEI
length is GSM_IMSI_LENGTH-1/GSM_IMEI_LENGTH-1.

For information: We assume that we allocate the structure with
talloc_zero. This means we have NULed the entire imsi array and then
only write sizeof - 1 characters to it. So the last byte remains NUL.

Fixes: Coverity CID 1206568, 1206567
Sponsored-by: On-Waves ehf
2015-04-10 08:47:00 +02:00
Jacob Erlbeck
322b1499cd nitb: Check source string length before calling strncpy (Coverity)
Currently some VTY command do neither check the length of the source
string before calling strncpy nor ensure NUL-termination afterwards.
This can to destination string buffers whose contents are not
NUL-teminated.

This commit adds checks and corresponding warnings to the VTY
commands 'subscriber TYPE ID name .NAME" and "subscriber TYPE ID
extension EXTENSION".

Fixes: Coverity CID 1206570, 1206569
Sponsored-by: On-Waves ehf
2015-04-07 20:13:53 +02:00
Jacob Erlbeck
5b51205187 gprs: Fix GSUP cancel_type handling (Coverity)
When handling an incoming GSUP cancellation request, the cancel_type
if effectively ignored, such that is always handled as
GPRS_GSUP_CANCEL_TYPE_UPDATE and never as WITHDRAW.

This commit fixes the expression used to set the variable
is_update_procedure.

Fixes: Coverity CID 1267739
Sponsored-by: On-Waves ehf
2015-04-07 20:13:43 +02:00
Jacob Erlbeck
9ed6fd25dd nat: Fix timeslot range in 'show bsc mgcp' VTY command
Currently the inner loop in show_bsc_mgcp iterates of the timeslot
interval [0, 31]. Timeslot 0 is not valid, which causes
mgcp_timeslot_to_endpoint to generate a corresponding warning and to
return an invalid endp value. That value causes an out-of-bound
read access, possibly hitting unallocated memory.

This patch fixes the loop range by starting with timeslot 1.

Note that this does not prevent mgcp_timeslot_to_endpoint from
returning an invalid endpoint index when called with arguments not
within its domain.

Addresses:
<000b> ../../include/openbsc/mgcp.h:250 Timeslot should not be 0
[...]
    vty=0xb4203db0, argc=1, argv=0xbfffebb0) at bsc_nat_vty.c:256
        max = 1
        con = 0xb4a004f0
        i = 0
        j = 0
[...]
==15700== ERROR: AddressSanitizer: heap-use-after-free on address
0xb520be4f at pc 0x8062a42 bp 0xbfffeb18 sp 0xbfffeb0c

Sponsored-by: On-Waves ehf
2015-04-07 20:13:28 +02:00
Holger Hans Peter Freyther
08ea4d87f6 nat: Check for the access list in set command as well
I omitted the check as this was already done by the verify
function for this command. Please Coverity and do the check
again even if it is not necessary. I begin to doubt the
usage of a "dedicated" verify method as well.

Silences: Coverity CID 1293150
2015-04-07 09:10:05 +02:00
Holger Hans Peter Freyther
0ac00c15b9 nat: Check the con->imsi for the tracked IMSI
On DT messages we directly write into the tracked SCCP
connection. This means "imsi" will always be NULL at
this check. Change the code to use con->imsi

Fixes: Coverity CID 1293151
2015-04-07 09:06:26 +02:00
Holger Hans Peter Freyther
8ccf06c58b nat: Add ctrl command to save the configuration
$ bsc_control.py -d localhost -p 4250 -s net.0.save-configuration 0
2015-04-05 15:42:32 +02:00
Holger Hans Peter Freyther
ab94ca18f2 nat: Add a ctrl command to add to an existing ACC list
We want to have a program add entries to the allow list
this can be done using:

$ bsc_control.py -d localhost -p 4250 -s net.0.add.allow.access-list.NAME "^IMSI$"
2015-04-05 15:42:25 +02:00
Holger Hans Peter Freyther
7c00983275 nat: Inform others if an IMSI is rejected
In case one wants to monitor the access lists one
there is now a trap for the IMSI.
2015-04-05 14:06:16 +02:00
Holger Hans Peter Freyther
fa1cba9e60 nat: The reject cause of "-1" has failure meaning, change it
bsc_stat_reject is treating -1 as parsing failure but for the
global barring. Change it to another return value so it is
not counted as parsing failure.
2015-04-05 11:44:47 +02:00
Holger Hans Peter Freyther
6f6cbf7c5d bts: "Repair" broken channels if we receive the release ack
We had issues with odd behavior on the nanoBTS which lead
to the introduction of the "broken" state. On busy multi
BTS cells (e.g. rhizomatica) with wifi backhaul the timeout
we set to wait for a RF Channe Release ACK is sometimes too
little and channels are marked broken that look to be okay
(besides the still to be determined delay).

In case of a sysmoBTS we now know that we can change the
state of a broken channel back to normal in case we do
receive the right response.

Manually verified using the Smalltalk BTS code

PackageLoader fileInPackage: 'FakeBTS'
bts := FakeBTS.BTS new.
bts btsId: '1903/0/0'.
bts connect: 'localhost'.
bts waitForBTSReady.
test := FakeBTS.OpenBSCTest new.
test bts: bts.

test requireAnyChannel

... wait for NITB output
<0004> abis_rsl.c:223 (bts=0,trx=0,ts=0,ss=0) Timeout during deactivation! Marked as broken.

... process pending messages
stdin next
<0004> abis_rsl.c:735 (bts=0,trx=0,ts=0,ss=0) CHAN REL ACK for broken channel. Releasing it.

So the channel went from broken to unallocated.
2015-04-04 19:58:50 +02:00
Holger Hans Peter Freyther
40407835b3 bsc: Change paging strategy based on override or not
Change the paging strategy based on on if a LAC override
is in place or not. In case we had changed the LAC we need
to page on all the BTS. Change the "grace" handling to
iterate over the BTS and filter out all non matching ones
LAC in case no LAC handling is active.

Manually verified all four cases with a single BTS:

* No LAC handling and grace period
* LAC handling and grace period
* No LAC handling and not lock
* LAC handling and lock.

Related: SYS#1398
2015-04-01 19:26:26 +02:00
Holger Hans Peter Freyther
067ce6dea5 bsc: In preparation to the MT lac/ci patching split the code
For MT we can't page per lac as we don't know which BTS was
the original one. Split the grace period and normal mode into
two methods so we can bloat both of them later.
2015-04-01 19:26:24 +02:00
Holger Hans Peter Freyther
32dd2f3f9b bsc: Allow to use different LAC/CI for the core-network
We need to use different LAC/CI towards the core network.
It is a bit problematic as LAC/CI is a per BTS attribute
so this feature only works if a BSC manages everything in
the same LAC.

Related: SYS#1398
2015-04-01 19:26:12 +02:00
Holger Hans Peter Freyther
7cce1d301a libmgcp: Fail if transcoding can't be configured
We want to fail theallocation of an endpoint in case the
transcoding can't be configured.

Manually verified with:

./src/osmo-bsc_mgcp/osmo-bsc_mgcp -c doc/examples/osmo-bsc_mgcp/mgcp.cfg

$ ./contrib/mgcp_server.py
0000   32 30 30 20 33 30 36 39    200 3069
0008   31 20 4F 4B 0D 0A          1 OK.. ('127.0.0.1', 2427)
0000   34 30 30 20 35 39 30 36    400 5906
0008   39 20 46 41 49 4C 0D 0A    9 FAIL.. ('127.0.0.1', 2427)
0000   34 30 30 20 33 35 34 36    400 3546
0008   33 20 46 41 49 4C 0D 0A    3 FAIL.. ('127.0.0.1', 2427)
0000   34 30 30 20 36 32 31 37    400 6217
0008   30 20 46 41 49 4C 0D 0A    0 FAIL.. ('127.0.0.1', 2427)

Verified by not sending L: in the CRCX and then failing on the
MDCX.
2015-03-29 11:46:45 +02:00
Holger Hans Peter Freyther
fd603ed9e2 write_queue: Check the result of osmo_wqueue_enqueue and free
The write_queue is designed to have a maximum amount of pending
messages and will refuse to take new messages when it has been
reached. The caller can decide if it wants to flush the queue
and add the message again, create a log. But in all cases the
ownership of the msgb has not been transferred. Fix the potential
memory leak in the failure situation.
2015-03-28 18:13:37 +01:00
Andreas Eversberg
cf7557a7e7 rtp: Fixed problem of mute audio on some calls
When reading from RTP socket, the first read() may fail right after
connecting to remote socket. Subsequent read() will work as it should.

If the remote socket does not open fast enough, the transmitted RTP
payload can cause an ICMP (connection refused) packet reply. This causes
the read to fail with errno=111. In all other error cases, the errno is
logged at debug level. In all error cases, reading is not disabled.

Conflicts:
	openbsc/src/libtrau/rtp_proxy.c

[hfreyther: Fix typo, stop reading in all cases but ECONNREFUSED]
2015-03-28 17:56:16 +01:00
Holger Hans Peter Freyther
37b5ce56a0 rtp: Fix memory leak fixed by Andreas without mentioning it
We allocate the msgb at entry of the method and we always need
to msgb_free it.
2015-03-28 17:56:16 +01:00
Andreas Eversberg
9967a57587 rtp: Add handling of BFI (Bad Frame Indicatior) of received TRAU frames
If a bad TRAU frame is received, it is forwarded to MNCC application
as GSM_BAD_FRAME. The application can now handle the GAP of missing
audio. (e.g. by extrapolation)

If TRAU frames are forwarded via RTP, bad frames are dropped, but frame
counter and timestamp of RTP sender state is incremented.

Conflicts:
	openbsc/src/libtrau/rtp_proxy.c

[hfreyther: Merge without testcase, fix typo]
2015-03-28 17:56:08 +01:00
Max
cea35aecdc ignore debian build byproducts
Signed-off-by: Max <max.suraev@fairwaves.co>
2015-03-28 17:13:57 +01:00
Holger Hans Peter Freyther
7ce72c1be8 rtp: And really catch up and remove all occurences of openbsc/rtp.h 2015-03-22 14:43:19 +01:00
Holger Hans Peter Freyther
7c7358e91e rtp: Catch up with the removal of the rtp.h 2015-03-22 13:56:30 +01:00
Holger Hans Peter Freyther
d0e171a9ff rtp: Use osmocom/netif/rtp.h for the rtp structure definition
We depend on libosmo-netif unconditionally. Let's use this
definition of rtp and have one portability issue less.
2015-03-22 09:51:43 +01:00
Holger Hans Peter Freyther
8deba01eda debian: We are at version 0.14 now 2015-03-14 20:33:43 +01:00
Holger Hans Peter Freyther
66105fd3dc ctrl: Implement a global result for rf_locked
Create a one stop command to give a statement for the
entire network. This can be used to check the policy
and the state of the entire network.
2015-02-10 23:03:25 +01:00
Holger Hans Peter Freyther
ca4151984c ctrl: Add a command to check how many bts are configured
This can be used to query how many bts are configured to
check if all of them are locked or not.
2015-02-10 21:55:37 +01:00
Holger Hans Peter Freyther
349c40f47b nitb: Move the rf-lock commands from osmo-bsc to libbsc
The bts.0.rf-state and rf_locked command have been moved
from the osmo-bsc binary to libbsc. All tests continue to
pass.
2015-02-10 21:37:16 +01:00
Holger Hans Peter Freyther
a0735ecab5 smpp: Fix potential crash in handling submitSM
In case:

* No message_payload and a 0 sm_length was used
* esm_class indicates UDH being present
* 7bit encoding was requested

The code would execute:

  ud_len = *sms_msg + 1;

Which is a NULL pointer dereference and would lead
to a crash of the NITB. Enforce the limits of the
sm_length parameter and reject the messae otherwise.

Fixes: Coverity CID 1042373
2015-02-08 09:56:31 +01:00
Holger Hans Peter Freyther
60e073e28d nat: getopt returns "static" data no need to copy it
I used strdup in case the data would not be valid from after
the call to getopt and this creates a potential leak if a user
is specifying multiple configuration files. If I depend on the
fact that the string is a pointer into the argv[] array I can
kill the strdup and fix the unlikely leak.

Fixes: Coverity CID 1206578
2015-02-08 09:25:38 +01:00
Holger Hans Peter Freyther
019851a523 smpp: Do not check conn for being null
We are deferencing conn earlier in this function without doing
a null check. At the time deliver_to_esme is called the conn
will always exist and even the lchan is likely to be present.
Remove the null check for conn right now.

Fixes: Coverity CID 1210594
2015-02-08 09:21:04 +01:00
Sipos Csaba
56e1766dba nokia: Allow to set the reset time for the nokia bts 2015-02-07 13:27:36 +01:00
Holger Hans Peter Freyther
9c20a5f45c sgsn: Add easy APN commands with just the name
For most configurations we don't address multiple GGSNs but
only want to enforce a list of APNs. In the future we might
add a special global GGSN context but not right now.

Fixes: SYS#593
2015-02-06 16:44:58 +01:00
Jacob Erlbeck
ca69b0f68d Revert "gprs: Block other GSUP procedures during PURGE_MS"
This reverts commit f81cacc681.

Since the PURGE MS retry mechanism had been removed, this feature
is not used anymore. It just makes the code more complex.

Conflicts:
	openbsc/include/openbsc/gprs_sgsn.h
	openbsc/src/gprs/gprs_subscriber.c
	openbsc/tests/sgsn/sgsn_test.c
2015-02-06 13:22:24 +01:00
Jacob Erlbeck
277b71e0d8 sgsn: Select GGSN based on APN
Currently the APN IE in the Activate PDP Contex Request and the PDP
data that is stored with the subscriber is ignored completely.

This commit adds the sgsn_mm_ctx_find_ggsn_ctx that checks the APN IE
against the subscriber's PDP data entries if both are present. If
there is no match, the request is rejected.

If an APN IE has not been included but PDP data entries are present,
the function checks all of these entries against the static 'apn'
configuration to find a suitable entry.

If an APN has not been determined so far and any APN is allowed, the
configuration is checked with an empty APN string, to allow for
default configurations based on the IMSI prefix only.

If nothing of this succeeded but the request wasn't rejected either,
and there is no 'apn' configuration at all or if any APN is allowed
but a default configuration ist not present, the GGSN with id 0 is
used (if present).

Otherwise the request is rejected ('missing APN').

Ticket: OW#1334
Sponsored-by: On-Waves ehf
2015-02-06 13:00:29 +01:00
Jacob Erlbeck
f345612654 sgsn: Add sgsn_ggsn_ctx_free function
This function will be needed for testing, since the leak check would
fail if the GGSN context are not cleaned up after use.

Sponsored-by: On-Waves ehf
2015-02-06 10:00:03 +01:00
Jacob Erlbeck
cb1db8b6d5 sgsn: Add functions to handle APN contexts
This commit adds the exported functions apn_ctx_find_alloc,
apn_ctx_free, apn_ctx_by_name, and apn_ctx_match to manage and
retrieve APN to GGSN mappings.

The following VTY commands are added to 'config-sgsn':

 - apn APN ggsn <0-255>
 - apn APN imsi-prefix PREFIX ggsn <0-255>

which maps an APN gateway string to an SGSN id. The SGSN must be
configured in advance. When matching an APN string, entries with a
leading '*' are used for suffix matching, otherwise an exact match is
done.  When a prefix is given, it is matched against the IMSI. If
several entries match, a longer matching IMSI prefix has precedence.
If there are several matching entries with the same PREFIX, the entry
with longest matching APN is returned.

Ticket: OW#1334
Sponsored-by: On-Waves ehf
2015-02-06 09:56:17 +01:00
Jacob Erlbeck
0e8add601d sgsn: Add PDP info to subscriber data
Currently the PDP info that is transmitted via GSUP is just parsed
and then discarded.

This commit adds a new data structure sgsn_subscriber_pdp_data and
maintains a list of those in sgsn_subscriber_data. The PDP data is
copied from an incoming GSUP UpdateLocationResult message. If that
message contains the PDPInfoComplete flag, the list is cleared before
new entries are added.  The 'show subscriber cache' output now also
shows the PDP data entries.

Note that the InsertSubscriberData message is still not supported.

[hfreyther: Added talloc_free in gprs_subscr_pdp_data_clear]

Sponsored-by: On-Waves ehf
2015-02-06 09:55:39 +01:00
Holger Hans Peter Freyther
f6f86b0eec osmo-bts: Introduce new struct for a power loop in the BTS code
Keep track if the power level has been "fixed" by the BSC,
otherwise keep track of the currently ordered one. The ms_power
is the initial value set by the BSC and continues to be used.
2015-02-05 22:25:03 +01:00
Holger Hans Peter Freyther
4e13a8f9f9 bsc/nitb: Allow to set the GPRS mode through the ctrl command
Create a control command to read and modify the gprs mode. Use
the get_string_value to indicate if the value was found or not.
This is useful for the ctrl interface where I didn't want to
replicate "none", "gprs" and "egprs". Share code to verify that
a BTS supports the mode.

Related: SYS#591
2015-01-31 22:38:48 +01:00
Holger Hans Peter Freyther
b8c204cb92 ctrl/bsc: Fix copy and paste error and update text
30f1f37638 introduced new channel
combinations but had a copy and paste error in the description.
The jenkins system didn't run the external tests so this issue
and others were not noticed until now.

Fix the copy and paste and update the test result.
2015-01-31 19:42:42 +01:00
Holger Hans Peter Freyther
7af5f8130f rsl: Remove unused code for channel activation
The code has been unused for a long time. Let's remove it.
2015-01-31 12:49:41 +01:00
Holger Hans Peter Freyther
8657326093 meas: Install the scenario command and test it 2015-01-31 12:49:41 +01:00
Holger Hans Peter Freyther
a07e38d4bf meas: Add VTY documentation for the measurement commands
Document the parameters that can be passed on.
2015-01-31 09:48:18 +01:00
Jacob Erlbeck
4b2d02d037 sgsn/test: Fix memory leak in test_subscriber_gsup
Currently the MM context is not deleted when a GSUP location
cancellation message is processed, because the real
sgsn_update_subscriber_data function has been wrapped to a dummy
implementation.

This commit adds an explicit call to sgsn_mm_ctx_cleanup_free which
also unassigns the LLME, so the call to gprs_llgmm_assign is removed.

It also adds an assertion to check that there are no talloc'ed blocks
left in tall_bsc_ctx.

Addresses:
== 372 bytes in 1 blocks are possibly lost in loss record 7 of 9
==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==    by 0x4059FB8: _talloc_zero (talloc.c:354)
==    by 0x8055B82: sgsn_mm_ctx_alloc (gprs_sgsn.c:167)
==    by 0x804A336: alloc_mm_ctx (sgsn_test.c:140)
==    by 0x804B24D: test_subscriber_gsup (sgsn_test.c:503)
==    by 0x804EC99: main (sgsn_test.c:1853)

Sponsored-by: On-Waves ehf
2015-01-30 21:33:29 +01:00
Jacob Erlbeck
baf0f94a7d sgsn/test: Add checks for subscr->error_cause
This commits adds a few asserts that check the value of
subscr->error_cause after a GSUP message has been received.

Sponsored-by: On-Waves ehf
2015-01-30 21:32:47 +01:00
Jacob Erlbeck
9ff82892da gprs: Use 'Network failure' as default cause
This commit adds a check after a GSUP message has been decoded
whether it is an error message and does not contain a cause value.
If his is the case, the cause value is set to 'Network failure', so
that this cause if effectively the default value for error messages.

Sponsored-by: On-Waves ehf
2015-01-30 21:32:26 +01:00
Jacob Erlbeck
85ba655788 gprs/test: Fix GSUP Purge MS response messages
Currently the message types for these message types are wrong.

This patch inserts the correct message types.

Sponsored-by: On-Waves ehf
2015-01-30 21:29:58 +01:00
Jacob Erlbeck
466cedd052 sgsn/test: Add tests for PurgeMs responses
Currently there are not any test cases for PurgeMS GSUP messages in
test_subscriber_gsup.

This commit adds tests for incoming PurgeMSResult and -Error
messages.

Sponsored-by: On-Waves ehf
2015-01-30 21:28:17 +01:00
Jacob Erlbeck
07f6e36ab4 gprs: Send GSUP error reply for requests without IMSI
Currently gprs_subscr_rx_gsup_message returns immediately after it
detects that an IMSI has not been given in the received GSUP message.
While this is ok for responses (result or error), a request should
always be answered.

This commit adds code to reply with a corresponding error message
("Invalid mandatory information") when it receives a request without
an IMSI.

Note that the generated error message will not contain an IMSI either.

Sponsored-by: On-Waves ehf
2015-01-30 21:28:07 +01:00
Jacob Erlbeck
8000e0ea50 gprs: Support cancellation type
The cancellation type that is part of the UpdateCancellation message
is currently ignored.

This patch adds the missing glue between the existing GSUP and GMM
support. If the type is not present or has the value updateProcedure
the subcriber and MM context are siliently removed. Otherwise, a
message with cause 'implicitly detached' is sent to the MS. Since the
real cause is not known (the specification neither added a cause IE
nor defined a static cause value), the MS may get the real cause in
the following AttachRej.

Added VTY commands:

- update-subscriber imsi IMSI cancel update-procedure
- update-subscriber imsi IMSI cancel subscription-withdraw

the old form without the cause is no longer supported.

Sponsored-by: On-Waves ehf
2015-01-30 21:27:07 +01:00
Jacob Erlbeck
929acdf6bf gprs: Handle PURGE MS ERR/RES without subscr
Currently the subscr entry is no longer present, when PURGE MS
ERROR/RESULT arrives. In this case, an unspecific notice is logged
('unknown IMSI'). This clutters up the logfile with notices even in
perfectly normal operation.

This commit changes the code path that is used when a subscr cannot
be found for an incoming GSUP message. A check for PURGE MS RESULT
and ERROR is added and gprs_subscr_handle_gsup_purge_no_subscr is
called for these messages instead of gprs_subscr_handle_unknown_imsi.

Sponsored-by: On-Waves ehf
2015-01-28 20:44:40 +01:00
Jacob Erlbeck
e988ae471d gprs: Don't use subscr->keep_in_ram in normal operation
Currently the keep_in_ram flag is explicitely reset in
gprs_subscr_cleanup to cover the case, that the VTY 'create'
sub-command has been used to create the subscriber entry.

This commit completely removes keep_in_ram handling from
gprs_subscriber.c and adds a VTY 'destroy' sub-command to reset the
flag and remove the entry. So 'create' and 'destroy' can be used to
manager sticky entries that are kept even when a location
cancellation is done.

Added VTY command:

- update-subscriber imsi IMSI destroy

Sponsored-by: On-Waves ehf
2015-01-28 20:42:58 +01:00
Jacob Erlbeck
e671d254cb sgsn: Add sgsn_mm_ctx_cleanup_free for safe shutdown
Currently the MM context cleanup code is distributed over several
functions. sgsn_mm_ctx_free not only frees data structure but also
eventually stops the timer and does the subscriber clean-up.
mm_ctx_cleanup_free (gprs_gmm.c) cleans up the PDP contexts and
unassign the TLLI.

This commit moves the cleanup code from both functions into a new
unifying function sgsn_mm_ctx_cleanup_free that cares about the
clean-up of all related sub-systems.

Sponsored-by: On-Waves ehf
2015-01-28 20:42:52 +01:00
Jacob Erlbeck
555b2e5ac1 sgsn: Don't allow mmctx == NULL in sgsn_update_subscriber_data
Currently, sgsn_update_subscriber_data can be called with mmctx ==
NULL and will find and associate the right context (if present) based
on the subscriber's IMSI. This will not happen in regular use
any more, since sgsn_update_subscriber_data will only be called when
subscribers are used (auth mode 'remote') and in this case
gprs_subscr_get_or_create_by_mmctx will already be called by
sgsn_auth_request. Therefore, MM context and subscriber are always
associated except for some test cases and experimental VTY usage.
The current implementation of sgsn_update_subscriber_data also causes
additional complexity for the deletion on MM contexts to avoid a
ipossible double-free MM contexts.

This commit removes the MM context <-> subscriber association code
from sgsn_update_subscriber_data. That function must always be called
with mmctx != NULL, now. To avoid problems with VTY and test usage,
the calling subscriber function now only call
sgsn_update_subscriber_data when mmctx != NULL, since the purpose of
that function is to update that state of an existing MM context after
subscriber data has been changed.

Sponsored-by: On-Waves ehf
2015-01-28 20:42:52 +01:00
Holger Hans Peter Freyther
925c57fb54 nitb: Make the last change configurable
Introduce a NITB node and add the subscriber creation as
config name in there.
2015-01-27 10:58:29 +01:00
Holger Hans Peter Freyther
1ba0730a71 nitb: Allow the network to decide if a subscriber should be created 2015-01-27 10:44:17 +01:00
Jacob Erlbeck
120250ad6f gbproxy: Remove dummy definition of subscr_put
The definition of subscr_put in gb_proxy_main.c will break linking if
symbols from libcommon are used. Since subscr_put is in libcommon,
there is no need for this dummy definition anymore.

This patch removes the dummy definition.

Adresses:
../../src/libcommon/libcommon.a(gsm_subscriber_base.o): In function `subscr_put':
/home/jerlbeck/git/build/openbsc/openbsc/src/libcommon/gsm_subscriber_base.c:90: multiple definition of `subscr_put'
gb_proxy_main.o:/home/jerlbeck/git/build/openbsc/openbsc/src/gprs/gb_proxy_main.c:56: first defined here

Sponsored-by: On-Waves ehf
2015-01-27 08:35:18 +01:00
Jacob Erlbeck
306bb993aa sgsn: Don't reset mm->subscr manually in sgsn_mm_ctx_free
Currently the sgsn_mm_ctx_free contains code to reset the mm->subscr
field that is also present in gprs_subscr_cleanup, which is called
directly afterwards.

This commit modifies the code path, so that the cleanup is done by
the gprs_subscr_cleanup function. The additional reference counter
increment is needed, since mm->subscr->mm->subscr (which is the same
like mm->subscr) will be reset (and unref'd) within
gprs_subscr_cleanup. Because the local variable subscr in
sgsn_mm_ctx_free is an additional pointer to the subscriber object,
it is consequent to adjust the reference counter when the assignment
is done.

Sponsored-by: On-Waves ehf
2015-01-27 08:31:36 +01:00
Jacob Erlbeck
3e4e58f349 gprs: Rename gprs_subscr_delete to gprs_subscr_cleanup
The old name is somewhat misleading. The function is rather preparing
the subscriber for a subsequent subscr_free, that is possibly invoked
by a subscr_put. It detaches the subscriber from the MM context and
optionally invokes a PURGE_MS procedure. Therefore the _cleanup
suffix is chosen (see mm_ctx_cleanup_free).

Sponsored-by: On-Waves ehf
2015-01-27 08:31:03 +01:00
Jacob Erlbeck
3ee67ff5c2 gprs: Don't check for EINPROGRESS in gprs_gsup_client_create
Currently, the return value of gsup_client_connect is checked whether
it is < 0 and != -EINPROGESS. Since gsup_client_connect will only
return a negative value on a few permanent errors (not including
EINPROGRESS), rc is always != EINPROGRESS.

This patch removes the explicit check againt -EINPROGRESS and just
leaves the check rc < 0.

Sponsored-by: On-Waves ehf
2015-01-27 08:30:49 +01:00
Holger Hans Peter Freyther
abb3478533 gb_proxy: No need to copy optarg
Fixes: Coverity CID 1206578
2015-01-27 08:30:37 +01:00
Jacob Erlbeck
496aee7cb8 sgsn: Ensure 0-terminated imsi strings (Coverity)
Currently the size argument of strncpy is set to sizeof(mm->imsi) in
some places. If the source IMSI string is too long, the terminating
NUL byte in the static mm->imsi field gets overwritten.

This patch limits the size to sizeof(mm->imsi)-1, so that the last
byte of the buffer (that has been initialized to 0) is not
overwritten.

Fixes: Coverity CID 12065751, 12065754, 1206575

Sponsored-by: On-Waves ehf
2015-01-26 10:59:49 +01:00
Jacob Erlbeck
37139e5933 gprs: Do not put the subscr in gprs_subscr_delete
Currently gprs_subscr_delete implicitely calls subscr_put, which
makes the code more complex than necessary (additional subscr_get) in
a few places. It also makes it more difficult to see, whether get/put
are balanced within a function. In addition, the functions are not
named consistently (gprs_subscr_delete vs.
gprs_subscr_put_and_cancel).

This commit changes the semantics of gprs_subscr_delete and
indirectly of gprs_subscr_put_and_cancel to not call subscr_put on
their argument, but to leave that for the caller to do it
explicitely.

It renames gprs_subscr_put_and_cancel to gprs_subscr_cancel to
reflect that change in the name, too.

Sponsored-by: On-Waves ehf
2015-01-26 09:10:06 +01:00
Holger Hans Peter Freyther
1d778fdce3 sgsn: Remove the "permanent" subscriber cache
The subscriber cache would help in case:

  * GPRS DETACH, GPRS ATTACH. In that case we might still
  have some cached authentication tuples we avoid another
  sendAuthenticationInfo request.

  * After a detach the cache expiry would make sure to
  eventually send a purgeMS to the HLR (which might be
  ignored).

At the same time to make the cache work we will need to
make sure to start and stop timers. In case we don't
start we might accumulate subscribers. I am afraid that
the above two benefits do not outweight the complexity
of this implementation.
2015-01-26 09:09:12 +01:00
Holger Hans Peter Freyther
e47d4f6d11 sgsn: Remove MM from the list before gprs_subscr_delete is called
Modify sgsn_mm_ctx_free to remove the entry from the
list as otherwise we might double free the context from
within gprs_subscriber_delete.
2015-01-26 09:08:57 +01:00
Jacob Erlbeck
81ffb740f7 sgsn: Remove inactive LLME/MM after inactivity timeout
Currently old LLMEs and MM contexts that haven't been explicitly
detached or cancelled are not removed until another request with the
same IMSI is made. These stale entries may accumulate over time and
severely compromise the operation of the SGSN.

This patch implements age based LLME expiry, when the maximum age has
been reached, the corresponding MM context is cancelled. If such an MM
context doesn't exist, the LLME is unassigned directly.

The implementation works as follows.
 - llme->age_timestamp is reset on each received PTP LLC message
 - sgsn_llme_check_cb is invoked periodically (each 30s)
 - sgsn_llme_check_cb sets the age_timestamp to the current time if
   it has been reset
 - sgsn_llme_check_cb computes the age and expires the LLME if
   it exceeds gprs_max_time_to_idle()

Ticket: OW#1364
Sponsored-by: On-Waves ehf

[hfreyther: Fix typo in comment LMME -> LLME]
2015-01-26 08:51:50 +01:00
Jacob Erlbeck
841d95f867 gprs: Use a macro value to set the 'Periodic RA update timer'
Currently the T3312 timer is directly set as encoded value when
generating the Attach/RAU Accept messages.

This patch adds GSM0408_T3312_SECS and uses it to set the
information element's value.

Sponsored-by: On-Waves ehf
2015-01-26 08:44:27 +01:00
Jacob Erlbeck
8de9c48c99 gprs: Add 'Negotiated READY timer value' IE to Attach/RAU Accept
Currently this optional IE is omitted, so that the optional
'Requested READY timer value' of the corresponding Request message
is used by the MS (or the default value if this IE is not used).

This patch extends gsm48_tx_gmm_att_ack and gsm48_tx_gmm_ra_upd_ack
to always include the IE set to the default value of T3312 (44s,
see GSM 04.08, table 11.4a).

Ticket: OW#1364
Sponsored-by: On-Waves ehf
2015-01-26 08:42:43 +01:00
Jacob Erlbeck
79af67d7c0 gprs: Add GPRS timer conversion functions
Currently, all GPRS timer values are hard-coded. To make these values
configurable in seconds and to show them, conversion functions from
and to seconds are needed.

This patch adds gprs_tmr_to_secs and gprs_secs_to_tmr_floor. Due to
the limited number of bits used to encode GPRS timer values, only a
few durations can be represented. gprs_secs_to_tmr_floor therefore
always returns the timer value that represents either the exact
number (if an exact representation exists) or the next lower number
for that an exact representation exists.

Sponsored-by: On-Waves ehf
2015-01-26 08:41:52 +01:00
Jacob Erlbeck
37184900e7 gprs: Return 0 from gsup_client_connect if ok or retry timer enabled
Currently the gsup_client_connect return 0 if the call to
ipa_client_conn_open was successful and -errno otherwise. This makes
it difficult for the caller to determine, whether the the whole
operation has been cancelled (currently on EBADF, ENOTSOCK,
EAFNOSUPPORT, EINVAL) or whether the GSUP client will retry to
connect after a timeout. This will cause gprs_gsup_client_create to
destroy the GSUP client object, even if the error might be temporary.

This patch changes the function to return 0 if (and only if)
ipa_client_conn_open was successful or the retry timer has been
started. Since the return value 0 doesn't guarantee, that a
subsequent call to gprs_gsup_client_send will succeed, this shouldn't
break anything.

Sponsored-by: On-Waves ehf
2015-01-26 08:41:52 +01:00
Holger Hans Peter Freyther
9d1a17e15f osmux: Initialize the socket only once
The per BSC code didn't guard against the init already having
been executed. This lead to:

 Adding a osmo_fd that is already in the list.
 <000b> bsc_nat_vty.c:1200 Setting up OSMUX socket

So a new socket got created and the old one leaked. Luckily
Linux appears to allow to bind multiple times so we were able
to just read from the new one. Use the same guard that is used
on the MGCP MGW. Re-order the log message to say "Setting up"
before we actually do that. I manually verified that osmux_init
is called at most once.

The log message was spotted by Roch
2015-01-21 16:56:53 +01:00
Jacob Erlbeck
b194862b62 debian: Fix dependencies
The dependecies do not match the current package names or are
missing:

Build-Depends:
  - renamed libgtp-dev -> libgtp0-dev
  - added   libosmo-netif-dev

Depends:
  - renamed libgtp     -> libgtp0

Other run time dependencies might still be missing and have to be
installed manually.

This is taken from Holger's e744ebd17c3761b5cad81d718d0349f2f820ec66.
In addition, the build-dependency on libgtp-dev is replaced by
libgtp0-dev.
2015-01-21 13:24:38 +01:00
Holger Hans Peter Freyther
9be675ea52 mgcp: Honor the rtp IP_TOS settings for Osmux
Honor the IP_TOS settings for Osmux as well. Re-use the RTP
setting as it makes sense to classify the audio packets the
same way.

Fixes: OW#1369
2015-01-21 11:43:03 +01:00
Jacob Erlbeck
d91934357f sgsn: Restructure the 'update-subscriber' command
This patch drops the following commands:

 - update-subscriber imsi IMSI insert authorized <0-1>
 - update-subscriber imsi IMSI commit

since they are already covered by the 'update-location-result'
sub-command, except that this command doesn't create an new entry if
none is found with the given IMSI.

It adds the following command:

 - update-subscriber imsi IMSI create

which can be used to create a new entry.

Sponsored-by: On-Waves ehf
2015-01-20 16:14:01 +01:00
Jacob Erlbeck
15cc8c8125 sgsn: Fix vty_out newlines
Currently '\n' is used to end lines in the VTY output string
constants instead of inserting VTY_NEWLINE. This leads to incorrect
line starts in error messages.

This patch fixes that accordingly.

Sponsored-by: On-Waves ehf
2015-01-20 16:13:55 +01:00
Jacob Erlbeck
d6267d12d8 sgsn: Add SGSN_ERROR_CAUSE_NONE and use it instead of 0
Currently an error_cause of 0 is being used to indicate normal
operation. Albeit this is not a defined GMM cause, the value is not
explicitly reserved.

This commit adds the macro SGSN_ERROR_CAUSE_NONE and uses it for
initialisation (instead of relying on talloc_zero) and comparisons.
The value is set to -1 to be on the safe side. The VTY code is
updated to set the error_cause when using the
'update-subscriber imsi IMSI update-location-result CAUSE' command.

Sponsored-by: On-Waves ehf
2015-01-20 16:13:48 +01:00
Jacob Erlbeck
2585620857 sgsn: Fix access to subscr in sgsn_auth_update (Coverity)
Currently the access to subscr->sgsn_data->error_cause is not
protected against subscr == NULL like it is done in other code paths
of sgsn_auth_update.

This commit adds a conditional to avoid a NULL-dereference.

Fixes: Coverity CID 1264589

Sponsored-by: On-Waves ehf
2015-01-20 16:13:17 +01:00
Jacob Erlbeck
6be9ffa3b8 sgsn/test: Make assert_substr safer (Coverity)
Currently, if assert_subscr were called with subscr == NULL, the
later call to subscr_put might fail, as Coverity has complained. In
addition, the call to subscr_put would free the subscr object if it
were in the cache with a refcount of 0 at the time assert_substr was
called.

This patch adds a check for the subscr being non-NULL and reorders
the checks, so that the subscr_put comes last.

Fixes: Coverity CID 1264590

Sponsored-by: On-Waves ehf
2015-01-20 16:13:09 +01:00
Jacob Erlbeck
d8a65536ec sgsn: Fix P-TMSI generator's distance of equal values
Currently sgsn_alloc_ptmsi uses rand() to get a new P-TMSI and then
sets to upper 2 MSB. Therefore there is no lower limit of the
distance between 2 identical P-TMSI.

This patch changes the implementation to discard any random value
above 2^30 and to generate a new random number in that case until a
fitting number is found (or a repetition limit is reached). This way,
all number below 2^30 within the PRNG's period are used.

Ticket: OW#1362
Sponsored-by: On-Waves ehf
2015-01-20 16:13:01 +01:00
Jacob Erlbeck
87c7ffccea gprs: Support the full cancellation procedure
Currently no GSUP LocationCancellationResult message is sent back to
the peer (HLR), if the procedure succeeded at the SGSN's side.

This patch adds the missing message and put the whole request
handling of this procedure into a separate function.

Ticket: OW#1338
Sponsored-by: On-Waves ehf
2015-01-20 16:12:52 +01:00
Jacob Erlbeck
4dedb27d7e gprs: Don't create a subscr entry on InsertSubscriberData
Currently gprs_subscr_rx_gsup_message creates a subscriber entry if
such an entry doesn't exist for the IMSI within an
InsertSubscriberData GSUP message. This behaviour is not compliant to
GSM 09.02, 20.3.3.2 (Subscriber data management/SGSN) where it is
defined, that an error ("Unidentified subscriber") shall be returned.

This patch removes the case distinction, so that an existing
subscriber entry is required for all incoming GSUP messages.

Sponsored-by: On-Waves ehf
2015-01-20 16:12:45 +01:00
Jacob Erlbeck
9999fd9026 gprs: Add replies for all GSUP requests
Currently, an incoming GSUP request message isn't answered at all if
it is not handled due to an error or missing implementation.

This patch adds GSUP error replies for these requests (and only for
requests). It also adds tests for these cases.

Note that several of these tests check for
GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL, which will have to be changed, when
the features are implemented.

Sponsored-by: On-Waves ehf
2015-01-20 16:12:39 +01:00
Jacob Erlbeck
f81cacc681 gprs: Block other GSUP procedures during PURGE_MS
GSM 09.02, 19.4.1.4 mandates that no other MAP procedures shall be
started until the PURGE_MS procedure has been completed.

This patch implements this by adding corresponding state and checks
to gprs_subscr_purge, gprs_subscr_location_update, and
gprs_subscr_update_auth_info. If an Update Location or a Send Auth
Info Req procedure is not started because of blocking, the retry
mechanism is aborted to shorten the blocking time. The outstanding
Purge MS procedure itself is not aborted.

Sponsored-by: On-Waves ehf
2015-01-20 16:12:33 +01:00
Jacob Erlbeck
743dec4c0c gprs: Retry PURGE_MS procedure after timeout
Currently, when the PURGE_MS_REQ to the HLR gets lost (e.g. by a
connection or peer failure), the expired subscriber entry will not get
deleted.

This commit adds a retry mechanism then restarts the procedure after
a timeout (currently 10s). The maximum number of retries is limited
(currently to 3 PURGE_MS messages). If none of these procedures is
completed (either with success or error), the subscriber data is
deleted.

Sponsored-by: On-Waves ehf
2015-01-18 18:37:36 +01:00
Jacob Erlbeck
65fa3f73a1 gprs: Use PURGE MS messages
When a subscriber entry is going to be deleted by SGSN and when the
subscriber info has been obtained from a remote peer via GSUP, the
peer should be informed before the entry is really deleted. For this
purpose, MAP defines the PURGE MS procedure (see GSM 09.02, 19.1.4).

This patch adds support for the PURGE_MS_REQ/_ERR/_RES messages and
invokes the procedure when the subscriber entry is going to be
removed. This only applies if GSUP is being used, the Update
Location procedure has been completed successfully, and the
subscriber has not been cancelled. The removal of the entry is
delayed until a PURGE_MS_RES or PURGE_MS_ERR message is received.

Note that GSM 09.02, 19.1.4.4 implies that the subscriber data is not
to be removed when the procedure fails which is not the way the
feature has been implemented.

Note that handling 'P-TMSI freezing' is not implemented.

Ticket: OW#1338
Sponsored-by: On-Waves ehf
2015-01-18 18:33:31 +01:00
Jacob Erlbeck
69d271376c gprs: Implement PURGE_MS GSUP messages
This commit implements the encoding and decoding of the messages

  - Purge MS Request
  - Purge MS Error
  - Purge MS Result

and adds corresponding tests.

Sponsored-by: On-Waves ehf
2015-01-18 18:33:13 +01:00
Jacob Erlbeck
cde0bb27a1 sgsn/doc: Add message definitions for PURGE_MS responses
Currently the definitions of the message PURGE_MS_RES and
PURGE_MS_ERR are missing in the specification.

This patch adds those definitions.

Sponsored-by: On-Waves ehf
2015-01-18 18:29:47 +01:00
Jacob Erlbeck
058bc26e1b sgsn/test: Add checks and reports to detect subscr leakage
This commit adds talloc reports to log remaining NULL chunks after the
terminates. It also adds explicit checks for empty subscriber lists.

Sponsored-by: On-Waves ehf
2015-01-18 18:29:13 +01:00
Jacob Erlbeck
c157ee7d2c sgsn/test: Add test that intercepts gprs_gsup_client_send
This test replaces gprs_gsup_client_send by a custom function, that
emulates a GSUP remote peer by calling gprs_subscr_rx_gsup_message
with responses for all requests. It then executes a full
Attach/Detach cycle.

Sponsored-by: On-Waves ehf
2015-01-18 18:28:20 +01:00
Jacob Erlbeck
0f47b8fae7 gprs: Add expiry timeout for subscriber entries
Set the expiry delay after the subscriber has been deleted (e.g. by
freeing the MM context). If cancelled, the subscriber will be deleted
immediately and no timeout will be set. If the expiry time is set to
SGSN_TIMEOUT_NEVER, no timer will be started and the subscriber entry
will be kept until it is cancelled.

The following VTY command is added to the sgsn node:

  - subscriber-expiry-time <0-999999>    set expiry time in seconds
  - no subscriber-expiry-time            set to SGSN_TIMEOUT_NEVER

The default is an expiry time of 0 seconds, which means that the
subscriber entries are wiped out immediately after an MM context is
destroyed.

Note that unused MM contexts are not expired yet. Therefore the
subscriber will only be expired after a successful MM detach.

Sponsored-by: On-Waves ehf
2015-01-18 18:27:19 +01:00
Jacob Erlbeck
b8fb1409d1 sgsn/test: Refactor subscriber test
The code sequence that checks, whether a subscriber is still
reachable for a given IMSI, is repeated several times.

This patch puts this code sequence into a single function and adds a
check for the IMSI after the entry has been found. In addition,
some comments are extended.

Sponsored-by: On-Waves ehf
2015-01-18 18:26:35 +01:00
Jacob Erlbeck
e1beb6f51d sgsn/test: Fix subscriber cleanup
Currently the subscribers are not really deleted by
cleanup_subscr_by_imsi, but kept in RAM instead.

This patch fixes this and adds a test to verify, that the subscriber
is really deleted afterwards.

Sponsored-by: On-Waves ehf
2015-01-18 18:26:14 +01:00
Jacob Erlbeck
d3cde1ecf4 gprs/test: Move subscr cleanup code into a separate function
Refactor several occurences of the same subscriber cleanup code into
a seperate cleanup_subscr_by_imsi function.

Sponsored-by: On-Waves ehf
2015-01-18 18:26:03 +01:00
Jacob Erlbeck
f06fe29f61 gprs: Pass GMM causes related to the MSC connection
Currently the error causes MSC_TEMP_NOTREACH, NET_FAIL, and
CONGESTION are silently dropped to force the MS to continue. On the
other hand, GSM 04.08/24.008, 4.7.3.1.4 in combination with 4.7.3.1.5,
require the MS to retry the attachment procedure for cause codes
above 15 instead of disabling GPRS. All of the mentioned GMM causes
have codes above 15, so using a REJECT message including the cause
code is a better choice. This way, the retry algorithm based on T3311
(15s, 5 times) and T3302 (default 12min) could be used.

This patch modifies gprs_subscr_handle_gsup_auth_err and
gprs_subscr_handle_gsup_upd_loc_err to proceed like when the access
has beed denied, except that the corresponding subscriber's
information fields are not cleared.

This has been successfully tested which an iphone which enters a
retry loop as it is being described in the specification.

Sponsored-by: On-Waves ehf
2015-01-18 18:23:51 +01:00
Jacob Erlbeck
bf34c67f3f gprs: Use LOGGSUBSCRP and LOGMMCTX for logging in gprs_susbcriber.c
To unify the layout of the logging messages in gprs_subscriber.c,
this patch replaces each LOGP by LOGGSUBSCRP, unless a non-NULL
pointer to a subscr is not available. In those cases, it uses
LOGMMCTXP if a pointer to an MM context is available or LOGP
otherwise.

Sponsored-by: On-Waves ehf
2015-01-18 18:23:21 +01:00
Jacob Erlbeck
4275578570 gprs: Add LOGGSUBSCRP macro to log subscriber info
This patch adds a new logging macro, that logs to DGPRS and provides
a uniform prefix containing the IMSI without using the mm reference.
This is an improvement over using LOGMMCTXP, since the new macro also
provides an IMSI if no MM context is attached.

Sponsored-by: On-Waves ehf
2015-01-18 18:23:04 +01:00
Jacob Erlbeck
bce2061b43 gprs: Let GSUP parser functions return GMM causes on errors
Currently the GSUP message handling function in gprs_subscriber.c and
the functions in gprs_gsup_messages.c are not consistent with respect
to the return codes if an error happens. Albeit all error return
codes are negative, the semantics of the absolute value are not
clearly defined. In addition, some return codes are not passed to the
calling function.

This path changes these functions to always return a negated GMM
cause value in case of errors. Return values of called parser
functions are not longer ignored.

Sponsored-by: On-Waves ehf
2015-01-18 18:22:47 +01:00
Jacob Erlbeck
9aa9991efe gprs: Use the cause value in GSUP error messages
Currently always a cause with the meaning of 'access denied' is
assumed. gprs_subscr_handle_gsup_auth_err just clears the auth
triplets and the authorized flag before calling the update function.
gprs_subscr_handle_gsup_upd_loc_err only clears the authorized flag
and calls the update function. This means, that an MS will not retry
to attach even on temporary network errors.

This patch changes these functions to use the GSUP error cause value
to decide, whether to clear the corresponding subscriber fields, to
just continue with the corresponding update function, or to log,
ignore and not pass the cause to the MS in case the error is directly
related to the GSUP protocol. The subscriber's error_cause field is
updated, if the update function is going to be called. The
error_cause fielt is reset on non-error GSUP messages.

Sponsored-by: On-Waves ehf
2015-01-18 18:20:41 +01:00
Jacob Erlbeck
af3d5c508c sgsn: Pass subscriber error causes to the GMM layer
This patch extends gsm0408_gprs_access_denied and
gsm0408_gprs_access_cancelled to accept GMM cause codes. These are
then passed to the MS, unless gsm0408_gprs_access_cancelled is called
with cause 0 (no error -> updateProcedure).

Since gsm0408_gprs_access_denied uses GMM_CAUSE_GPRS_NOTALLOWED if
the cause is not set, and the subscriber's error_cause is never set
(and thus always 0), the SGSN's behaviour does not change with this
patch.

Sponsored-by: On-Waves ehf

Conflicts:
	openbsc/include/openbsc/gprs_sgsn.h

[hfreyther: Conflict due the removal of the unused
authenticate flag]
2015-01-18 18:14:49 +01:00
Jacob Erlbeck
afcf23001e gprs: Move protocol value_strings to gsm_04_08_gprs.c
Currently the mapping between GSM 04.08 (GPRS) protocol specific
numbers and their textual description was put into gprs_gmm.c and not
exported.

This commit moves the mappings to a new file gsm_04_08_gprs.c,
renames some of them, and exports them via gsm_04_08_gprs.h.

The following identifiers are renamed to match the corresponding type
names:

  - gmm_cause_names -> gsm48_gmm_cause_names
  - gsm_cause_names -> gsm48_gsm_cause_names

Sponsored-by: On-Waves ehf
2015-01-18 18:13:06 +01:00
Jacob Erlbeck
8054799963 sgsn: Show GSUP client info on 'show sgsn'
This commit adds a line to the output of 'show sgsn' if the GSUP
client has been initialized:

  - Remote authorization: [not] connected to HOST:PORT via GSUP

Sponsored-by: On-Waves ehf
2015-01-18 18:12:06 +01:00
Jacob Erlbeck
03b4630348 gprs: Send PING and eventually reconnect
Currently, the reconnect mechanism relies on gsup_client_updown_cb
which in turn gets called based on the OS' view of connection state.

This patch adds a timer based PING mechanism that regularly sends
PING messages and forces a reconnect if a PONG message won't be
received until the next PING message is scheduled. The current ping
interval is 20s.

Sponsored-by: On-Waves ehf

Conflicts:
	openbsc/src/gprs/gprs_gsup_client.c

[hfreyther: Conflicts due the potential memleak fix by me. Removed
another TODO from the code as we stop the ping/pong timer]
2015-01-18 18:11:08 +01:00
Jacob Erlbeck
e154d8bdd4 gprs: Handle incoming IPA CCM message in gsup_client_read_cb
Currently the IPA CCM messages are not handled by the GSUP client.
This means, that the client doesn't answer to PING and ID_GET and
logs notices when receiving PONG or ID_ACK. At least the PING
functionality (remotely originated PING) shall be supported.

This patch extends gsup_client_read_cb by a call to
ipaccess_bts_handle_ccm. Only when the return code is 0, the message
is processed further and checked for an OSMO/GSUP message. ID_GET
messages are answered by a dummy description, where only the
unit_name is set to 'SGSN'.

Sponsored-by: On-Waves ehf
2015-01-18 18:02:09 +01:00
Jacob Erlbeck
69e16b9ea5 gprs: Handle return code of ipa_client_conn_open correctly
The ipa_client_conn_open function does not distinguish between a
connection being already established or waiting for establishment.
In either case, the application gets informed about the connection
state via the updown_cb. The 'up' parameter is only set, if
poll/select consider the socket as writable.

This patch handles both cases equally and fully relies on the
updown_cb to adjust the gsupc obejct state.

Sponsored-by: On-Waves ehf
2015-01-18 17:59:18 +01:00
Jacob Erlbeck
4188c30c4a gprs: Avoid sending stale GSUP requests after reconnect
Currently, messages are added to the tx queue even if the connection
is down for some reason and all of these messages are eventually sent
after a re-connect.  The MS has probably sent several Attach Requests
while the connection was down and will continue doing so. Therefore
these stored messages could be dropped.

This patch clears the queue before re-connecting and also extends
gprs_gsup_client_send to return immediately, when the connection is
not established instead of calling ipa_client_conn_send.

Sponsored-by: On-Waves ehf

[hfreyther: Replaced
	while (!llist_empty(&gsupc->link->tx_queue))
		llist_del(gsupc->link->tx_queue.next);
with new libosmo-abis API]
2015-01-18 17:58:56 +01:00
Jacob Erlbeck
849d0a83e8 gprs: Add automatic re-connect if the GSUP connection is down
Currently the GSUP connection to a server is not restarted if the
connection cannot be established or is terminated during operation.

This commit adds a timer based connection mechanism, basically
consisting of a timer callback that calls gsup_client_connect. The
timer is eventually triggered (up == 0) or cleared (up != 0) by
gsup_client_updown_cb. It adds calls to osmo_timer_del() to
gsup_client_connect and gprs_gsup_client_destroy. The latter is now
called instead of talloc_free in gprs_gsup_client_create on error to
be on the safe side.

Sponsored-by: On-Waves ehf
2015-01-18 17:24:37 +01:00
Jacob Erlbeck
7660ffa29f sgsn/test: Extend tests to simulate lost GSUP requests
This patch extends test_gmm_attach to optionally resend Attach
Requests until the SGSN responds to it instead of calling
OSMO_ASSERT at a few places. The test_gmm_attach_subscr_gsup_auth
test optionally uses this feature. It is called once in either mode.

Sponsored-by: On-Waves ehf
2015-01-18 17:23:59 +01:00
Jacob Erlbeck
3d722450de sgsn/test: Add GMM test for a GSUP based attach procedure
This test calls test_gmm_attach() where the mocked subscriber
functions insert GSUP messages instead of manipulating the
subscriber structure directly.

Sponsored-by: On-Waves ehf
2015-01-18 13:27:02 +01:00
Jacob Erlbeck
e21e184d84 sgsn/test: Add wrapper for gprs_subscr_rx_gsup_message
Currently, several lines of boiler plate are needed around a call to
gprs_subscr_rx_gsup_message.

This patch puts all of this (including the call to
gprs_subscr_rx_gsup_message) into a separate function.

Sponsored-by: On-Waves ehf
2015-01-18 13:25:24 +01:00
Jacob Erlbeck
771573c535 sgsn: Add global require_update_location flag
This flag is used to determine, whether the Update Location procedure
shall be invoked. This is currently only set, when the 'remote'
authorization policy is set. When the flag is set, sgsn_auth_update
will not never be called directly by sgsn_auth_request, if an Attach
Request procedure is pending, even if the remote connection fails for
some reason.

Sponsored-by: On-Waves ehf
2015-01-18 13:23:13 +01:00
Holger Hans Peter Freyther
a071c1ccc0 gprs: Remove now unused authenticate flag
This has been obsoleted by the previous commit. Remove it.
2015-01-18 13:22:37 +01:00
Jacob Erlbeck
9d4f46c975 sgsn: Replace subscr.authenticate by global require_authentication flag
Currently the flag 'authenticate' is managed per subscriber.

This patch replaces that flag by a global cfg.require_authentication
flag that enables/disables the use of the Auth & Ciph procedure for
every subscriber. The flag is set by the VTY, if and only if the
authorization policy is 'remote'.

The VTY command

  - update-subscriber imsi IMSI insert authenticate <0-1>

is removed.

Sponsored-by: On-Waves ehf
2015-01-18 13:18:35 +01:00
Jacob Erlbeck
39f040d62b sgsn: Integrate the GSUP client into the SGSN
This commit adds GSUP client configuration (via VTY), connection set
up, and real message sending.

The following configuration commands are added:

 - gsup remote-ip A.B.C.D            set server IP address
 - gsup remote-port PORT             set server TCP port

Ticket: OW#1338
Sponsored-by: On-Waves ehf
2015-01-18 13:17:50 +01:00
Jacob Erlbeck
bb23dc17f8 gprs: Add GSUP client
This commit adds the client code to get subscriber information from a
remote server. It provides an IPA over TCP connection to transmit and
receive GSUP messages.

Sponsored-by: On-Waves ehf
2015-01-18 13:17:11 +01:00
Jacob Erlbeck
1610626fe9 gprs: Clear GSUP message structures before decoding
Currently the message structure is not cleared before the message is
parsed which can cause information leaking between messages if the
same gprs_gsup_message object is used. Especially list elements (auth
tuples and pdp info) are not replaced by an IE, but the IE is
appended.

This patch uses the assignment operator to clear gprs_gsup_message,
gsm_auth_tuple, and gprs_gsup_pdp_info before using them. This also
replaces the use of memcpy of the latter.

Sponsored-by: On-Waves ehf
2015-01-18 13:17:09 +01:00
Jacob Erlbeck
a2315eebf9 gprs: Always reset auth tuples/pdp infos in gprs_gsup_decode
Currently auth tuples are always appended to the lists when
gprs_gsup_decode is called with a gsup_msg structure. This makes a
test case fail, where the same gsup_msg is used again and again
without clearing it after each use.
Sponsored-by: On-Waves ehf
2015-01-18 13:17:09 +01:00
Jacob Erlbeck
424ffa4806 gprs: Handle empty GSUP messages correctly
Currently, the gprs_gsup_decode function doesn't check the return
value of gprs_shift_v_fixed before using the value pointer. The
function fails, if the GSUP message length (not including IPA
headers) is 0. In this case, a segfault can happen, depending on the
value of the uninitialized 'value' pointer. The test case doesn't
trigger a segfault, but valgrind complains about reading
uninitialized data.

This patch adds a check for the return value that would return with
an error code if the shift function failed.

Sponsored-by: On-Waves ehf
2015-01-18 13:17:09 +01:00
Jacob Erlbeck
0572ee045d gprs/test: Add tests for invalid GSUP messages
Currently, the tests only use valid GSUP messages. This does not
check the robustness of the parser.

This commit adds a test for truncated messages and another for
modified messages.

Thanks to Holger for the basic truncation test.

Sponsored-by: On-Waves ehf
2015-01-18 13:17:09 +01:00
Jacob Erlbeck
f0b06d82cd sgsn/test: Fix msgb freeing in mocked bssgp_tx_dl_ud
Currently the mocked bssgp_tx_dl_ud function used for testing in
sgsn_test.c does not free the msg as it is done by the original
function. This leads to a msgb leak in the test.

This patch fixes the test code accordingly and uncomments the
assertion that checks for left-over msgbs.

Sponsored-by: On-Waves ehf
2015-01-18 13:17:09 +01:00
Jacob Erlbeck
07de92e2c0 sgsn/test: Add checks and reports to detect msgb leakage
This commit adds talloc reports to log remaining chunks after the
testing has been finished. It also adds a (currently disabled) check,
that no msgbs are allocated after running the tests.

Sponsored-by: On-Waves ehf
2015-01-18 13:17:08 +01:00
Jacob Erlbeck
a6ddc2d99f gprs: Add subscriber functions to create/handle GSUP messages
This patch extends gprs_subscr_query_auth_info and
gprs_subscr_location_update to create GSUP messages with the help of
a static gprs_subscr_tx_gsup_message function. A corresponding
gprs_subscr_rx_gsup_message is added which takes a messages, gets the
subscr, and updates it accordingly.

Sponsored-by: On-Waves ehf

[hfreyther: Added a msgb_free gprs_subscr_tx_gsup_message]
2015-01-10 21:26:18 +01:00
Jacob Erlbeck
f3a271fa73 gprs: Add encoder/decoder for the Subscriber Update Protocol
This patch adds functions to encode and decode GSUP messages. This
does not include the layer 1 framing (IPA). The messages so far
supported are: send_auth_info_*, update_location_*,
location_cancellation_*.

Sponsored-by: On-Waves ehf
2015-01-10 21:26:18 +01:00
Jacob Erlbeck
46684dcfd2 sgsn/doc: Add IPA default parameters
This commit adds the default protocol identifiers that should be used
for GSUP by the IPA protocol.

Sponsored-by: On-Waves ehf
2015-01-10 21:26:18 +01:00
Jacob Erlbeck
0024cee9f8 sgsn/doc: Add protocol specification for remote subscriber update
This is the first version of the specification for the GPRS
Subscriber Update Protocol.

Sponsored-by: On-Waves ehf
2015-01-10 20:55:46 +01:00
Jacob Erlbeck
17fb3d46ff sgsn: Fix VTY command error handling (Coverity)
Currently the result of the osmo_hexparse function in
update_subscr_insert_auth_triplet is not handled correctly. There is
a misplaced leading exclamation mark in a few conditional
expressions. This effectively disables the error checks, as it is
noticed by Coverity ("Missing parentheses" followed by "Logically
dead code").

This patch removes the exclamation marks.

Fixes: Coverity CID 1260435 and CID 1260434
Sponsored-by: On-Waves ehf
2015-01-10 20:55:04 +01:00
Holger Hans Peter Freyther
bb06eb9d7c meas: Unbreak the build once more
The code assumes that sqlite3.h is in the standard include
path. Maybe sqlite3 wasn't installed or resides in a non
standard (/usr/local) location? Fix the build as it has been
broken since 1st of January.
2015-01-10 09:54:30 +01:00
Harald Welte
a67704753a Revert "debug.c: use new libosmocore features to print and save log filter"
This reverts commit c598e6e0a6.

It introduced a dependency from libcommon to libosmovty, which we don't
want
2015-01-05 14:15:16 +01:00
Harald Welte
0c4e400d2f meas_pcap2db.c: Fix build without CDK
Spotted by Jacob Erlbeck.
2015-01-05 14:13:16 +01:00
Harald Welte
c598e6e0a6 debug.c: use new libosmocore features to print and save log filter 2015-01-05 14:05:32 +01:00
Harald Welte
a9e420e93d RSL: Change "... is back in operation" to an INFO level message 2015-01-05 14:05:32 +01:00
Harald Welte
1dcc2603e9 Don't return an error to caller if we are out of lchan on CHAN RQD
This is a normal situation under high load: The BTS is out of resources
and the BSC cannot allocate any dedicated channel.  We may send an IMM
ASS REJECT back to the MS.  All well within normal parameters, not an
error that needs to be reported back to the caller, who propagates it
all the way up to libosmo-abis.
2015-01-05 14:05:32 +01:00
Harald Welte
e5d2c60ae6 SMS: Attempting to send SMS is not a NOTICEable event 2015-01-05 14:05:32 +01:00
Holger Hans Peter Freyther
6995f24831 logging: Only compare the subscr address
Move the "logging filter imsi IMSI" into the BTS/NITB code to
allow to set the gsm_subscriber and only compare it. This way
we simply compare the subscriber address and don't have to care
if the subscriber data is still valid.
2015-01-02 11:43:06 +01:00
Holger Hans Peter Freyther
b7ccac4d62 logging: Set the context for paging requests as well. 2015-01-02 11:43:06 +01:00
Holger Hans Peter Freyther
454140e7fc lchan: Remember why a channel is broken using static strings
Remember why a channel is being marked as broken. So we can
maybe understand what happend.
2015-01-02 11:43:06 +01:00
Holger Hans Peter Freyther
52fa7bd2da misc: Ignore new binaries 2015-01-02 11:43:06 +01:00
Holger Hans Peter Freyther
c6e32ad0b8 Partial revert "Fix most compiler warnings with gcc-4.9.2"
Most of the "fixes" have nothing to do with gcc-4.9.2 but are a
question of ABI/Architecture (e.g. x86 vs. AMD64). Revert these
for now.

This partially reverts commit 7b1d25a11e.

abis_test.c: In function ‘test_simple_sw_config’:
abis_test.c:68:2: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘int’ [-Wformat=]
  printf("Start: %ld len: %zu\n", descr[0].start - simple_config, descr[0].len);
  ^
abis_test.c: In function ‘test_dual_sw_config’:
abis_test.c:111:2: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘int’ [-Wformat=]
  printf("Start: %ld len: %zu\n", descr[0].start - dual_config, descr[0].len);
  ^
abis_test.c:115:2: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘int’ [-Wformat=]
  printf("Start: %ld len: %zu\n", descr[1].start - dual_config, descr[1].len);
  ^
abis_test.c: In function ‘test_sw_selection’:
abis_test.c:132:2: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘int’ [-Wformat=]
  printf("Start: %ld len: %zu\n", descr[0].start - load_config, descr[0].len);
  ^
abis_test.c:136:2: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 2 has type ‘int’ [-Wformat=]
  printf("Start: %ld len: %zu\n", descr[1].start - load_config, descr[1].len);
2015-01-02 11:42:38 +01:00
Harald Welte
c83f0276b3 Merge branch 'laforge/meas_vis'
I'm merging this code, as it is proven to be very useful.  The only
reason to keep it out of master was the fact that the UDP data
structures it sends are non-portable, so you can only run it reliably on
localhost or between identical systems (hardware/compiler/os).

As this hasn't been fixed in the past >= 2 years, I am merging the code
now anyway.  We can still introduce a portable protocol by increasing
the protocol  version at a later point.

There are two options:
a) we make 'struct gsm_meas_rep' portable.  This requires an ABI
   change with libosmocore, as it contains struct gsm_meas_rep_unidir :(

b) we introduce a completely separate wire format with corresponding
   encoding and decoding functions.
2015-01-01 13:23:49 +01:00
Harald Welte
8db0788896 meas_feed.c: Fix compiler warning 2015-01-01 13:06:48 +01:00
Harald Welte
dfbc42c261 meas_feed: add osmo-meas-udp2db for realtime feed into database
This tool can save the meas_feed messages from UDP port 8888 directly to
a sqlite3 database for further analysis.
2015-01-01 13:03:03 +01:00
Harald Welte
dc9b4e9ebf meas_feed: Add tool to read meas_feed PCAP and write it to sqlite3
In fact, the DB write code has been split out so we could later also
have a binary that would listen to realtime meas_feed packets and stuff
them into a database without any intermediate PCAP step.

The database schema contains a couple of convenience wrapper views, most
notably the "overview" view.
2015-01-01 13:03:03 +01:00
Harald Welte
7465e4c2e1 build meas_vis only if libcdk is available 2015-01-01 13:03:03 +01:00
Harald Welte
61c9156a74 meas_vis: Add header and print TA + TO values 2015-01-01 13:03:03 +01:00
Harald Welte
98ba6359a1 meas_vis: assign bar colors depending on level, display RxQual 2015-01-01 13:03:03 +01:00
Harald Welte
b4771a6871 Initial support for export + curses-visualization of measurements
This extends osmo_nitb to offer a UDP feed of real-time measurement
reports, which can be used by (a variety of) external tools for
visualization or other processing.

We also add a small ncurses based tool (meas_vis) which shows a
baragraph display of the last few mobile stations that were active,
indicating their uplink/downlink receive level and quality.

<WARNING>
This sends non-portable structures like gsm_meas_rep over UDP
and assumes the receiver has identical alignment and endianness!  Before
this feature is merged, it either needs to be converted to a unix domain
socket (but they don't do multicast, which would be nice) or the wire
format needs to change into something portable with defined alignment
and encoding
</WARNING>
2015-01-01 13:03:03 +01:00
Holger Hans Peter Freyther
7ff77ec713 smscb: Prepare to fill in the info for CBCH in SI4
Pass the number of bytes the rest octet for si4 should
fill.
2015-01-01 12:57:35 +01:00
Harald Welte
f86852ce0b chan_alloc: remove ts_alloc() and ts_free()
The idea of ts_alloc()/ts_free() dates back to the very early days of
OpenBSC, where we didn't yet have a fixed PCHAN type assigned for every
lchan in a BTS.  However, ever since, PCHAN types (channel combinations)
are configured by OML in a certain way, and we only allocate LCHANs
inside PCHANs of a matching type.  There should be no PCHANs with
type GSM_PCHAN_NONE, unless those that you don't want to use for
administraive reasons or the like.
2015-01-01 12:46:26 +01:00
Harald Welte
5468f76861 convert away from deprecated gsm_7bit_{encode,decode}() functions
which removes yet another bunch of compiler warnings.
2015-01-01 12:41:39 +01:00
Harald Welte
7b1d25a11e Fix most compiler warnings with gcc-4.9.2 2015-01-01 12:32:03 +01:00
Harald Welte
7b129e76ce rtp_proxy: Remove dead code
commit 65be6de155 removed the RTP
timesetamp mangling and thus the only caller to tv_difference(),
which can now be removed, too.
2015-01-01 12:20:21 +01:00
Harald Welte
c3e66ff5c3 chan_alloc: Fix missing break statement
Fixes: Coverity CID 1261354
2015-01-01 12:15:33 +01:00
Harald Welte
c3f0cb38cf chan_alloc.c: Don't remove SDCCH/8 without CBCH
In commit 30f1f37638 we wanted to add
support for SDCCH/8+CBCH, not replace the existing SDCCH/8 with the new
CBCH-enabled configuration.
2015-01-01 12:13:42 +01:00
Daniel Willmann
979ac86095 libbsc/chan_alloc: Fix size of pchan to hold the +CBCH channels as well
show net with an CCCH+SDCCH/4+CBCH channel active caused bts_chan_load to read
from invalid memory. Fix this by making sure the pchan array is large enough.

==30346==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff9bdc5dc8 at pc 0x5aeece bp 0x7fff9bdc5350 sp 0x7fff9bdc5348
READ of size 4 at 0x7fff9bdc5dc8 thread T0
    #0 0x5aeecd in bts_chan_load /home/alphaone/scm/osmo/openbsc/openbsc/src/libbsc/chan_alloc.c:490
    #1 0x5af706 in network_chan_load /home/alphaone/scm/osmo/openbsc/openbsc/src/libbsc/chan_alloc.c:511
    #2 0x4b7410 in net_dump_vty /home/alphaone/scm/osmo/openbsc/openbsc/src/libbsc/bsc_vty.c:208
    #3 0x4b5f23 in show_net /home/alphaone/scm/osmo/openbsc/openbsc/src/libbsc/bsc_vty.c:227
    #4 0x7fdabaa425bd in cmd_execute_command_real /home/alphaone/scm/osmo/libosmocore/src/vty/command.c:2042
    #5 0x7fdabaa3f124 in cmd_execute_command /home/alphaone/scm/osmo/libosmocore/src/vty/command.c:2077
    #6 0x7fdabaa850e9 in vty_command /home/alphaone/scm/osmo/libosmocore/src/vty/vty.c:402
    #7 0x7fdabaa75962 in vty_execute /home/alphaone/scm/osmo/libosmocore/src/vty/vty.c:666
    #8 0x7fdabaa6d947 in vty_read /home/alphaone/scm/osmo/libosmocore/src/vty/vty.c:1408
    #9 0x7fdabaa9165f in client_data /home/alphaone/scm/osmo/libosmocore/src/vty/telnet_interface.c:119
    #10 0x7fdaba7860b6 in osmo_select_main /home/alphaone/scm/osmo/libosmocore/src/select.c:160
    #11 0x43c656 in main /home/alphaone/scm/osmo/openbsc/openbsc/src/osmo-nitb/bsc_hack.c:355
    #12 0x7fdab92604bc (/lib64/libc.so.6+0x224bc)
    #13 0x43b6cc (/home/alphaone/local/osmo-asan/bin/osmo-nitb+0x43b6cc)
Address 0x7fff9bdc5dc8 is located in stack of thread T0 at offset 232 in frame
    #0 0x4b5faf in net_dump_vty /home/alphaone/scm/osmo/openbsc/openbsc/src/libbsc/bsc_vty.c:182
  This frame has 3 object(s):
    [32, 40) ''
    [96, 104) ''
    [160, 224) 'pl'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /home/alphaone/scm/osmo/openbsc/openbsc/src/libbsc/chan_alloc.c:490 bts_chan_load
2014-12-30 12:15:08 +01:00
Daniel Willmann
695675f539 libbsc/system_information.c: Fix off-by-one error in si4 generation with CBCH enabled
==25637==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff3f587c43 at pc 0x5bf591 bp 0x7fff3f587630 sp 0x7fff3f587628
READ of size 4 at 0x7fff3f587c43 thread T0
    #0 0x5bf590 in tv_fixed_put /home/alphaone/local/osmo-asan/include/osmocom/gsm/tlv.h:237
    #1 0x5b7e14 in generate_si4 /home/alphaone/scm/osmo/openbsc/openbsc/src/libbsc/system_information.c:607
    #2 0x5b488b in gsm_generate_si /home/alphaone/scm/osmo/openbsc/openbsc/src/libbsc/system_information.c:882
    #3 0x4cb247 in gsm_bts_trx_set_system_infos /home/alphaone/scm/osmo/openbsc/openbsc/src/libbsc/bsc_init.c:166
    #4 0x4d3c26 in bootstrap_rsl /home/alphaone/scm/osmo/openbsc/openbsc/src/libbsc/bsc_init.c:272
    #5 0x4ced44 in inp_sig_cb /home/alphaone/scm/osmo/openbsc/openbsc/src/libbsc/bsc_init.c:316
    #6 0x7f4f15b563d7 in osmo_signal_dispatch /home/alphaone/scm/osmo/libosmocore/src/signal.c:105
    #7 0x7f4f156c0e3f in e1inp_int_snd_event (/home/alphaone/local/osmo-asan/lib/libosmoabis.so.4+0x17e3f)
    #8 0x7f4f156be7e5 in e1inp_event (/home/alphaone/local/osmo-asan/lib/libosmoabis.so.4+0x157e5)
    #9 0x583a6a in ipaccess_sign_link /home/alphaone/scm/osmo/openbsc/openbsc/src/libbsc/bts_ipaccess_nanobts.c:675
    #10 0x7f4f156e63b0 in handle_ts1_read (/home/alphaone/local/osmo-asan/lib/libosmoabis.so.4+0x3d3b0)
    #11 0x7f4f156e4f4e in ipaccess_fd_cb (/home/alphaone/local/osmo-asan/lib/libosmoabis.so.4+0x3bf4e)
    #12 0x7f4f15b540b6 in osmo_select_main /home/alphaone/scm/osmo/libosmocore/src/select.c:160
    #13 0x43c656 in main /home/alphaone/scm/osmo/openbsc/openbsc/src/osmo-nitb/bsc_hack.c:355
    #14 0x7f4f1462e4bc (/lib64/libc.so.6+0x224bc)
    #15 0x43b6cc (/home/alphaone/local/osmo-asan/bin/osmo-nitb+0x43b6cc)
Address 0x7fff3f587c43 is located in stack of thread T0 at offset 483 in frame
    #0 0x5b712f in generate_si4 /home/alphaone/scm/osmo/openbsc/openbsc/src/libbsc/system_information.c:580
  This frame has 8 object(s):
    [32, 40) ''
    [96, 104) ''
    [160, 164) 'rc'
    [224, 232) 'si4'
    [288, 296) 'cbch_lchan'
    [352, 360) 'restoct'
    [416, 420) 'l2_plen'
    [480, 483) 'cd'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /home/alphaone/local/osmo-asan/include/osmocom/gsm/tlv.h:237 tv_fixed_put
2014-12-30 12:14:25 +01:00
Harald Welte
142d12d829 move gsm_bts_get_cbch() to gsm_data_shared() as its needed in osmo-bts 2014-12-30 00:35:44 +01:00
Harald Welte
30f1f37638 Add basic support for CBCH / SMS-CB (Cell Brroadcast)
We can now configure the pyisical channel types for CBCH either in the
CCCH+SDCCH4 or in the SDCCH8 chanel combination.

Depending on whether a CBCH exists on the BTS, we also generate the SI4
with matching CBCH channel description to notify the phones of the
existance of the CBCH.

There is now a VTY command how a SMS-CB message can be sent to a given
BTS.

We do not yet have any logic at all for actual scheduling of multiple
CBCH RSL messages towards one or multiple BTSs yet, though.
2014-12-30 00:35:28 +01:00
Holger Hans Peter Freyther
65be6de155 rtp: Remove the "correction" of timestamps
We tend to comment out this code every XXC3, let's just get rid
off it. The nanoBTS has a rather odd timing behavior. Jacob has
spent hours this summer to trial/document/fix it in the MGCP code
and this code is not getting close to working around the ip.access
audio issues.

If someobody still wants to use the nanoBTS then he should help
to have the MGCP MGW use/share code with the rtp_proxy.c
2014-12-25 18:47:27 +01:00
Holger Hans Peter Freyther
be8e775776 db: Extend the test to mark a SMS as delivered and verify it
Mark the SMS as delivered, then free it and try to get an
undelivered SMS to that subscriber again and make sure it
is failing.
2014-12-25 17:33:30 +01:00
Jacob Erlbeck
98a95ac17f sgsn: Add a subscriber based authentication phase
This implements the MAP way of subscriber validation when the MS
tries to perform an Attach Request:

  1. perform authentication (optionally invoke the sendAuthInfo
     procedure), starts the Auth & Ciph procedure
  2. perform update location
  3. insert subscriber data
  4. finish the update location
  5. Attach Accept / Attach Reject

The authentication triplets are used and eventually updated if all of
them have been used.

This is currently accessible via the VTY interface by the following
commands:

  - update-subscriber imsi IMSI update-auth-info
  - update-subscriber imsi IMSI update-location-result (ok|ERR-CAUSE)

Sponsored-by: On-Waves ehf
2014-12-24 16:50:30 +01:00
Jacob Erlbeck
7921ab1593 sgsn: Add support for authentication triplets
This commit add data structures, functions, initialization, and VTY
commands for per subscriber authentication triplets.

The following VTY command is added:

  - update-subscriber imsi IMSI \
    insert auth-triplet <1-5> sres SRES rand RAND kc KC

Note that the triplets are not really used by the SGSN yet.

Sponsored-by: On-Waves ehf
2014-12-24 16:50:16 +01:00
Jacob Erlbeck
7dba11fe32 sgsn: Be more tolerant with state and SUSPEND/RESUME
Currently, when a BSSGP SUSPEND is received and the corresponding MM
context is already in the state GMM_REGISTERED_SUSPENDED, a
SUSPEND_NACK is returned which is not covered by GSM 08.18, 7.4.1.
The same goes for RESUME in the state GMM_REGISTERED_NORMAL.

This commit changes gprs_gmm_rx_suspend and gprs_gmm_rx_resume to not
complain (and thus answer a NACK) when the MM context is either in
GMM_REGISTERED_SUSPENDED or GMM_REGISTERED_NORMAL.

Note that GSM 08.18, 7.4.1 and 7.5.1 only mention to send an NACK if
the MS is not known. Even with this patch, the SGSN returns a NACK if
either the MS is unknown _or_ the MM context ist not in one of the
state GMM_REGISTERED_SUSPENDED and GMM_REGISTERED_NORMAL.

Sponsored-by: On-Waves ehf
2014-12-23 15:15:13 +01:00
Jacob Erlbeck
3ea2260d00 sgsn: Log requested state change in sgsn_auth_update
Sponsored-by: On-Waves ehf
2014-12-23 15:14:36 +01:00
Jacob Erlbeck
4b59d24f4f openbsc: Ignore generated coverage analysis files
This patch adds *.gcda and *.gcno to .gitignore to skip files that
are generated by gcc --coverage and related tools.

Sponsored-by: On-Waves ehf
2014-12-23 15:12:42 +01:00
Jacob Erlbeck
697a534ed6 gprs: Add gprs_shift_tlv function
This function is similar to gprs_match_tlv with the exception, that
the tag is not compared but returned in *tag instead.

Sponsored-by: On-Waves ehf
2014-12-23 15:10:24 +01:00
Jacob Erlbeck
dcfd456640 gprs: Move TLV parser functions to gprs_utils.c and rename them
Currently the parser functions for single information elements are
defined within gprs_gb_parse.c and not exported explicitely. In
addition they are named like libosmocore's TLV parser functions and
do not have a proper name prefix. Since it is planned to use them for
other protocols, they need to be globally accessible.

This patch moves them to gprs_utils.c and renames them.

The new names are:
    lv_shift             -> gprs_shift_lv
    v_fixed_shift        -> gprs_shift_v_fixed
    lv_shift             -> gprs_shift_lv
    v_fixed_shift        -> gprs_shift_v_fixed

In the long term, these functions should be moved to libosmocore (and
renamed again).

Sponsored-by: On-Waves ehf
2014-12-23 15:08:52 +01:00
Jacob Erlbeck
c939196557 sgsn: Add missing LF in log message
Sponsored-by: On-Waves ehf
2014-12-23 15:07:54 +01:00
Holger Hans Peter Freyther
22fd3cd0de ho: Copy the multirate config to the new lchan
The new lchan will be in speech mode already but for AMR we will
need to provide a working multirate config in the channel activation,
otherwise the channel act might be nacked.

Copy the config from the current lchan into the new lchan. The
abis code simply added the mrconf if the speech mode was amr.
Before this commit the invalidate mrconf with all zeroes was
copied/sent.
2014-12-18 18:33:11 +01:00
Holger Hans Peter Freyther
d30ed6b6f2 ho: Make sure the timer is always stopped
In case of a ho_chan_activ_nack (sent due another bug inside
both sysmobts and openbsc) the code would not stop the timer
but free the datastructure. This can lead to a clear segfault
when the timer has expired. Create a "free" function which is
responsible to detach the handover structure, stop the timer
(which is idempotent) and free the structure.
2014-12-17 21:21:36 +01:00
Holger Hans Peter Freyther
f7e23c5ff7 bts: When one link drops.. check what needs to be dropped
In case a BTS is dropped, iterate over the list of BTS and check
if a dependency is now missing and then drop the BTS. This check
could lead to check of 256*256 checks (e.g. all BTS on each other
in the chain and the master is being dropped). The performance
aspect of it doesn't matter for our usecase. We expect to have
pairs of BTS right now.
2014-12-17 15:50:11 +01:00
Holger Hans Peter Freyther
c22930e24b bts: Add some simple dependency between different BTS
E.g. for the sysmoBTS2050 we have the requirement that the first
board connects before the second due clocking. The easiest point
to enforce this is the BSC. Add a simple bitmask based system to
allow to express dependencies for IP based systems.
2014-12-17 14:46:17 +01:00
Holger Hans Peter Freyther
27ca0436ac bts: Remove unused fields from the trx structure
These have either never been used or were replaced with a
more generic approach.
2014-12-10 14:38:43 +01:00
Jacob Erlbeck
2e5e94c328 sgsn: Support subscriber based authentication
This commit mainly extends sgsn_auth.c to use and support the
auth_state SGSN_AUTH_AUTHENTICATE. It will be activated when IMSI and
IMEI are available, authentication is required
(subscr->sgsn_data->authenticate is set), but the MM context is not
marked as authenticated. If the state has been set to
SGSN_AUTH_AUTHENTICATE and sgsn_auth_update() is called, the GMM
layer will be informed by invoking gsm0408_gprs_authenticate().

Sponsored-by: On-Waves ehf
2014-12-10 12:45:22 +01:00
Jacob Erlbeck
4adb136da6 sgsn: Integrate Auth & Ciph into gsm48_gmm_authorize
Currently the Authentication and Ciphering procedure is not yet
invoked by the GMM layer.

This patch starts this procedure from within gsm48_gmm_authorize when
the mm->auth_state has been set to SGSN_AUTH_AUTHENTICATE and a call
to gsm0408_gprs_authenticate has been issued directly or indirectly
by the call to sgsn_auth_request.

Sponsored-by: On-Waves ehf
2014-12-10 12:44:05 +01:00
Jacob Erlbeck
665acd1dbd sgsn: Do not 'commit' implicitely when executing 'insert'
Currently the gprs_subscr_update function is called when the
'update-subscriber ... insert ...' command is executed. This will
eventually notify the GMM layer which is rather the purpose of the
'commit' command.

This patch removes the call from update_subscr_insert.

Sponsored-by: On-Waves ehf
2014-12-10 12:42:36 +01:00
Holger Hans Peter Freyther
416c08f9ed nat: Fix copy and paste in the test code
The test didn't test that the access-list has been properly
removed. Fix the test to only remove the list once and verify
that it is gone.
2014-12-09 19:13:00 +01:00
Jacob Erlbeck
a1e0373224 sgsn: Put SGSN related subscriber data into separate struct
There will be an increasing number of SGSN related fields per
subscriber. Instead of extending gsm_subscriber accordingly, a single
struct sgsn_subscriber_data object is assigned to it. The talloc
context used to allocated that object is the subscr object itself.
Therefore it will be freed automatically along with the subscr
object.

Sponsored-by: On-Waves ehf
2014-12-09 10:01:08 +01:00
Jacob Erlbeck
207f4a5deb sgsn: Add VTY commands to manage subscriber cache
This adds the following commands to the ENABLE node:
  - show subscriber cache
  - update-subscriber imsi IMSI insert authorized (0|1)
  - update-subscriber imsi IMSI cancel
  - update-subscriber imsi IMSI commit

These commands are mainly testing tools and maintenance helpers. The
update commands work asynchronously and can be used to complete a
pending update request or to terminate an existing connection. The
'insert' command just update the subscriber records but does not
notify the GMM layer. Invoke the 'commit' command to continue with
pending procedures.

Note that the subscriber cache is not stored persistently and will
always be empty after an SGSN restart.

Sponsored-by: On-Waves ehf
2014-12-09 10:00:41 +01:00
Jacob Erlbeck
98647ca0ef sgsn: Add gsm0408_gprs_access_cancelled
This function is called to delete an established MM context
silently without invoking a detach procedure.

It is called when a subscriber is cancelled by the HLR. This
generally happens, when an MS has moved to another routing area and
has to use another SGSN.

Sponsored-by: On-Waves ehf
2014-12-09 09:48:25 +01:00
Jacob Erlbeck
be2c8d9358 sgsn: Integrate subscriber handling into the SGSN
This commit adds a new authorization policy 'remote' and uses
the subscriber cache for authorization when this policy is being used.

Note that there is no remote backend implemented yet. After the
IMSI/IMEI have been acquired, a request would be sent to the remote
peer. The attach/auth-ciph procedure continues when authorization
info has been received from the peer. This means, that
gprs_subscr_update() must be called then to tell the GMM layer
that it can proceed. A later commit will add VTY commands to do this
manually.

Sponsored-by: On-Waves ehf
2014-12-09 09:27:20 +01:00
Jacob Erlbeck
33b6dadc88 sgsn: Add gprs_subscriber.c
This patch adds GPRS specific functions for gsm_subscriber objects
(allocation, retrieval, deletion) and subscriber data
requests/updates. The sgsn_update_subscriber_data callback is used to
notify the sgsn about updates and is extended by a parameter that
passes a reference to a gsm_subscriber.

Sponsored-by: On-Waves ehf
2014-12-09 09:23:11 +01:00
Jacob Erlbeck
70d8e31a74 msc: Add per subscriber keep_in_ram flag
Currently the keep_subscr flag in gsm_subscriber_group refers to a
whole group of subscribers which makes it difficult to really delete
single entries if the flag is set.

This patch adds a keep_in_ram field to gsm_subscriber which allows for
keeping subscriber objects in RAM while deleting others.

Note that really deleting an entry requires that both flags
(subscr_group->keep_subscr and subscr->keep_in_ram) are set to 0. So
only the latter should be used if a specification requires the
deletion of a subscriber entry.

Sponsored-by: On-Waves ehf
2014-12-09 09:08:28 +01:00
Jacob Erlbeck
901c40f550 sgsn: Remove warnings
Remove warnings related to the SGSN specific code.

Sponsored-by: On-Waves ehf
2014-12-09 08:59:36 +01:00
Jacob Erlbeck
af792d6bb2 msc: Add net parameter to trans_alloc
The trans_alloc function still uses the subscr object to access the
network object.

This patch adds an explicit net parameter to this function and
removes the access to subscr to obtain it.

Sponsored-by: On-Waves ehf
2014-12-09 08:59:29 +01:00
Jacob Erlbeck
8ff3fb04f2 sgsn: Do authentication based on SRES values
Currently the SRES value in the Auth & Ciph Response is ignored.

This patch checks the SRES value in response against the value stored
in mm->auth_triplet.sres. If they don't match, an Auth & Ciph Reject
message is sent to the MS. If they match, the mm->is_authenticated
flag is set.

Note that the procedure will not be started yet.

Sponsored-by: On-Waves ehf
2014-12-08 10:51:38 +01:00
Jacob Erlbeck
bd0cf1190a sgsn: Change Auth&Ciph timer handling
Currently mmctx_timer_start is called from within
gsm48_tx_gmm_auth_ciph_req which differs from the way e.g. the
identification procedure is implemented. It also makes it more
difficult to restart the procedure after timeout, which is not
implemented yet. In addition, the timer is not properly stopped when
an AUTH & CIPH response is received.

This patch removes this timer start from gsm48_tx_gmm_auth_ciph_req,
adds the retransmission of Auth & Ciph requests to the timer callback
function, and properly stops the timer in
gsm48_rx_gmm_auth_ciph_resp.

Sponsored-by: On-Waves ehf
2014-12-08 10:50:52 +01:00
Jacob Erlbeck
65d8273bf3 sgsn: Fix and enable auth/ciph message generation
Currently gsm48_tx_gmm_auth_ciph_req/_rej are commented out. In
addition, gsm48_tx_gmm_auth_ciph_req uses a wrong encoding (two byte TV instead of two nibbles TV) of the CKSN information element.

This patch fixes the encoding of the CKSN IE and enables the
functions mentioned above.

Sponsored-by: On-Waves ehf
2014-12-08 10:49:17 +01:00
Jacob Erlbeck
0acc0018d9 bsc/test: Add tests for gsm_subscriber base
This commit adds test for the generic part of gsm_subscriber like
reference counting and flag usage.

Sponsored-by: On-Waves ehf
2014-12-05 15:16:59 +01:00
Jacob Erlbeck
1e30a28e51 msc: Add and use gsm_subscriber_group
Currently every subcriber object directly refers to the gsm_network
which contains a flag shared by every related subscriber
(keep_subscr). This adds a dependency on gsm_network even if only the
function defined in gsm_subscriber_base.c are used.

This patch adds a new struct gsm_subscriber_group which contains the
keep_subscr flag and a back reference to the network object. The
latter is not dereferenced in gsm_subscriber_base.c, so it can safely
be set to NULL when only that part of the gsm_subscriber API is being
used. It also changes that API to use gsm_subscriber_group instead of
gsm_network parameters.

Since there are some places where a pointer to the gsm_network is
needed but where only a gsm_subscriber is available, a 'net' back
pointer is added to the group struct, too. Nevertheless subscr group
and network could be separated completely, but this is not the topic
of this commit.

Sponsored-by: On-Waves ehf
2014-12-05 14:59:02 +01:00
Jacob Erlbeck
dae1f64ba6 msc: Don't use the subscriber to access the net object
Sponsored-by: On-Waves ehf
2014-12-05 14:58:41 +01:00
Jacob Erlbeck
f07c605361 msc: Add net back pointer to gsm_trans
Currently the net pointer is obtained from trans->subscr->net. On the
other hand, the list gsm_trans object is managed by the net object.

This patch adds the back pointer to the structure and replaces all
trans->subscr->net by trans->net expressions. In trans_alloc() the
trans->net pointer is obtained from the subscr object.

Sponsored-by: On-Waves ehf
2014-12-05 14:56:35 +01:00
Holger Hans Peter Freyther
1f6cce772e ctrl: Allow to query if the OML link is connected or not
Related: SYS#798
2014-12-05 14:52:57 +01:00
Holger Hans Peter Freyther
5eebb7a814 ctrl: Add command to get the current load of a BTS
Add a command and test to see the current channel load and
available channels per BTS.

Related: SYS#798
2014-12-05 14:52:57 +01:00
Jacob Erlbeck
de4bbc7146 sgsn/test: Add test case for unexpected Detach Accepts
The commit "sgsn: Don't send XID reset after Detach Accept" fixed the
SGSN to not respond to a Detach Accept message when there is no MM
context.

This patch adds a test case to verify, that there is really no
message sent in that case.

The test fails when the commit mentioned aboved is reverted.

Sponsored-by: On-Waves ehf
2014-12-02 09:18:45 +01:00
Jacob Erlbeck
aec03a1f13 sgsn/test: Don't rely on the actual PRNG sequence
Currently the expected P-TMSI generated by the SGSN is hard-coded
into the test. This adds a dependency on the implementation of rand()
and thus the libc used. This breaks the test e.g. on FreeBSD.

This patch modifies test_gmm_attach() to srand(1) first, generate the
P-TMSI, and finally srand(1) again before starting the test.

Sponsored-by: On-Waves ehf
2014-12-02 09:18:19 +01:00
Jacob Erlbeck
59ac49dc1f gbproxy: Reset TLLIs when the link_info is found by IMSI/P-TMSI
Currently when the MS does a re-attach without doing a proper detach
first, the gbproxy uses the old local TLLI if patching and the keep
mode are enabled. This leads to a failing attachment procedure when
TLLI patching is also enabled.

This patch changes gbproxy_update_link_state_ul to reset all TLLIs
within the link_info if the message contains an unknown TLLI and an
MI. This is generally the case with Attach Request messages.

The gbproxy_get_link_info_ul gets an additional tlli_is_valid
output parameter that is set, when a TLLI was present and found.
This flag is then used instead of checking tlli.current == 0 to
set TLLI/P-TMSI e.g. Attach Requests when a link_info was already
present for the P-TMSI/IMSI used in such a request.

Ticket: OW#1324
Sponsored-by: On-Waves ehf
2014-12-02 09:00:09 +01:00
Holger Hans Peter Freyther
175a240285 bsc: Add ctrl command to set the TRX ARFCN 2014-11-21 11:40:32 +01:00
Holger Hans Peter Freyther
a49b2c010e bsc: Allow to generate new system information online
Increase the bcch_change_mark and generate a new copy of the
system information. Make the method public, add a small test
case. Manually verified using the FakeBTS. I don't know if
the MS will re-read these SIs.

Related: SYS#739
2014-11-21 11:23:47 +01:00
Holger Hans Peter Freyther
b92a538d23 bts: Store the bcch_change_mark in the bts structure
Store the BCCH change mark inside the BTS structure. This will
allow us increment the number and re-generate the SIs.

Related: SYS#739
2014-11-21 11:23:47 +01:00
Holger Hans Peter Freyther
8a64141a53 bsc: Allow to set the call-identity
Allow to set the cell-identity through the control interface
and add a small test for it.

Related: SYS#739
2014-11-21 11:23:47 +01:00
Holger Hans Peter Freyther
b1461152e6 bsc: Allow to apply configuration for an individual BTS
This will drop a specific IP based BTS. It will lead to a
re-connect of the BTS and the new settings will be applied
then.

Fixes: SYS#737
2014-11-21 10:24:18 +01:00
Holger Hans Peter Freyther
b1edf7b64f mgcp/sdp: Session name must not be empty pick an empty one
The session name must be present in a SDP file. The RFC proposes
to use a space for it but the other equipment is using the dash
so I have picked that as well.

RFC 4566:
The "s=" field is the textual session name.  There MUST be one and
only one "s=" field per session description.  The "s=" field MUST NOT
be empty and SHOULD contain ISO 10646 characters (but see also the
"a=charset" attribute).  If a session has no meaningful name, the
alue "s= " SHOULD be used (i.e., a single space as the session
name).

Fixes: RT#2196
2014-11-20 23:17:32 +01:00
Holger Hans Peter Freyther
619b014d3a mgcp: Allow to omit sending the audio name at all
Equipment like AudioCode appears to get upset when we use a
builtin type and then assign a name to it. Allow to completely
omit the name.
2014-11-19 16:18:56 +01:00
Jacob Erlbeck
02ab91e6a7 sgsn: Cross-link gsm_subscriber and sgsn_mm_ctx
To implement subscriber based authorization a data structure is
needed that keeps the subscriber data. The MSC already uses a similar
struct named gsm_subscriber whose implementation is split into a
generic part (allocation, retrieval, reference counting, list
maintenance) and MSC related parts. For GPRS, only the generic part
will be used and specific fields may be added when needed.

This patch adds a field mm to struct gsm_subscriber that will be used
by the SGSN to store a reference to the current MM context (or NULL
if there is none). This also adds a field subscr to struct
sgsn_mm_ctx that reversely points to a gsm_subscriber (or NULL if
there is none).  Either both fields are NULL or both fields are
non-NULL. Note that subscr is being reference counted.

Sponsored-by: On-Waves ehf
2014-11-14 10:26:49 +01:00
Jacob Erlbeck
a0b6efb368 sgsn: Remove explicit sgsn_instance parameters
Currently the function in sgsn_auth.c either have an sgsn_config or
an sgsn_instance parameter. Since then global sgsn variable is
already being used in that file and since other parts of the SGSN
related code also rely on a global sgsn singleton, these parameters
pretend to provide a flexibility that is not really supported.

Therefore this patch removes these parameters except for the ACL
related functions, which do not call code that uses the sgsn
variable.

Sponsored-by: On-Waves ehf
2014-11-14 10:26:06 +01:00
Jacob Erlbeck
f951a01bb2 sgsn: Refactor sgsn_auth to separate request and authorization
Currently the authorization is done in sgsn_auth_request for ACL
based authorization. This doesn't match the way remote authorization
would work, so that there is a second call to sgsn_auth_state already
present in sgsn_auth_update.

This patch removes the autorization check completely from
sgsn_auth_request which in turn calls sgsn_auth_update directly now.

Sponsored-by: On-Waves ehf
2014-11-14 10:23:54 +01:00
Jacob Erlbeck
f6e7d99d54 sgsn: Don't assign a new P-TMSI if one is pending
Currently every time an RA Update Req or an Attach Req is processed, a
new P-TMSI is allocated. When an MS issues another of these messages
before it has completed the first procedure, old_ptmsi is replaced by
ptmsi (and thus lost) and ptmsi is replaced by the newly allocated
P-TMSI. This can confuse the gbproxy, which can loose track of the
logical link then. At least a Blackberry emits a double set of RA Upd
Req messages from time to time which may be just 20ms apart.

This patch adds a check whether mm->ptmsi or mm->old_ptmsi are set.
If both are set, the P-TMSI is not re-allocated. This is only the
case, when the Complete message has not been received yet, since that
message will reset old_ptmsi.

Sponsored-by: On-Waves ehf
2014-11-14 10:19:29 +01:00
Jacob Erlbeck
c4f9bf3142 sgsn: Don't send XID reset after Detach Accept
Currently when a Detach Accept is received for an unknown TLLI (which
is in general the case afer the SGSN has requested the detachment),
an XID reset is sent to the BSS, causing a BSSGP Status message. This
happens in gsm0408_rcv_gmm.

This patch moves the corresponding call to gprs_llgmm_reset downwards
so that it is not being called in that case.

Addresses:
SGSN->BSS TLLI: 0xd75b91d9 SAPI: LLGMM, UI (DTAP) (GMM) Detach Request
BSS->SGSN TLLI: 0xd75b91d9 SAPI: LLGMM, UI (DTAP) (GMM) Detach Accept
SGSN->BSS TLLI: 0xd75b91d9 SAPI: LLGMM, U, XID (Reset, IOV-UI)
BSS->SGSN TLLI: ---        BSSGP STATUS (Unknown MS)

Sponsored-by: On-Waves ehf
2014-11-14 10:12:32 +01:00
Jacob Erlbeck
80d07e30c7 sgsn: Cleanup after RA Update Reject / Attach Reject
Currently, the LLME is not cleaned up after sending an RA Update
Reject. This happens after entering a routing area from outside,
since in that case the SGSN sends an RA Update Reject (implicitly
detached) which causes the MS to restart the attach procedure.
The LLME is also not updated if an Attach Request with message errors
(encoding, invalid MI type) is received or if an MM context cannot be
allocated.

This patch changes gsm48_rx_gmm_ra_upd_req and gsm48_rx_gmm_att_req
to unassign the LLME or free the MM context (if available) after a
Reject message has been sent.

Ticket: OW#1324
Sponsored-by: On-Waves ehf
2014-11-14 10:07:42 +01:00
Jacob Erlbeck
106f547733 sgsn: Add 'acl-only' authentication policy
Currently the VTY 'auth-policy' command results in setting or clearing
the acl_enabled flag. This also enables the matching of the MCC/MNC
prefix of the IMSI.

This patch adds an additional policy 'acl-only' which disables the
MCC/MNC matching and relies on the ACL only.

Sponsored-by: On-Waves ehf
2014-11-14 10:07:28 +01:00
Jacob Erlbeck
144b8b1ca7 sgsn/test: Add VTY tests for the SGSN
This patch adds some basic SGSN tests to vty_test_runner.py:
- check for config tree nodes
- check specific show commands

Sponsored-by: On-Waves ehf
2014-11-14 10:06:53 +01:00
Jacob Erlbeck
423f8bfa02 sgsn: Make authorization asynchronous
Currently the authorization of an IMSI is done by checking ACLs
synchronously which is not feasible when the subscriber data has to
be retrieved from an external source.

This patch changes this by using a callback when the information is
available. This is also done when only ACL are checked, in this case
the callback is invoked from within sgsn_auth_request(). The callback
function sgsn_update_subscriber_data calls sgsn_auth_update which
in turn calls either gsm0408_gprs_access_granted or
gsm0408_gprs_access_denied. gsm48_gmm_authorize is extended by a call
to sgsn_auth_request when IMSI and IMEI are available but the
auth_state is unknown.

The change has been successfully tested with single phones (E71 and
IPhone 5c).

Sponsored-by: On-Waves ehf
2014-11-14 09:58:28 +01:00
Jacob Erlbeck
0c06f98ced sgsn: Move IMSI authorization to gsm48_gmm_authorize
Currently the IMSI is only checked immediately when an Attach Request
is received that contains an IMSI IE. If it contains a P-TMSI
instead, access is always granted.

This commit moves the IMSI check to gsm48_gmm_authorize where it is
applied when IMSI and IMEI have been acquired. This fixes the
authorization when the Attach Accept doesn't contain an IMSI.

Sponsored-by: On-Waves ehf
2014-11-14 09:27:23 +01:00
Jacob Erlbeck
b1c074f62c sgsn: Fix LLME leak when forcing a reattach
Currently when forceing a reattach by sending a Detach
Request (reattach), the SGSN waits for the Detach Accept until it
frees the MM context (if present) and the LLME. If that message gets
lost or isn't sent by the MS, the LLME is never freed if it isn't
bound to an MM context.

This patch adds code to free the MM context/LLME when forcing a
reattachment.

Sponsored-by: On-Waves ehf
2014-11-14 09:26:27 +01:00
Jacob Erlbeck
abdf02b9b9 sgsn: Split gsm0408_gprs_force_reattach into 2 functions
This patch replaces gsm0408_gprs_force_reattach(msg, mmctx) by two
functions
  - gsm0408_gprs_force_reattach(mmctx)
  - gsm0408_gprs_force_reattach_oldmsg(msg)

The old function basically consists of the code of the two new
functions, where the code path selected depends on mmctx == NULL,
which is harder to maintain, less obvious to use, and not consistent
with many other SGSN functions.

Sponsored-by: On-Waves ehf
2014-11-14 09:23:38 +01:00
Jacob Erlbeck
a790456f1b sgsn: Call mm_ctx_cleanup_free to deregister MM context
Currently the MM context isn't always removed when it is
de-registered (mmctx_timer_cb), mm_state is set to GMM_DEREGISTERED
instead. This can lead to left-over MM contexts which are only
cleaned up if the MS reattaches.

This patch replaces all of these assignments by a call to
mm_ctx_cleanup_free.

Ticket: OW#1324
Sponsored-by: On-Waves ehf
2014-11-14 09:16:58 +01:00
Jacob Erlbeck
0074a77424 sgsn: Cleanup GMM state transitions
Currently the GMM state is set to GMM-REGISTERED when an Attach
Accept or a RA Update Accept message is sent, even if a new P-TMSI is
included. In this case 04.08 requires (see 4.7.3.1.3 and 4.7.5.1.3),
that the state is set to GMM-COMMON-PROCEDURE-INITIATED when the
Accept is sent. When the Complete is received, the SGSN shall set
the state to GMM-REGISTERED.

This patch modifies the state updates accordingly.

Sponsored-by: On-Waves ehf
2014-11-14 09:12:10 +01:00
Jacob Erlbeck
93eae8ec78 sgsn: Reorganize and fix gsm48_gmm_authorize
Currently the order of the 'if' clauses in gsm48_gmm_authorize
doesn't match the order in which the conditional parts are entered.
This makes it difficult to maintain. In addition the t3350_mode is
not stored in every path, so that this information is lost when the
identification procedure is started. Since the default value
coincidentally is GMM_T3350_MODE_ATT, this doesn't hurt for Attach
Requests which are the only messages that initially trigger the
authentication yet.

This patch changes the order of the 'if' clause to match the
processing order, it removes the t3350_mode parameter entirely and
introduces a mm->pending_req field. The latter must be set when the
request that causes the authorization before calling
gsm48_gmm_authorize. The gprs_t3350_mode enum is extended by
GMM_T3350_MODE_NONE (value 0, which is the default) to make it
possible to detect related initialisation errors or race conditions.

Sponsored-by: On-Waves ehf
2014-11-14 08:57:50 +01:00
Jacob Erlbeck
3911880b68 bsc: Move gsm_subscriber_base.c to libcommon
Since it is planned to use struct gsm_subscriber to manage subscriber
data in the SGSN, this file which contains the generic subscriber
related methods is moved to libcommon.

Sponsored-by: On-Waves ehf
2014-11-11 22:52:21 +01:00
Jacob Erlbeck
cdd4302c6d bsc: Move gsm_network_init function to libbsc
Currently libcommon depends on libbsc, because gsm_network_init
(libcommon/gsm_data.c) directly calls gsm_net_update_ctype
(libbsc/gsm_04_08_utils.c).

This patch moves gsm_network_init to a new file libbsc/net_init.c.

Sponsored-by: On-Waves ehf
2014-11-11 22:52:04 +01:00
Jacob Erlbeck
27cb4d57e0 sgsn/test: Add test_gmm_attach
This test checks the attach procedure until the Attach Complete is
received.

Note that authorization and GMM state updates are not working
properly yet.

Sponsored-by: On-Waves ehf
2014-11-11 22:47:59 +01:00
Jacob Erlbeck
94ef1c0da9 sgsn/test: Move message sending to send_0408_message
This replaces serveral occurences of duplicated code for message
creation and sending (passing to gsm0408_gprs_rcvmsg) into a single
function. In addition, the sgsn_tx_counter is always reset within
send_0408_message to simplify the code that checks for the number of
messages sent.

Sponsored-by: On-Waves ehf
2014-11-11 22:47:40 +01:00
Jacob Erlbeck
4110868029 gbproxy: Honour the BSS TLLI type when creating an SGSN TLLI
Currently gbproxy_make_sgsn_tlli always returns a foreign TLLI when
it uses the (SGSN) P-TMSI to generate one.

This patch changes the implementation to return a SGSN TLLI of the
same type like the BSS TLLI in that case.

Sponsored-by: On-Waves ehf
2014-11-11 22:44:32 +01:00
Henning Heinold
0d8ac0eac0 systemd: use Wants for the dependency btw. osmo-bsc-mgcp and osmo-bsc
* osmo-bsc and osmo-bsc-mgcp are needed to run
* with Wants, both are started but can be indepently
  controlled via systemctl

Fixes: SYS#738
2014-11-11 17:59:49 +01:00
Holger Hans Peter Freyther
054bc24e6d bts: Allow to set the LAC through the CTRL interface
Allow to set the LAC of the BTS through the CTRL interface.
The change will not be effective immediately.

Fixes: SYS#738
2014-11-10 11:41:03 +01:00
Jacob Erlbeck
74b2028167 bsc: Fix use-after-free on OML NM messages from the BTS
Currently the sign_link pointer is dereferenced after a call to
osmo_signal_dispatch, which can indirectly call
e1inp_sign_link_destroy. If that happens, accessing *sign_link is
illegal and can lead to a segmentation violation.

Since only the bts pointer is needed from sign_link after the call to
osmo_signal_dispatch, this patch changes abis_nm_rcvmsg_fom to save
that pointer to a local variable earlier.

Addresses:
<0019> input/ipa.c:250 accept()ed new link from 192.168.1.101 to port 3002
SET ATTR NACK  CAUSE=Message cannot be performed
<0005> bsc_init.c:52 Got a NACK going to drop the OML links.
<001b> bsc_init.c:319 Lost some E1 TEI link: 1 0xb351a830
=================================================================
==13198== ERROR: AddressSanitizer: heap-use-after-free on address 0xb5d1bc70 at pc 0x80a6e3d bp 0xbfbb33d8 sp 0xbfbb33cc

Sponsored-by: On-Waves ehf
2014-11-10 08:47:14 +01:00
Holger Hans Peter Freyther
33f2c4d898 bts: Fail OML in case the channel combination is wrong
In case a BTS is being bootstrapped and one TS can not be
activated prevent the whole BTS from coming up.

When the OML activation is not being done the rest of the BSC
code still assumes these logical channel(s) to be available
and one will see channel activation issues that might be hard
to debug.

Instead of having a half-configured system up and running,
keep the BTS offline.
2014-11-07 09:54:57 +01:00
Holger Hans Peter Freyther
1464a121c0 ipa: Correct the prototype of these functions
They return nothing and not int.
2014-11-06 16:32:57 +01:00
Jacob Erlbeck
9d0fb1e97a gbproxy/test: Extend test_gbproxy_keep_info
Add new test message sequences:
  - Normal attach (with IMSI) after detach (ok)
  - Normal attach (with local TLLI) after detach (ok)
  - Unexpected attach (with IMSI) after successful TLLI validation (fails)
  - Unexpected attach (with P-TMSI) after successful TLLI validation (fails)

Ticket: OW#1324
Sponsored-by: On-Waves ehf
2014-11-05 00:26:34 +01:00
Jacob Erlbeck
de74e721b2 gbproxy: Fixed VTY doc for delete-gbproxy-link
The command definition delete_gb_link_by_id_cmd lacks a description
for the sgsn-nsei token.

This patch adds the missing description.

Addresses:
Verifying src/gprs/osmo-gbproxy -c doc/examples/osmo-gbproxy/osmo-gbproxy.cfg, test verify_doc
Documentation error (missing docs):
<command id='delete-gbproxy-link &lt;0-65534&gt; (tlli|imsi|sgsn-nsei) IDENT'>
        <param name='IDENT' doc='(null)' />

Sponsored-by: On-Waves ehf
2014-11-05 00:24:13 +01:00
Jacob Erlbeck
14ae582064 sgsn: Unassign the LLME after GMM Status without mmctx
Currently the LLME is not deleted when a GMM Status message is
received for which a mmctx cannot be found. This can fill the LLME
list with unneeded entries.

This patch adds code to unassign the LLME in that case.

Ticket: OW#1324
Sponsored-by: On-Waves ehf
2014-11-05 00:24:02 +01:00
Jacob Erlbeck
7067142100 sgsn: Remove unused static functions from gprs_gmm.c
The following functions are not being used:
 - gsm48_tx_gmm_status_oldmsg
 - gsm48_tx_sm_status_oldmsg

This patch removes the function definitions.

Sponsored-by: On-Waves ehf
2014-11-05 00:23:44 +01:00
Holger Hans Peter Freyther
db64f2e45a bsc: Allow to disable sending ping/pong to the MSC
Some switches do not like to receive the IPA PING/PONG messages.
Allow to disable the handling with "no timeout-ping" and create
test cases that verify the switching between the modes. Change the
code to trat <= 0 as an invalid timeout.

Fixes: SYS#713
2014-10-29 10:11:21 +01:00
Jacob Erlbeck
76606d3473 nitb/ctrl: Fix access to freed memory in verify_subscriber_modify
Currently the temporary string 'tmp' is freed before parts of it are
referenced. This lets address sanitizer complain when evaluating
strlen(imsi), where imsi points into the 'tmp' data block.

This patch moves the talloc_free to the end of the function and uses
a rc variable instead of using early returns.

Addresses:
testSubscriberAddRemove (__main__.TestCtrlNITB) ... Launch:
./src/osmo-nitb/osmo-nitb -c
  ./doc/examples/osmo-nitb/nanobts/openbsc.cfg -l test_hlr.sqlite3
Connecting to host 127.0.0.1:4249
Sending "SET 1000 subscriber-modify-v1 2620345,445566"
Decoded replies:  {}
ERROR

Sponsored-by: On-Waves ehf
2014-10-28 15:17:02 +01:00
Jacob Erlbeck
5a38f6470e sgsn: Handle Detach Requests even when there is no mmctx
Currently, when a Detach Request is received with an unknown TLLI,
it is answered by another Detach Request (!), even when a power_off
Type is used.

This patch uses gsm48_rx_gmm_det_req to handle the message instead.
So this function is changed to cope with a NULL mmctx. In that case
it doesn't unassign the llme, so this must be done manually
afterwards.

Sponsored-by: On-Waves ehf
2014-10-27 15:34:14 +01:00
Jacob Erlbeck
b9ab0d4f39 sgsn: Only send Detach Accept (MO) if power_off isn't set
Currently, every time the SGSN received a Detach Request from the MS
via an established logical link, it is answered by a Detach Accept.
This violates the specification (GSM 04.08, 4.7.4.1.2 and .3), which
states, that it should only be sent, if "the detach type IE value
indicates that the detach request has not been sent due to switching
off".

This patch adds a conditional to limit the sending of Detach Accept
accordingly.

Sponsored-by: On-Waves ehf
2014-10-27 15:21:31 +01:00
Jacob Erlbeck
189999d654 sgsn/test: Add test case for Detach Request (MO, power-off = 1)
Currently only a Detach Request (MO) message with power_off = 0 is
checked.

This commit adds a new test case with power_off set to 1. It also
adds checks for the number of messages generated by the SGSN to
verify that these messages are handled differently.

Note that the handling of power_off isn't implemented yet. Therefore
the corresponding assertion is being disabled yet.

Sponsored-by: On-Waves ehf
2014-10-27 15:21:11 +01:00
Jacob Erlbeck
abc16a55b2 sgsn/test: Move MM context allocation into separate function
This refactores serveral code lines needed for the allocation of MM
contexts into the new function alloc_mm_ctx.

Sponsored-by: On-Waves ehf
2014-10-27 15:20:07 +01:00
Jacob Erlbeck
3b5d407203 sgsn: Moved IMSI ACL management to sgsn_auth.c
Currently the ACL code is located in sgsn_vty.c.

This commit moves this to a new file sgsn_auth.c as a first step to
make authorization more flexible in order to implement remote
acquisition on subsciber data.

Sponsored-by: On-Waves ehf
2014-10-27 13:06:55 +01:00
Jacob Erlbeck
fb26c60a2f sgsn: Avoid duplicated Attach Accept messages
Currently each received Ident Resp triggers an Attach Accept/Reject
if IMSI and IMEI are known. This has led to duplicated Attach Accept
messages when used with the gbproxy (IMSI acquisition active) and
with certain mobile equipment (iOS).

This patch modifies gsm48_rx_gmm_id_resp to discard Ident Resp messages
if all required information (IMEI and IMSI) has been gathered.

Ticket: OW#1322
Sponsored-by: On-Waves ehf
2014-10-27 13:06:55 +01:00
Jacob Erlbeck
c37ef6cd0e gbproxy: Patch BSSGP P-TMSI in PAGING PS messages
Currently the P-TMSI IE in PAGING_PS is not patched.

This commit adds code to patch BSSGP P-TMSI IE in
gbproxy_patch_bssgp independently from the P-TMSI patching at the LLC
layer. It also extends gbproxy_update_link_state_dl to use the IMSI
to find the link_info if the TLLI is not present in the message.

Note that the spec (GSM 08.18, 7.2) requires to use of the P-TMSI
instead of the IMSI to select the MS if that IE is available.
Nevertheless as long as the IMSI is always present in downlink BSSGP
messages and as long as the optional P-TMSI refers to the same MS
(which is the case currently), this is not an issue.

Sponsored-by: On-Waves ehf
2014-10-27 11:59:28 +01:00
Jacob Erlbeck
91e9f555b6 gbproxy: Fix P-TMSI generation for repeated Attach Accept messages
Currently, when P-TMSI patching is enabled, a new BSS P-TMSI is
generated for each Attach Accept. So two duplicated, subsequent
Attach Accept messages will be mapped to different BSS side P-TMSI.
Because the last one will replace former ones in the link_info
struct, the MS will fail to access the SGSN if it uses the former
P-TMSI to derive the new TLLI.

This patch checks the SGSN P-TMSI already assigned to the link_info
and only generates a new BSS P-TMSI on mismatch (or if the BSS P-TMSI
hasn't been set yet).

Ticket: OW#1322
Sponsored-by: On-Waves ehf
2014-10-27 11:17:11 +01:00
Jacob Erlbeck
e99c333d61 gbproxy/test: Add test case for repeated and otherwise bad messages
This adds a test case to check gbproxy's behaviour when processing
two subsequent but identical Attach Accept messages.

Ticket: OW#1322
Sponsored-by: On-Waves ehf
2014-10-27 11:12:22 +01:00
Jacob Erlbeck
fb83ed32d2 gbproxy/test: Add expect_msg checks to test_gbproxy_keep_info
This patch adds assertions to check the LLC/GMM message received from
the gbproxy by the test framework within the function
test_gbproxy_keep_info.

It also fixes the source address of the DETACH ACC messages.

Sponsored-by: On-Waves ehf
2014-10-27 10:51:40 +01:00
Jacob Erlbeck
78ecaf0561 sgsn: Send detach(re-attach) instead of gmm status if TLLI unknown
The osmo-sgsn sends Status messages (or nothing in case of non
GMM/GSM) when the TLLI is unknown. This prevents the MS from
reconnecting.

This patch adds the initiation of an MT detach procedure to force a
re-attach to set up a valid LLE context if an LLE or an MM context
cannot be found. Since this can also be triggered by non-GMM SAPI
messages, a GPRS application callback sgsn_force_reattach_oldmsg is
added which in turn calls the GMM layer to generate the GSM 04.08
specific messages.

Note that the MS can be left in REGISTERED state after initially
wanting to detach itself, since it will receive a Detach Req
(re-attach) when sending a DEACT PDP CTX REQ after the SGSN or
gbproxy (P-TMSI patching enabled) has been restarted. This same
behaviour has been observed with another SGSN.

Sponsored-by: On-Waves ehf
2014-10-27 10:50:36 +01:00
Jacob Erlbeck
99985b5ea8 sgsn: Delete PDP contexts properly
Currently the PDP contexts are hard freed (via sgsn_pdp_ctx_free)
at some places in gprs_gmm.c on the reception of a Detach Req and on
re-use of an IMSI that is already associated with an MM context. This
can lead to segfaults when there is a pending request or a data
indication at libgtp.

This patch add a new function sgsn_pdp_ctx_terminate that de-associates
the PTP context from the MM context, deactivates SNDCP, sets pdp->mm
to NULL and then calls sgsn_delete_pdp_ctx. sgsn_libgtp is updated to
check for pdp->mm being non-NULL before dereferencing it. The
sgsn_pdp_ctx_terminate function will be called for each PDP context of
an MM context before this context is going to be deleted via
sgsn_mm_ctx_free. To ensure, that the ctx->llme (which is accessed
during the deactivation of SNDCP) remains valid, the call to
gprs_llgmm_assign is moved after the call to sgsn_mm_ctx_free. The
handling of re-used IMSIs is changed to mimic the processing of a
Detach Req.

Addresses:
<0002> gprs_gmm.c:654 MM(/f6b31ab0) Deleting old MM Context for same
    IMSI p_tmsi_old=0xc6f19134
<000f> gprs_sgsn.c:259 PDP freeing PDP context that still has a
    libgtp handle attached to it, this shouldn't happen!
[...]
SEGFAULT

Ticket: OW#1311
Sponsored-by: On-Waves ehf
2014-10-27 10:25:13 +01:00
Jacob Erlbeck
ae20b4b31b sgsn: Cancel pending timer in sgsn_mm_ctx_free
Currently the timer is not stopped before the MM context is freed
which can lead to failure if sgsn_mm_ctx_free is called while timer
protected procedures are active.

This patch add code to cancel the timer if necessary from within
sgsn_mm_ctx_free.

Ticket: OW#1322
Sponsored-by: On-Waves ehf
2014-10-27 10:25:03 +01:00
Holger Hans Peter Freyther
19e990d6a7 gprs: Fix typo in the comment 2014-10-27 10:25:03 +01:00
Jacob Erlbeck
6a1d428f56 gbproxy: Fix segfault for VTY delete-gbproxy-link
Currently the code segfaults when the link shall be deleted by IMSI
when the IMSI has not been set yet.

This patch adds a NULL check to skip the entry before calling
gsm48_mi_to_string,

Adresses:
Program received signal SIGSEGV, Segmentation fault.
0xb693af77 in gsm48_mi_to_string (string=0xbfffe020 "", str_len=200,
mi=0x0, mi_len=0) at gsm48.c:360
    360         mi_type = mi[0] & GSM_MI_TYPE_MASK;
    str_len=200, mi=0x0, mi_len=0) at gsm48.c:360
    self=0x807c9a0 <delete_gb_link_by_id_cmd>, vty=0xb4303c70,
     argc=3, argv=0xbfffe1c0) at gb_proxy_vty.c:670
...

Sponsored-by: On-Waves ehf
2014-10-27 09:47:00 +01:00
Jacob Erlbeck
c79beec8f6 gbproxy/test: Don't assign a variable within OSMO_ASSERT (Coverity)
Coverity complains about having side effects in OSMO_ASSERT argument
expressions. This would be an issue in this case, because that
variable is only reference in other OSMO_ASSERT expressions.

Nevertheless this patch changes this to assign the variable outside
of OSMO_ASSERT.

Fixes: Coverity CID 1244239
Sponsored-by: On-Waves ehf
2014-10-27 09:45:28 +01:00
Jacob Erlbeck
058ae12135 gbproxy: Discard UL PTP messages with an unknown BVCI
Currently all PTP messages are in general forwarded to the SGSN even
when the BVCI is not known to the gbproxy. Only if message patching
is active and the peer cannot be determined, a log message is
generated, a STATUS message returned, and the message discarded.
The intention for this was to keep the old gbproxy's behaviour if
patching is disabled. But the code gets much more complex this way.
Another drawback is that when the SGSN returns a corresponding STATUS
message, it cannot be routed to the BSS where the original message
came from.

This patch therefore changes the behaviour to reject BSSGP PTP uplink
messages immediately if the BVCI is not known.

Fixes: Coverity CID 1244240
Ticket: OW#1317
Sponsored-by: On-Waves ehf
2014-10-27 09:44:29 +01:00
Holger Hans Peter Freyther
f9ffd1fa18 sgsn: Prevent memory leak and double free
This has been re-produced using the "osmo-pcu emulator" code
and a ping to force segmented SNDCP messages. When the NS link
enters the DEAD/BLOCKED state the msgb would be freed twice.
Once inside gprs_ns_sendmsg and once by the caller. Based on the
return one can not see if the parameter has been deleted.

I changed libosmocore/libosmogb to always free the msgb in case
of an error on the way to gprs_ns_sendmsg. Catch up, avoid the
double free and fix some memory leaks. In case the sending fails
assume the entire segmented message is at end and free the
original input data.

This has been tested by posix suspending/resuming the emulator
process to have the GPRS-NS link go to dead/blocked to alive
and unblocked. The ping recovers and "SIGUSR1" to the SGSN does
not show active memory allocations.

The SGSN calls bssgp_tx_dl_ud at the lowest level and has the
following callchains. Most of them allocate the msgb and have
no early return and transfer ownership already:

<- gprs_llc_tx_u
<- gprs_llc_tx_ui
	<- gsm48_gmm_sendmsg (all callers sane)
		<- _tx_status
		<- _tx_detach_req
	<- gprs_llc_tx_xid (all callers sane)
	<- sndcp_unitdata_req
		<- sndcp_send_ud_frag
2014-10-10 17:43:40 +02:00
Jacob Erlbeck
b4f0e8089d gbproxy: Log more information on parse errors
To get a clue which message caused the error without having to enable
LOGL_DEBUG, information about how far the parser came (message name,
parsed fields) is logged with LOGL_NOTICE along with a full hexdump
of the message.

Ticket: OW#1307
Sponsored-by: On-Waves ehf
2014-10-09 18:17:06 +02:00
Jacob Erlbeck
1c407aa993 gbproxy: Pass the log level as argument to gprs_gb_log_parse_context
Currently, the log level is always LOGL_DEBUG. In case of errors it
would be helpful to use a higher log level.

This patch adds a log_level parameter to gprs_gb_log_parse_context to
let the caller decide about the level.

Ticket: OW#1307
Sponsored-by: On-Waves ehf
2014-10-09 18:16:22 +02:00
Jacob Erlbeck
9b07135b92 gbproxy: Add gprs_gb_message_name function
This function tries to get an accurate name for the message even if
the parsing has been aborted due to message errors.

The patch also moves the settings of the BSSGP related fields in
parse_ctx from behind to the front of bssgp_tlv_parse, to get more
information in the case of failure. This is now consistent with the
handling of the llc and g48_hdr fields.

Id addition, gprs_gb_log_parse_context now uses the new function to
derive a more accurate message name.

Ticket: OW#1307
Sponsored-by: On-Waves ehf
2014-10-09 18:15:31 +02:00
Jacob Erlbeck
cc8856f9d3 gbproxy: Refuse to configure conflicting NSEIs
Currently it is possible to set the secondary SGSN NSEI to the same
value like the (primary) SGSN NSEI. This leads to undefined behaviour
and is hard to recognize.

This patch adds checks to either NSEI configuration command to refuse
conflicting values.

Ticket: OW#1306
Sponsored-by: On-Waves ehf
2014-10-09 18:14:09 +02:00
Jacob Erlbeck
49389178cc gbproxy: Use pointer to PTMSI value instead of MI
Currently, ptmsi_enc and new_ptmsi_enc point to the beginning of the
mobile identity. Since all P-TMSI in 04.08 (MM) are encoded this way (1
byte header + 4 byte P-TMSI value). This is different to the P-TMSI
encoding in 08.18 (BSSGP), where the P-TMSI is encoded into 4 byte
without MI header.

This patch changes the code to use pointers to the P-TMSI value,
which is encoded in the same way in both specifications.

Sponsored-by: On-Waves ehf
2014-10-09 18:12:27 +02:00
Jacob Erlbeck
43b8f9f8a1 gbproxy: Send STATUS(BVCI unknown) to BSS on unknown PTP BVCI
Currently BSSGP PTP messages are silently dropped when the BVCI is
not known and patching is enabled. The nanoBTS will not recognize
this and continue to send messages on the BVCI. If it receives a
STATUS(BVCI unknown) instead, it will start a BVC reset procedure
instead.

This patch modifies gbprox_rx_ptp_from_bss() to return a
STATUS(BVCI unknown) to the BSS instead of dropping the message.

Sponsored-by: On-Waves ehf
2014-10-09 18:09:54 +02:00
Jacob Erlbeck
f349baeec8 gbproxy: Replace ';;' by ';'
This patch removes some superfluous ';' from the code.

Sponsored-by: On-Waves ehf
2014-10-09 18:09:27 +02:00
Jacob Erlbeck
c9cd15fbc9 gbproxy: Fix parser to accept GSM 24.008 Attach Req messages
Currently the parse expects a 'MS network capability' IE with
2 <= length <= 3 which is compliant to GSM 04.08, 9.4.1  but not to
GSM 24.008, 9.4.1 which specifies 3 <= length <= 9. Thus the parser
rejects messages with a length >= 4 (including length field).

This patch relaxes the length check to accept either range by
requiring 2 <= length <= 9.

Ticket: OW#1258
Sponsored-by: On-Waves ehf
2014-10-09 18:07:10 +02:00
Jacob Erlbeck
b36032cb27 gbproxy: Use a separate regexp for routing
Currently one regexp ('patching') is used for all matching.

This patch adds a second category 'routing' which is exclusively used
for SGSN selection. It also adds a corresponding VTY command:

  - match-imsi patching RE : MS related patching (currently APN)
  - match-imsi routing RE  : Select secondary SGSN on match only
  - no match-imsi          : Clear all filter expressions

Ticket: OW#1258
Sponsored-by: On-Waves ehf
2014-10-09 18:06:30 +02:00
Jacob Erlbeck
6c3fdc1091 gbproxy: Extend the match-imsi VTY command to support categories
This patch modifies the match-imsi command to allow for different
match categories (currently only 'patching' is provided).

  - match-imsi patching RE : Filter APN patching and routing
  - no match-imsi          : Clear all filter expressions

Sponsored-by: On-Waves ehf
2014-10-09 18:05:17 +02:00
Jacob Erlbeck
9ccc41ea05 gbproxy: Cleanup match config after tests
Currently, patch filter configurations are leaking between tests.

This adds a call to gbproxy_clear_patch_filter() to the end of each
test that calls gbproxy_set_patch_filter().

Sponsored-by: On-Waves ehf
2014-10-09 18:04:14 +02:00
Jacob Erlbeck
9a83d7af55 gbproxy: Refactor IMSI matching
The current implementation makes it difficult to add further match
expressions.

This patch adds a new struct gbproxy_match that contains the fields
needed for each match expression. The matches (config) and the
results (link_info) are stored in arrays. All related functions are
updated to use them. The old fields in the config structure are
removed.

Sponsored-by: On-Waves ehf
2014-10-09 18:02:33 +02:00
Jacob Erlbeck
55ec2bf97f gbproxy/test: Add expect_msg checks to test_gbproxy_ra_patching
This patch adds assertions to check the LLC/GMM message received from
the gbproxy by the test framework within the function
test_gbproxy_ra_patching.

Sponsored-by: On-Waves ehf
2014-10-09 18:01:48 +02:00
Jacob Erlbeck
acfaff38db gbproxy/test: Save and check received messages
Currently the only way to check, whether the right message have been
generated is to look into the generated text output. This is
error-prone if there are many messages.

This patch adds a way to optionally store all received messages into
a FIFO. They can then be checked by calling expect_msg() which
removes the first message from the FIFO and returns a pointer to it
or NULL if there is none. The pointer is only valid until the next
call to this function.

A few convenience functions are added to check for common message
types:

  - expect_gmm_msg checks for certain GSM 04.08 messages in LLC/GMM
  - expect_llc_msg checks for arbitrary LLC messages in BSSGP/UD
  - expect_bssgp_msg checks for arbitrary BSSG messages

Each of their arguments can be set by MATCH_ANY to ignore it while
matching. On success, they return a pointer to a statically
allocated struct containing the pointer to the msg and the full parse
context.

Recording is enabled by setting the global variable received_messages
to a pointer to a struct llist_head. It can be disabled again by
setting it to NULL.

Sponsored-by: On-Waves ehf
2014-10-09 18:01:15 +02:00
Jacob Erlbeck
7e31f847af gprs: Fix gprs_msgb_copy pointer computation
Currently the pointers are computed by adding an offset to the new
message's _data pointer even when the original pointer is NULL.
This leads to invalid pointers in the copied msgb.

This patch adds a NULL check to each computation such that NULL
pointers are not adjusted.

Sponsored-by: On-Waves ehf
2014-10-09 18:00:55 +02:00
Jacob Erlbeck
657502812b gbproxy: Refactor local message generation
This patch adds und uses the function gbproxy_gsm48_to_peer() which
takes a GSM 04.08 message, encapsulates it in BSSGP and LLC, and
sends it to the BSS peer. This function increments vu_gen_tx_bss
which is now used instead of imsi_acq_retries to set the N(U) of the
outgoing message.

Since imsi_acq_retries isn't currently incremented before a Detach
Accept is generated, this patch also fixes the N(U) of such messages.

Sponsored-by: On-Waves ehf
2014-10-09 17:57:28 +02:00
Jacob Erlbeck
d211d1d999 gbproxy: Reset IMSI acquisition within gbproxy_unregister_link_info
Currently then link_info is not cleaned up completely, when
gbproxy_unregister_link_info is called.

This patch adds a function gbproxy_reset_link that must be defined
externally. This is done in gb_proxy.c, where it resets the IMSI
acquisition.

Sponsored-by: On-Waves ehf
2014-10-09 17:56:16 +02:00
Jacob Erlbeck
9c65c8116f gbproxy: Parse Attach Reject messages
That message is currently ignored but should invalidate the TLLI and
de-register the logical link instead.

This patch extends the parser to recognize such messages and to set
the invalidate_tlli flag.

Sponsored-by: On-Waves ehf
2014-10-09 17:48:37 +02:00
Jacob Erlbeck
2bf326186a gbproxy/test: Add invalidation tests to test_gbproxy_keep_info()
The TLLI should also be invalidated:
 - when an Attach Reject info is received from the SGSN
 - when an Attach Req is immediately followed by a Detach Req
 - when an Attach Req is immediately followed by an MT detach
   procedure

To verify that, this patch adds corresponding message sequences to
the test.

Sponsored-by: On-Waves ehf
2014-10-09 17:48:29 +02:00
Jacob Erlbeck
ea71b4880c gbproxy/test: Fix IMSI length check (Coverity)
This fixes the IMSI length assertion, which currently uses a
greater-or-equal than zero comparison which always yields true. It is
replaced by a greater than zero check.

Fixes: Coverity CID 1239442

Sponsored-by: On-Waves ehf
2014-10-09 17:47:58 +02:00
Jacob Erlbeck
51fde08b07 gbproxy/test: Fix time calculation in test_gbproxy_tlli_expire()
A single test case still uses time() to obtain the reference time.

This commit fixes this by using the 'now' variable instead, that
contains a fixed time value and does therefore not depend on when the
test is executed.

Sponsored-by: On-Waves ehf
2014-10-09 17:47:30 +02:00
Jacob Erlbeck
c6807c4405 gbproxy: Use monotonic system time instead of time-of-day
Currently time() is used for age calculations. This time source
may jump either forwards or backwards in time (NTP update, leap
seconds).

This patch replaces the use of time() by using
clock_gettime(CLOCK_MONOTONIC) instead.

Sponsored-by: On-Waves ehf
2014-10-09 17:46:34 +02:00
Jacob Erlbeck
ba6267f05a gbproxy: Only search by valid identifiers
Don't return a link_info if TLLI is 0 resp. P-TMSI is 0xffff. These
values are used for uninitialised or cleared fields and can possibly
match several entries.

Sponsored-by: On-Waves ehf
2014-10-09 17:46:06 +02:00
Jacob Erlbeck
d4c79a458b gbproxy: Replace 'tlli' by 'link' in VTY commands
Since the (former) TLLI list has developed into a logical link list,
related commands are renamed accordingly.

 - tlli-list * -> link-list *
 - delete-gbproxy-tlli * -> delete-gbproxy-link *
 - show gbproxy tllis -> show gbproxy links

Sponsored-by: On-Waves ehf
2014-10-09 17:45:27 +02:00
Jacob Erlbeck
f8562e362b gbproxy: Rename the field 'enabled_tllis' to 'logical_links'
This field in struct gbproxy_patch_state has involved and holds a
list of all tracked logical links now. Thus the name is modified
accordingly.

Sponsored-by: On-Waves ehf
2014-10-09 17:45:14 +02:00
Jacob Erlbeck
91d2f8a704 gbproxy: Use the term 'link' instead of 'tlli'
Currently in many places where 'tlli' (Temporary Logical Link
Identifier) within identifiers is used, the logical link itself is
meant instead. For instance, the tlli_info contain information about
an LLC logical link including up to four individual TLLI.

To avoid confusion between these concepts, this patch replaces all
'tlli_info' by 'link_info' and a few 'tlli' by 'link'.

Sponsored-by: On-Waves ehf
2014-10-09 17:44:57 +02:00
Jacob Erlbeck
9a7b0d5641 gbproxy: Rename functions related to tlli_info
This patch replaces 'tlli' by 'tlli_info' within the following
function identifiers:
  - gbproxy_delete_tlli
  - gbproxy_delete_tllis
  - gbproxy_remove_stale_tllis
  - gbproxy_touch_tlli
  - gbproxy_unregister_tlli
  - gbproxy_remove_matching_tllis
  - gbproxy_find_tlli -> gbproxy_tlli_info_by_tlli
  - gbproxy_find_tlli_by_* -> gbproxy_tlli_info_by_*

These functions refer to the whole logical link info rather than to a
certain TLLI. So they are renamed to be named consistently with
gbproxy_attach_tlli_info and others.

Sponsored-by: On-Waves ehf
2014-10-09 17:43:53 +02:00
Jacob Erlbeck
9a6b763507 gbproxy: Remove sgsn_nsei parameter
The function gbproxy_imsi_acquisition() has a parameter sgsn_nsei
that is alyways equal to tlli_info->sgsn_nsei (if tlli_info is not
NULL).

This patch removes this parameter from gbproxy_imsi_acquisition() and
gbproxy_flush_stored_messages() and accesses tlli_info->sgsn_nsei
instead within these functions.

Sponsored-by: On-Waves ehf
2014-10-09 17:43:34 +02:00
Jacob Erlbeck
8992f30866 gbproxy: Rename identifiers related to IMSI matching
This patch renames gbproxy_check_tlli() to
gbproxy_imsi_matches() and struct tlli_info's
enable_patching to imsi_matches.

It's meant to be more obvious and consistent this way.

Sponsored-by: On-Waves ehf
2014-10-09 17:43:12 +02:00
Jacob Erlbeck
08fbeb8fa4 gbproxy/sgsn: Enforce termination when creating a P-TMSI/TLLI
Currently the number of iterations when creating a P-TMSI/TLLI is not
limited. It is nevertheless very unlikely that the loop will not
terminate. On the other hand, the number of iterations of every loop
should have an upper bound (loop variant) which wouldn't be the case
here if an arbitrary random generator was used.

This patch limits the number of iterations to 23 and logs an error if
the creation of the indentifier was aborted due to this limit.

Sponsored-by: On-Waves ehf
2014-10-09 17:42:23 +02:00
Jacob Erlbeck
e27ab916d6 gbproxy: Restart IMSI acquisition on RA UDP REQ
Currently the IMSI acquisition is not restarted when a RA Update
Request is received. This leads to repeated N(U) in the generated
Ident Request message, which in turn causes the MS to drop the
second of these message. This is bad, when the first Ident Response
has been lost between MS and gbproxy.

This patch changes gbproxy_imsi_acquisition() to handle RA Update
Request messages like Attach Requests.

Sponsored-by: On-Waves ehf
2014-10-09 17:41:41 +02:00
Jacob Erlbeck
2ec2757def gbproxy/test: Test IMSI acquisition for RA UDP REQ
When a MS is state GMM_REGISTERED enters a new RA, it sends a RA
Update Request which is then handled by a gbproxy that possibly
doesn't have a matching tlli_info. In this case, depending on the
configuration an identification procedure to acquire the IMSI must be
started.

This adds tests to test_gbproxy_imsi_acquisition():
 - IMSI acquisition triggered by a RA Update Request message
 - Reaction to repeated RA Update Request messages, like it could be
   caused by packet loss between PCU and gbproxy.

Sponsored-by: On-Waves ehf
2014-10-09 17:41:06 +02:00
Jacob Erlbeck
258ce3ded5 sgsn: Free MM context after receiving a Detach Request
On a Detach/Re-attach cycle the Address Sanitizer detected a
use-after-free kind of problem. That is because we tried to
destroy the LLME twice. The first time it is destroyed as part
of the Detach handling ans the second time it is destroyed as
part of destroying the old MM context.

In case the GPRS GMM detach message is lost the SGSN needs
to reply besides not having a MM entry.

The alternative would have been to add NULL checks for all
usages of ctx->llme which would not have helped with the
readability.

Sponsored-by: On-Waves ehf
2014-10-09 17:22:34 +02:00
Holger Hans Peter Freyther
fe92133132 sgsn: Add test that exposes a dangling pointer to the LLME
On detach the LLME get's unassigned (and hence destroyed) but the
GMM context will still point to that dead structure.
2014-10-09 17:22:34 +02:00
Holger Hans Peter Freyther
4299c0560f sgsn: Create testcase that verifies that llmes get deleted
On an "unassignment" this code verifies that the LLME will vanish
from the list of LLMEs. We assume that this doesn't create a
memory leak.
2014-10-09 17:22:34 +02:00
Holger Hans Peter Freyther
68c6f887c2 sgsn: Add boilerplate code for a SGSN test 2014-10-09 17:22:34 +02:00
Holger Hans Peter Freyther
7b76f82b6e mgcp: Count the incoming data instead of the modified one
For jitter, transit and packet loss we should count the data
that arrived and not the data we send towards the remote. This
is changing the jitter timings to what they were before the
re-factoring.

For forced timing we might willingly add jumps in the sequence
number but for jitter and packet loss we are more interested
in the data that traveled through the wire/air.
2014-10-09 17:22:33 +02:00
Holger Hans Peter Freyther
05d481a42c mgcp: Do not detect the initial package as a wrap around
The Annex A code has a probation period but we don't have it. When
starting with seq_no==0 do not assume that the sequence numbers
have wrapped. Do it by moving the entire checking code into the
else.
2014-10-09 17:22:33 +02:00
Holger Hans Peter Freyther
a5a59c9a05 mgcp: Move Annex A counting out of patch/count method
mgcp_patch_and_count has grown due supporting linearizing timestamps,
ssrc and other things for equipment like the ip.access nanoBTS. Fight
back and move the Annex A code into a dedicated method.

The result is updated as we now count after all the patching and for
the Annex A code no change in SSRC can be detected.
2014-10-09 17:22:33 +02:00
Holger Hans Peter Freyther
2a7ab868e3 mgcp: We only look at the RTP header use that in the comment 2014-10-09 17:22:33 +02:00
Ruben Pollan
ed04a0d060 nitb: Add subscriber delete command 2014-10-03 09:15:28 +02:00
Holger Hans Peter Freyther
47c624b561 bsc: Let the VTY verify that the timeout is a number
Before the old code allowed to specify "timeout-ping bla" which
would be parsed as '0' which would trigger a flood of pings. Use
the VTY code to parse it as a number.
2014-10-02 12:08:29 +02:00
Daniel Willmann
f8070f4793 gprs: Move log message about mm context after NULL check
Fixes: CID#1240205
2014-09-25 14:24:55 +02:00
Daniel Willmann
465531403c gprs: Improve loglevels and log messages for SGSN
Many log levels were DEBUG without any good reason. Also where possible
the details of the MM or PDP context are now logged with LOGMM/PDPCTXP.
2014-09-22 10:47:11 +02:00
Daniel Willmann
b15ceec33f gprs_sgsn.h: Add two macros to log details of MM/PDP contexts 2014-09-22 10:47:11 +02:00
Jacob Erlbeck
25ad52cf6a sgsn: Reset local LLC parameters when sending XID reset
Currently when gprs_llgmm_reset() is invoked an XID reset is sent but
the local LLC parameters (e.g. V(U)) are not cleared (see GSM 04.64,
8.5.3.1). This can lead to discarded messages on the SGSN side.

This patch modifies gprs_llgmm_reset to clear vu_send, vu_recv,
oc_ui_send, oc_ui_recv.

Sponsored-by: On-Waves ehf
2014-09-19 11:55:21 +02:00
Jacob Erlbeck
91a0e8639a gbproxy: Separate SGSN numeric namespaces
Currently the SGSN side message's TLLI are searched without checking
the originating SGSN. This leads to collisions if both SGSN use the
same P-TMSI for different MS.

With this patch, the SGSN NSEI is stored within the tlli_info and is
used in comparisons to separate the namespaces.

Note that this type of collision cannot happen with BSS numbers,
since the tlli_info are already separated and stored per (BSS) peer.

Sponsored-by: On-Waves ehf
2014-09-19 11:21:35 +02:00
Jacob Erlbeck
af952baffc gbproxy/test: Add a test with a P-TMSI collision between two SGSNs
This patch extends test_gbproxy_secondary_sgsn() by the establishment
of a third MS connection using a P-TMSI that has been assigned by the
other SGSN already. It is expected that the entries do not
interfere and are properly retrieved.

Note that these collisions are not handled properly yet.

Sponsored-by: On-Waves ehf
2014-09-19 11:21:24 +02:00
Jacob Erlbeck
2bb4543809 gbproxy/test: Fix Identification Response
At one place, the reply to the second Ident Req contains the wrong
IMSI. That is fixed by this patch.

Sponsored-by: On-Waves ehf
2014-09-19 11:21:13 +02:00
Jacob Erlbeck
1a02442f66 gbproxy: Check other tlli_infos for matching TLLI/P-TMSI
Currently it is possible to create serveral entries referring to the
same P-TMSI/TLLI by using P-TMSI assigment via Attach Accept or
RA Update Accept messages. This can lead to the use of the wrong
tlli_info.

This patch adds gbproxy_remove_matching_tllis() that removes all
conflicting entries. This function is called after the P-TMSIs and
the resulting TLLIs has been set up.

Sponsored-by: On-Waves ehf
2014-09-19 11:21:01 +02:00
Jacob Erlbeck
04f679be73 gbproxy/test: Add test case for P-TMSI assigment
This tests P-TMSI assignment when P-TMSI patching is disabled. A test
with colliding P-TMSI in Attach Accept messages is included.

Note that P-TMSI collisions are not handled properly yet.

Sponsored-by: On-Waves ehf
2014-09-19 11:20:50 +02:00
Jacob Erlbeck
85e5c8f905 gbproxy: Parse RA_UPD_REJ and invalidate TLLI
Since this message puts the MS into DEREGISTERED state (like a detach
procedure), this message is parsed and the invalidate_tlli field is
set accordingly.

Sponsored-by: On-Waves ehf
2014-09-19 11:20:31 +02:00
Jacob Erlbeck
cdd37837b3 gbproxy: Delete and show detached entries via VTY
This commit adds/modifies the following VTY commands:

  - delete-gbproxy-tlli <NSEI> de-registered : Delete all
    de-registered entries
  - show gbproxy tllis : Display 'DE-REGISTERED' when appropriate

In addition, the implementation of the delete-gbproxy-tlli command
has been split into two functions (with and without TLLI/IMSI
value).

Sponsored-by: On-Waves ehf
2014-09-19 10:54:21 +02:00
Jacob Erlbeck
d3bde96b36 gbproxy: Replace LOGP by LOGPC for continued lines
gprs_gb_log_parse_context() uses a sequence of LOGP calls to compose
a single message line. This leads to cluttered log output.

This patch replaces all but the first LOGP applications in this
function by applications of LOGPC.

Sponsored-by: On-Waves ehf
2014-09-19 10:49:17 +02:00
Jacob Erlbeck
16a3cd3847 gbproxy: Avoid multiple tlli_info entries with the same IMSI
Currently it is possible to create several tlli_info entries with the
same IMSI.

This patch disables this by adding a check before the imsi field
is updated.

Sponsored-by: On-Waves ehf
2014-09-19 10:49:12 +02:00
Jacob Erlbeck
7430da621a gbproxy: Keep tlli_info after detach
Currently a tlli_info entry is deleted when the TLLI gets invalidated
by a Detach message.

This patch introduces the possibility to keep tlli_info entries in
the list. Those entries then have cleared TLLI fields, are marked as
de-registered, and can only be retrieved by a message containing an
IMSI or a P-TMSI.

The following VTY configuration commands are added to the gbproxy
node:
  - tlli-list keep-mode never : Don't keep the entries (default)
  - tlli-list keep-mode re-attach : Only keep them, when a Detach
    message with re-attach required has been received
  - tlli-list keep-mode identified : Only keep entries which are
    associated with an IMSI
  - tlli-list keep-mode always : Keep all entries

Note that at least one of max-length or max-age should be set when
this feature is used to limit the number of entries.

Sponsored-by: On-Waves ehf
2014-09-19 10:46:23 +02:00
Jacob Erlbeck
cba4c0cc60 gbproxy: Only patch what has been configured
Currently when patching is basically enabled P-TMSI and TLLI gets
patched even when P-TMSI patching is not enabled. Albeit the result
is correct in this case (the same value is re-written), the counter
shows unexpected results.

This patch adds configuration checks for P-TMSI and TLLI patching. It
also reorders the code of gbproxy_patch_raid to return early if there
is nothing to patch.

Sponsored-by: On-Waves ehf
2014-09-18 13:46:09 +02:00
Jacob Erlbeck
772a22b529 gbproxy/test: Add test case for tlli_info persistence
This test case consists of a sequence of several attach and detach
procedures. The kind of detach varies (mobile originated, mobile
terminated re-attach required, mobile terminated re-attach not
required, routing area update reject). To main focus is to check that
the tlli_info is de-registered correctly (not accessible via the
TLLI) and that can be re-used afterwards (which is not implemented
yet).

Sponsored-by: On-Waves ehf
2014-09-18 13:40:03 +02:00
Jacob Erlbeck
a42fe9f61e gbproxy: Remove gbproxy_register_tlli
This function is a remainder of the initial implemenation that was
not meant for TLLI patching and can be used for the BSS side only.
The SGSN side is already using a composition of more flexible
single purpose functions.

This patch changes the implementation to use a similar approach. The
function is moved to gbproxy_test.c and renamed to register_tlli to
keep the tests intact.

Sponsored-by: On-Waves ehf
2014-09-18 13:21:17 +02:00
Jacob Erlbeck
2a5096dfc6 gbproxy: Send DETACH_ACC if the IMSI has not been acquired
If IMSI acquisition is enabled and the gbproxy receives a Detach
request from the MS, it cannot pass it to the SGSN since the
acquisition has not yet been completed.

This patch implements the generation of a Detach Accept message and
for this case and updates the TLLI state accordingly.

Sponsored-by: On-Waves ehf
2014-09-18 13:21:16 +02:00
Jacob Erlbeck
948c07f490 gbproxy: Fixed RAI patching in Attach Request messages
Currently the RAI in the LLC part of the message is not updated if
the message has been taken from the list of stored messages. The
reason is, that old_raid_matches is update in
gbprox_process_bssgp_ul() but not in gbproxy_flush_stored_messages().

This patch moves the check to gprs_gb_parse_bssgp() which is called
at both places and where other fields like parse_ctx->tlli are set,
too.

In addition, old_raid_matches is replaced by old_raid_is_foreign
since this is clearer in the case when there is no old RAI at all.

Several RAI patch counter assertions are also added to
test_gbproxy_ra_patching().

Sponsored-by: On-Waves ehf
2014-09-18 13:20:58 +02:00
Jacob Erlbeck
991606b57a gbproxy/test: Add/modify test cases
Add a Attach Request message to test_gbproxy_ra_patching, where the
BSSGP RAI differs from the old RAI signalled in the LLC part. This
case had not been tested explicitely yet.

Change the RAI in the first Attach Request in
test_gbproxy_imsi_acquisition from rai_unknown to rai_bss.

Add Detach Requests to test_gbproxy_imsi_acquisition, one for a
incomplete attach procedure and one for an unknown (fresh) TLLI.
In these cases, the acquisition of a IMSI is not necessary and also
doesn't work properly with an E71.

Sponsored-by: On-Waves ehf
2014-09-18 11:26:07 +02:00
Jacob Erlbeck
2fd1ba4c6d gbproxy: Replace 'mi_data' by 'imsi'
Since at all places where mi_data/mi_data_len is used it will always
contain an IMSI. Thus the names of the identifiers have been updated
accordingly for clarity.

Sponsored-by: On-Waves ehf
2014-09-18 11:22:15 +02:00
Jacob Erlbeck
6bafa4ce0d gbproxy: Rework gbproxy_imsi_acquisition
This commit changes gbproxy_imsi_acquisition as follows:

tlli_info->mi_data_len is used instead of parse_ctx->imsi to check,
whether the IMSI is known already. Since the function is always
called after gbproxy_update_tlli_ul(), the two values are already
synchronized.

Messages are always flushed when the IMSI gets known, if the current
message is IDENT RESP discard it, otherwise continue processing as
usual.

The 'if' clauses are simplified for better readability.

Sponsored-by: On-Waves ehf
2014-09-18 11:21:57 +02:00
Jacob Erlbeck
0b243a106a gbproxy: Refactor gbprox_process_bssgp_ul into smaller functions
gbprox_process_bssgp_ul has grown quite large mainly by the addition
of IMSI acquisition.

This patch moves that code into several smaller functions. In
addition, the peer resolution which is similar to that in
gbprox_process_bssgp_dl is moved into a separate function, too.

Sponsored-by: On-Waves ehf
2014-09-18 08:49:21 +02:00
Pablo Neira Ayuso
ee11bc0f5c osmux: send osmux stats in MGCP DLCX responses
This allows us to know what number of messages and bytes has been
received per active osmux endpoint.

Note that an Osmux message is composed of several chunks. Each chunk
contains an osmux header plus several voice data frames.

 P: PS=385, OS=11188, PR=195, OR=5655, PL=0, JI=49
 X-Osmo-CP: EC TIS=0, TOS=0, TIR=0, TOR=0
 X-Osmux-ST: CR=51, BR=3129

The new 'X-Osmux-ST:' notifies the received chunks and bytes.
2014-09-17 19:34:25 +02:00
Holger Hans Peter Freyther
8d2fe43c7f nitb: Don't mention the broken PCAP generation option
The PCAP option doesn't seem to work for TCP/IP based BTS. Don't
mention it to not confuse people that search for a way.
2014-09-16 18:13:44 +02:00
Pablo Neira Ayuso
115e81ee19 osmux: account extracted traffic from the osmux batch
Use struct mgcp_rtp_end statistics to account the RTP messages
that has been extracted from the osmux batch and transmitted.
2014-09-16 14:32:37 +02:00
Jacob Erlbeck
1abfdc218e gbproxy: Remove patch_mode, update initial checks
This patch removes the patch_mode feature including the related VTY
command patch-mode. Where sensible, the other configuration flags are
queried instead.

In addition, this initial checks in gbprox_process_bssgp_dl() and
gbprox_process_bssgp_ul() have been updated.

The patch mode feature has not been used and was increasingly
difficult to maintain.

Sponsored-by: On-Waves ehf
2014-09-09 10:10:25 +02:00
Jacob Erlbeck
7fb26c2943 gbproxy/test: Add assertions, improve test coverage
This patch add explicit tests for
  - gbproxy_peer_by_bvci
  - gbproxy_peer_by_nsei
  - gbproxy_cleanup_peers
  - gbproxy_peer_by_rai
  - gbproxy_peer_by_lai
  - gbproxy_peer_by_lac
and for messages with an unknown TLLI sent by the SGSN.

Sponsored-by: On-Waves ehf
2014-09-09 10:10:12 +02:00
Jacob Erlbeck
31591142e9 gbproxy: Reset IMSI acquisition and free stored messages in tlli_info
Currently the stored messages are only removed, when IMSI acquisition
has succeeded. In addition, receiving two ATTACH_REQ messages in
sequence (e.g. due to loss of a Identity Req/Resp message) will not
restart the IMSI acquisition procedure.

This patch adds gbproxy_tlli_info_discard_messages() to clean up the
message list and calls it from gbproxy_delete_tlli() fixing a
potential memory leak. It is also called when an Attach Request
message has been received. In that case the imsi_acq_pending flag is
cleared, too. This would (re-)trigger the IMSI acquisition procedure
at each of these messages. If an Ident Response has been lost,
resending the Ident Request with the same N(U) will not work.
Therefore the N(U) gets incremented on each Ident Request generated
by the gbproxy. The first N(U) used is 256 which shouldn't collide
with the V(UT) used by the SGSN given that P-TMSI patching is enabled
(since a new random TLLI is used initially on every new (no
tlli_info) connection and V(U) starts with zero then).

Ticket: OW#1261
Sponsored-by: On-Waves ehf
2014-09-09 10:10:00 +02:00
Jacob Erlbeck
ea1698e322 gbproxy/test: Add test cases for IMSI acquisition
If the Attach Request procedure gets restarted e.g. because of a lost
message, all of these messages are stored if IMSI acquisition is in
progress.

This patch adds a test for this case and modifies the dump_peers
function to output the number of stored messages.

Note that the number of stored messages currently increases with each
(repeatedly) received Attach Request which is not the desired behaviour.

Sponsored-by: On-Waves ehf
2014-09-09 10:09:50 +02:00
Jacob Erlbeck
b1ee5cd3b6 gbproxy: Fix P-TMSI reassignment
Currently, a new P-TMSI within an Attach Accept or within an RA
Update Request is applied to the TLLI mapping (gbproxy_reassign_tlli)
_before_ patching is done. This can lead to inconsistent behaviour
when the TLLI validation has not been completed, which is the case
when subsequent RA UDP REQ are received. The new TLLI must not be
applied to the message itself yet, it should only be considered for
following messages.

This patch moves the TLLI reassignment to
gbproxy_update_tlli_state_after() to fix that.

It also separates the implementation of the feature that a new
tlli_info can be created when such a message is received from the
SGSN. This makes sense, when P-TMSI patching is not active and the
tlli_info entry has expired.

Sponsored-by: On-Waves ehf
2014-09-09 10:05:56 +02:00
Jacob Erlbeck
37fda77814 gbproxy: Change creation of tlli_info for SGSN originated messages
Currently tlli_info are created for SGSN originated messages when
the SGSN TLLI cannot be found and P-TMSI patching is active. This
doesn't make much sense, since the BSS side TLLI is not known in this
case. Given that the SGSN is working properly, that can only happen
if either the tlli_info has expired or the gbproxy has been
restarted.

This patch disables the creation of a tlli_info in this case.

Note that these messages are passed unmodified to the MS so far.

Sponsored-by: On-Waves ehf
2014-09-09 09:47:03 +02:00
Jacob Erlbeck
52f070a099 gbproxy/test: Extend P-TMSI patch test by a sequence of RA UDP REQ
This adds a sequence of two RA update procedures to
test_gbproxy_ptmsi_patching(). Each of them assigns a new P-TMSI.

Note that the implementation fails to patch the RAI within the
message labelled 'RA UDP ACC (P-TMSI 3)' and logs 'TLLI sent by the
SGSN is unknown'.

Sponsored-by: On-Waves ehf
2014-09-08 13:34:13 +02:00
Jacob Erlbeck
cd9e1c94e5 gbproxy: Reorganize VTY commands
Since the secondary SGSN selection and APN patching can both be
enable/disabled by IMSI matching, this patch introduces a separate
match-imsi command and removes the corresponding variant of the
core-access-point-name command.

P-TMSI patching and IMSI acquisition are enabled/disabled by
match-imsi resp. secondary-sgsn. The patch-ptmsi and acquire-imsi
commands are still available for internal testing but are subject to
being removed.

Sponsored-by: On-Waves ehf
2014-09-08 10:54:20 +02:00
Jacob Erlbeck
146e30736d gbproxy: Show number of stored messages in VTY show
This patch extends the 'show gbproxy tllis' command to display the
number of stored messages per tlli_info if there are any.

Sponsored-by: On-Waves ehf
2014-09-08 10:20:18 +02:00
Jacob Erlbeck
1e65b0e7a1 gbproxy: Forward SGSN originated STATUS messages with BVCI
Currently all STATUS messages coming from the SGSN are just logged
and dropped. This prevents the PCU from recognising that the
(secondary) SGSN doesn't know about a certain BVCI and might require
a reset procedure.

This patch changes gbprox_rx_sig_from_bss() to forward STATUS
messages with cause "Invalid BVCI" containing a BVCI to the BSS.

Note that this will not forward broken "Invalid BVCI"
messages which do not include a BVCI IE.

Sponsored-by: On-Waves ehf
2014-09-08 10:20:18 +02:00
Jacob Erlbeck
17b42b81f0 gbproxy: Make STATUS messages spec compliant
Currently the gbproxy sends STATUS messages that are not compliant to
GSM 08.18, 10.4.14.1: The BVCI must be included if (and only if) the
cause is either "BVCI blocked" or "BVCI unknown".

This patch adds a missing BVCI to UNKNOWN_BVCI and BVCI_BLOCKED
status messages if the BVCI is available. Otherwise, INV_MAND_INF is
used instead.

Sponsored-by: On-Waves ehf
2014-09-08 10:20:18 +02:00
Jacob Erlbeck
18a3787296 gbproxy: Check tlli_info when patching, fix APN patching
Currently the numeric TLLI or tlli_info's enable_patching flag is
used to decide, whether a APN shall be patched or the secondary SGSN
shall be used. Using the numeric TLLI imposes a problem, when
TLLI/P-TMSI patching is used, since gbproxy_check_tlli uses the BSS
side TLLI namespace when trying to get the tlli_info.

This patch modifies the gbproxy_check_tlli() function to accept a
tlli_info pointer instead of a numeric TLLI. The tlli_info is already
available when the function is called. Since this a similar approach
has been used by accessing the enable_patching flag directly, this
commit unifies checking by always using this function instead of the
flag outside of gb_proxy_tlli.c.

This fixes the APN patching that doesn't work currently when P-TMSI
patching is enabled.

Sponsored-by: On-Waves ehf
2014-09-08 10:20:16 +02:00
Jacob Erlbeck
82add78f89 gbproxy/test: Check APN patching while P-TMSI patching is enabled
This commit adds a single ACT PDP CTX REQ message to
test_gbproxy_ptmsi_patching() to check whether APN patching works in
this case, too.

Note that this doesn't work currently, the APN patch count is not
incremented.

Sponsored-by: On-Waves ehf
2014-09-08 09:27:41 +02:00
Jacob Erlbeck
25f98e618a gbproxy: Add missing commands to VTY write
Currently the new command acquire-imsi and secondary-sgsn are not
included into the write command's output.

This is fixed by this commit.

Sponsored-by: On-Waves ehf
2014-09-08 09:27:41 +02:00
Jacob Erlbeck
c1c57d3a26 gbproxy: Copy uplink messages to SGSN 2
Some messages that are related to the BVC itself must be forwarded to
the secondary SGSN, too.

This patch implements this for BVC-RESET (BVCI != 0) and FLOW-CONTROL-BVC
messages. The resulting acknowledgement messages from the secondary
SGSN are silently dropped. The idea behind this is that the primary
SGSN is responsible for setting up and maintaining the BVC whereas
the secondary SGSN is rather passive and just has to accept it.

Ticket: OW#1258
Sponsored-by: On-Waves ehf
2014-09-08 09:27:41 +02:00
Jacob Erlbeck
cabd24b33f gbproxy: Use secondary SGSN if IMSI matches
This patch modifies gbprox_process_bssgp_ul() to send the message to
the secondary SGSN if the IMSI has matched and routing to the
secondary SGSN is enabled. The destination for stored messages is
modified accordingly.

Ticket: OW#1261
Sponsored-by: On-Waves ehf
2014-09-08 09:27:36 +02:00
Jacob Erlbeck
f181f9ec2a gbproxy/test: Add test case for secondary SGSN
This patch adds a case to test the establishment (and shutdown) of
connection between 2 MS and 2 SGSN, where the assignment is based
on each IMSI. Since BVC-RESET and FLOW-CONTROL-BVC will have to be
sent to both SGSN, an ACK is simulated for both.

New functions to generate FLOW-CONTROL-BVC(-ACK) messages are
provided.

It modifies dump_peers to add the string "IMSI matches" to a TLLI dump
line if appropriate.

Note that there is no real support to use a secondary SGSN in the
gbproxy yet, but the test code reflects the expected behaviour when
the feature is implemented.

Sponsored-by: On-Waves ehf
2014-09-08 09:12:02 +02:00
Jacob Erlbeck
f4d60c8788 gbproxy: Support a secondary SGSN
This patch refactors SGSN NSEI handling to support a secondary SGSN.

It adds the following VTY commands:
  - secondary-sgsn nsei <0-65534>
  - no secondary-sgsn

Sending messages to the secondary SGSN is not yet implemented, but
received messages from such a SGSN would be forwarded to the BSS
peers.

Sponsored-by: On-Waves ehf
2014-09-08 09:11:59 +02:00
Jacob Erlbeck
5930064700 gbproxy: Add missing gbprox_process_bssgp_ul() return check
This should have been part of the 'Implement IMSI acquisition'
commit, where a similar change has been made for BSS originated PTP
messages.

Sponsored-by: On-Waves ehf
2014-09-08 09:04:01 +02:00
Jacob Erlbeck
1a8dbc4fc9 gbproxy: Fix warnings
This patch fixes the remaining 'unused' warnings.

Sponsored-by: On-Waves ehf
2014-09-07 10:46:10 +02:00
Holger Hans Peter Freyther
56cb729907 bsc: Add a "IPA PING" to the SCCP CR messages
We want to reduce the background traffic and might set the ping
interval to be in the range of minutes. But this means that if
the TCP connection is frozen several "SCCP CR CM Service Requests"
will be stuck in the send queue without ever being answered. I
could have used the logic of not receiving the "SCCP CC" to close
the connection but instead I am introducing an overload to schedule
the ping as part of the normal SCCP connection establishment.

The VTY write case has been manually verified, I have also looked
at a single trace to see that the SCCP CR and the IPA PING is
transfered in the same ethernet frame.
2014-09-05 12:25:32 +02:00
Holger Hans Peter Freyther
0169971a59 mgcp: Re-load the state after the transcoding change
Jacob ran the tests with ASAN and noticed that the state is
dead. This is on purpose as we have forced a change in the
transcoding. Re-load the state and verify that it has not
changed in the other cases.
2014-09-05 12:25:32 +02:00
Holger Hans Peter Freyther
0454e32861 mgcp: Use l16 in the test
G729 might not be available, so execute the test with codecs that
are always available.
2014-09-02 12:16:22 +02:00
Jacob Erlbeck
5f4ef321a6 gbproxy: Implement IMSI acquisition
To modify or route messages based on the IMSI the latter must be known
when the action shall take place.

This patch modifies the gbproxy to optionally retain and enqueue
messages from the MS while initiating an identification procedure.
Further message processing of the LLC PTP link towards the SGSN will
be done, when the identity of the MS has been acquired.

Note that the N(U) of the LLC GMM SAPI are not adjusted, so it is
possible that adjacent messages of a single LLC link arriving either
at the BSS or the SGSN have the same N(U) and might get discarded,
leading to retransmissions and additional delay.

Note also that retransmissions and packet loss are not yet handled
explicitely. If for instance the generated IDENT REQ gets lost, the
gbproxy will not act on its own. In this case, the MS will time out
and eventually resend the Attach Request on which the gbproxy will
act exactly like before (thus having two Attach Req messages in its
queue, which will both be sent after the Ident Resp arrives).

This has been tested successfully with an E71, needing one
retransmission by the SGSN due to an N(U) collision.

Ticket: OW#1261
Sponsored-by: On-Waves ehf
2014-09-02 09:53:47 +02:00
Jacob Erlbeck
28fe98891f gbproxy/test: Add a test for IMSI acquisition
This patch copies test_gbproxy_ptmsi_patching to
test_gbproxy_imsi_acquisition as a base for a later test for IMSI
acquisition (which is not yet implemented). The idea behind this is
to make the different behaviour visible in the ok file without
compromising the P-TMSI test.

Sponsored-by: On-Waves ehf
2014-09-02 09:53:42 +02:00
Jacob Erlbeck
4b663ac34a gbproxy: Create STATUS message with original PDU
Currently when patching is enabled and an error happens when
receiving a message from the SGSN, the patched message is sent back
with the PDU_IN_ERROR IE.

This patch modifies gbprox_rx_sig_from_sgsn() to copy the message
before it is patched, so that the original message can be used with
the STATUS message. gbprox_rx_ptp_from_sgsn() does all checks before
the message is patched, so copying is not necessary.

Since gbprox_rx_sig_from_sgsn() is not called for BSSGP UNITDATA
messages and the msgb is already been copied in the gbprox_relay2peer
function, the relative performance impact is expected to be low.

Note that the PDU IE of STATUS messages received from an MS and
forwarded to the SGSN will not be patched. STATUS messages from the
SGSN are only logged and not forwarded to the MS.

Sponsored-by: On-Waves ehf
2014-09-02 09:53:38 +02:00
Jacob Erlbeck
299389a99f gbproxy/test: Test patching BSSGP SUSPEND/LLC-DISCARDED
Currently messages like these with a TLLI IE (BSSGP) are not
tested (properly) with TLLI patching.

This patch extends the send_bssgp_suspend* functions to accept a
TLLI as argument and adds the send_bssgp_llc_discarded function.
These are then used in test_gbproxy_ptmsi_patching() with a valid
TLLI.

Note that the TLLI IE patching doesn't work currently.

Sponsored-by: On-Waves ehf
2014-09-02 09:53:34 +02:00
Jacob Erlbeck
46f1d6fddb gbproxy: Move PTP message handling into separate functions
This patch adds gbprox_rx_data_from_sgsn() and
gbprox_rx_ptp_from_bss() which contain the PTP message processing
of gbprox_rcvmsg(). The calls to gbprox_process_bssgp_ul() are moved
from gbprox_relay2sgsn() to gbprox_rx_ptp_from_bss() and
gbprox_rx_sig_from_bss().

The goal is, to do all patching (and calls to gbprox_process_bssgp_*)
from within the gbprox_rx_* functions. Doing the patching from within
gbprox_relay2sgsn has the drawback, that the patching code cannot
call gbprox_relay2sgsn() which is needed if a single message shall
trigger a sequence of messages.

Sponsored-by: On-Waves ehf
2014-09-02 09:53:30 +02:00
Jacob Erlbeck
48bb3a37da gbproxy: Remove nonnull attributes
The compiler also uses this attribute for code elimination. If the
nonnull attribute has been given erroneously for an parameter, that
is later been checked against NULL, this check is removed silently
by the gcc if optimization is enabled. This can lead to hard-to-find
segmentation violation faults.

To be on the safe side, this patch removes all uses of the nonnull
attribute in openbsc.

Compiler:
  - gcc 4.8.2 (Ubuntu 4.8.2-19ubuntu1): no warning, segfault
  - clang 3.4 (3.4-1ubuntu3): no warning, no segfault, asm ok

Example:
  /* foo.c */
  int f(int* p) __attribute((nonnull));
  int f(int *p) {
      if (!p)
          return 0;

      return *p;
  }

  /* main.c */
  int f(int* p) __attribute((nonnull));
  int g () {
      return f(arg);
  }

  int main() {
      return g(NULL);
  }

When these files are compiled into an executable, no warnungs are
issued but it will fail with a segfault when -O2 is used (unless LTO
is active).

Compiler output (gcc -O2):
  int f(int *p) {
    0:  8b 44 24 04             mov    0x4(%esp),%eax
    4:  8b 00                   mov    (%eax),%eax
    6:  c3                      ret
  }

Sponsored-by: On-Waves ehf
2014-09-02 09:53:18 +02:00
Holger Hans Peter Freyther
e3283ec3eb Merge branch 'zecke/features/dynamic-codec-switch' 2014-09-02 09:28:44 +02:00
Holger Hans Peter Freyther
4680121fe6 mgcp: Deal with receiving another payload type
In case we get offered G729 and G711 we might have selected
G729 as the audio codec. The first packet we receive might be
G711 though. In that case we will need to change. But only if
we have a matching alternate codec payload_type. E.g. in the
case of comfort noise we will receive the PT=11 and we don't
want to change.
2014-09-02 09:27:45 +02:00
Holger Hans Peter Freyther
e46bc2714d mgcp: Store one more codec/payload type if it is present
In case of some RTP proxy from time to time we are offered both
G729 and G711 but only one of them will work. I intend to adjust
the codec at runtime in case we receive the wrong codec.
2014-09-02 09:22:19 +02:00
Holger Hans Peter Freyther
fa80d07de0 mgcp: Group codec reset and put it to a separate method. 2014-09-02 08:25:49 +02:00
Holger Hans Peter Freyther
cac2438b0c mgcp: Move the "codec" params to a struct
We might be offered multiple codecs by the remote and need to
switch between them once we receive data. Do this by moving it
to a struct so we can separate between proposed and current
codec. In SDP we can have multiple codecs but a global ptime.
The current code doesn't separate that clearly instead we write
it to the main codec.
2014-09-02 08:25:49 +02:00
Holger Hans Peter Freyther
3713f78ac2 mgcp: Use the rtp_hdr structure and extract ts/seq from there
Use the rtp_hdr structure. The basic alignment issue remains
and I need to merge/cherry-pick Jacob's getters for the ts,
sequence number and other attributes.
2014-09-02 08:25:49 +02:00
Pablo Neira Ayuso
c20a661272 osmux: osmux batch-factor can't be higher than 8
The osmux header uses a counter of 3 bits, so you can put up to
8 message in it.
2014-09-01 20:07:27 +02:00
Pablo Neira Ayuso
fcec6d85d0 osmux: save specific osmux configuration options if osmux is enabled
Just like other options do, to avoid polluting the configuration file
with unused options if osmux is disabled.
2014-09-01 20:06:43 +02:00
Pablo Neira Ayuso
9224010859 configure: fix unrecognized option --enable-external-tests
./configure --help indicates:

  --enable-external-tests Include the VTY/CTRL tests in make check
                          [default=no]
but

./configure ... --enable-external-tests
configure: WARNING: unrecognized options: --enable-external-tests

the name of the option seems to be --enable-ext-tests.
2014-09-01 18:35:15 +02:00
Pablo Neira Ayuso
08726e2837 osmux: initialize osmux_batch_size in mgcp config
The library allows to indicate zero as batch size if you want to use
the default size, however openbsc saves 'osmux batch-size 0' which is
not good as input.

Use OSMUX_BATCH_DEFAULT_MAX to explicitly initialize the batch size
from mgcp_parse_config().
2014-08-30 07:59:41 +02:00
Pablo Neira Ayuso
03ab79abac osmux: add 'osmux batch-size NUM' option to mgcp vty
This allows you to specify the osmux batch frame size. If zero, the
library uses the default value.
2014-08-29 12:30:38 +02:00
Pablo Neira Ayuso
308d5f8912 osmux: set default port from mgcp_parse_config() 2014-08-29 12:21:58 +02:00
Holger Hans Peter Freyther
73ec6980d5 nat: Introduce a config free for the test and fix valgrind issues
The talloc_free on the nat lead to the freeing of the bsc_config
which lead to freeing of the rate_ctr_group. The rate_ctr_group
remained in a global list and the next creation of a bsc_config
would access dead memory. Fix it.

The free routine is only meant to be used by the test, for the
real nat we would need to make sure that all connections and
other state that refers to the cfg is removed/closed first.

Fix various memleaks in the test while we are at it. There are
still some to fix.

==7195== Invalid write of size 4
==7195==    at 0x4043171: rate_ctr_group_alloc (linuxlist.h:65)
==7195==    by 0x804D893: bsc_config_alloc (bsc_nat_utils.c:174)
==7195==    by 0x804B5D2: main (bsc_nat_test.c:954)
==7195==  Address 0x4311cbc is 52 bytes inside a block of size 208 free'd
==7195==    at 0x4029D28: free (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==7195==    by 0x4048D98: _talloc_free (talloc.c:609)
==7195==    by 0x4052806: talloc_free (talloc.c:578)
==7195==    by 0x804B58A: main (bsc_nat_test.c:940)
2014-08-29 11:42:34 +02:00
Holger Hans Peter Freyther
dc16bdd369 nat: Remove the entry from the list before we destroy it 2014-08-29 11:42:26 +02:00
Holger Hans Peter Freyther
cd48525ecb nat: Fix compiler warning about unknown prototype
bsc_nat_ctrl.c: In function ‘set_net_cfg_cmd’:
bsc_nat_ctrl.c:360:3: warning: implicit declaration of function ‘bsc_replace_string’ [-Wimplicit-function-declaration]
   bsc_replace_string(bsc_cfg, &bsc_cfg->acc_lst_name, cmd->value);
   ^
2014-08-29 11:42:26 +02:00
Holger Hans Peter Freyther
fcc30a3df7 gprs: Document the stale option in delete-gbproxy-tlli 2014-08-29 10:51:44 +02:00
Pablo Neira Ayuso
dfa91df289 tests: bsc-nat: fix bsc_mgcp_rewrite() with osmux
Pass -1 to indicate no osmux, before ("b769f3c osmux: add osmux
circuit ID management and resolve NAT problems"), 0 was indicating
no osmux.
2014-08-29 09:14:37 +02:00
Jacob Erlbeck
ecbd56c625 gbproxy: Fix issues found by Coverity
gbproxy_patch_bssgp: Move a check for tlli_info in front of the first
conditional that depends on it, and return immediately if it is NULL.

gbproxy_register_tlli: Initialize tlli_already_known to 0.

Fixes: Coverity CID 1232691
Fixes: Coverity CID 1232692
Sponsored-by: On-Waves ehf
2014-08-29 08:50:40 +02:00
Pablo Neira Ayuso
3ba3cf85e1 osmux: fix unchecked return value in mgcp_parse_osmux_cid()
** CID 1232804:  Unchecked return value  (CHECKED_RETURN)
/src/libmgcp/mgcp_protocol.c: 888 in mgcp_parse_osmux_cid()
2014-08-29 08:46:54 +02:00
Pablo Neira Ayuso
4ef66b1c5f osmux: fix leak in osmux_deliver()
The callback is responsible for releasing the batch message that
libosmo-netif builds.
2014-08-28 20:14:12 +02:00
Pablo Neira Ayuso
caa0aace21 osmux: fix access to uninitialized memory area in scheduled_tx_*_cb
mgcp_send() needs some initialized address when printing a log message.
Nothing really serious but let's calm down valgrind.
2014-08-28 19:50:41 +02:00
Pablo Neira Ayuso
7a83f4d264 osmux: rename osmux.c to mgcp_osmux.c
So we can easily identify in the log message what refers to
libosmo-netif and what to libmgcp.
2014-08-28 19:40:51 +02:00
Pablo Neira Ayuso
91ca4a77b7 osmux: remove spamming debug log messages
It may print a debug line every 20ms, so disable this. We can still
compile this extra spamming debug from the libosmo-netif library.
2014-08-28 17:25:28 +02:00
Pablo Neira Ayuso
f892763b0f osmux: use osmux port when specified from vty from engine
Instead of the hardcoded OSMUX_PORT.
2014-08-28 16:51:30 +02:00
Pablo Neira Ayuso
eb7aeb19a2 osmux: print out 'osmux port' when saving configuration 2014-08-28 16:48:55 +02:00
Pablo Neira Ayuso
0fe78d39bd osmux: allow to specify the Osmux port
via mgcp section from the configuration file.
2014-08-28 16:43:38 +02:00
Pablo Neira Ayuso
36a03bdfcb osmux: display statistics once osmux input handle is released 2014-08-28 16:34:40 +02:00
Pablo Neira Ayuso
1c81045521 osmux: fix error path in osmux_handle_dummy()
This patch adds a missing goto err. While at it, reword log message.
2014-08-28 15:37:04 +02:00
Pablo Neira Ayuso
1e1558f548 osmux: remove spamming log message
Not very useful:

<000b> osmux.c:163 Osmux uses CID 1 from endpoint=7 (active=1)

Get rid of it.
2014-08-28 15:07:56 +02:00
Pablo Neira Ayuso
a1efcc26cb osmux: remove redundant log message when bsc doesn't want to use Osmux
Remove redundant information log message:

<000b> bsc_mgcp_utils.c:647 BSC doesn't want to use Osmux, failing back to RTP
<000b> bsc_mgcp_utils.c:669 bsc didn't accept to use Osmux (cid=0)

One single log message is just fine. The error path already indicates
the precise reason not to accept the request to use Osmux.
2014-08-28 14:50:48 +02:00
Pablo Neira Ayuso
72b187be6d osmux: cleanup osmux input handle on release
Use osmux_xfrm_input_fini() to release the internal state of the osmux
input handle.
2014-08-28 12:47:21 +02:00
Pablo Neira Ayuso
b769f3ce0b osmux: add osmux circuit ID management and resolve NAT problems
This patch includes several osmux fixes that are interdependent:

1) This adds Osmux circuit ID, this is allocated from the bsc-nat. This
   announces the circuit ID in the CRCX MGCP message. This aims to resolve
   the lack of uniqueness due to the use of endp->ci, which is local to
   the bsc. This ID is notified via X-Osmux: NUM where NUM is the osmux
   circuit ID.

2) The dummy load routines are now used to setup osmux both in bsc and
   bsc-nat to resolve source port NAT issues as suggested by Holger. The
   source port that is used from the bsc is not known until the first
   voice message is sent to the bsc-nat, therefore enabling osmux from
   the MGCP plane breaks when a different source port is used.

3) Add refcnt to struct osmux_handle, several endpoints can be using the
   same input RTP osmux handle to perform the batching. Remove it from the
   osmux handle list once nobody is using it anymore to clean it up.

4) Add a simple Osmux state-machine with three states. The initial state
   is disabled, then if the bsc-nat requests Osmux, both sides enters
   activating. The final enabled state is reached once the bsc-nat sees
   the dummy load message that tells what source port is used by the bsc.

5) The osmux input handle (which transforms RTP messages to one Osmux batch)
   is now permanently attached to the endpoint when Osmux is set up from the
   dummy load path, so we skip a lookup for each message. This simplifies
   osmux_xfrm_to_osmux().

After this patch, the workflow to setup Osmux is the following:

                    bsc                   bsc-nat
                     |                       |
                     |<------ CRCX ----------|
                     |      X-Osmux: 3       | (where 3 is the Osmux circuit ID
                     |                       |  that the bsc-nat has allocated)
                     |------- resp --------->|
                     |      X-Osmux: 3       | (the bsc confirm that it can
                     |                       |  use Osmux).
                     .                       .
                     |                       |
         setup osmux |----- dummy load ----->| setup osmux
                     |      Osmux CID: 3     |

In two steps:

1st) Allocate the Osmux Circuit ID (CID): The bsc-nat allocates an unique
     Osmux CID that is notified to the bsc through the 'X-Osmux:' extension.
     The bsc-nat annotates this circuit ID in the endpoint object. The bsc
     replies back with the 'X-Osmux:' to confirm that it agrees to use Osmux.
     If the bsc doesn't want to use Osmux, it doesn't include the extension
     so the bsc-nat knows that it has to use to RTP.

2nd) The dummy load is used to convey the Osmux CID. This needs to happen
     at this stage since the bsc-nat needs to know what source port the bsc
     uses to get this working since the bsc may use a different source
     port due to NAT. Unfortunately, this can't be done from the MGCP signal
     plane since the real source port is not known that the bsc uses is not
     known.

This patch also reverts the MDCX handling until it is clear that we need
this special handling for this case.
2014-08-28 12:08:29 +02:00
Pablo Neira Ayuso
8be171e88f osmux: move osmux socket initialization out of osmux_enable_endpoint()
In the bsc-nat side, the osmux socket initialization can be done from
the vty. This ensure that the osmux socket is available by the time the
bsc-nt receives the dummy load that confirms that the osmux flow has
been set up.

This change is required by the follow up patch. This change ensures that
the Osmux socket in the bsc-nat is already in place by the time this
receives the dummy load.
2014-08-27 16:56:08 +02:00
Pablo Neira Ayuso
fd1d961af5 osmux: split osmux_handle_lookup() in several functions
This is a cleanup to allow the reuse of the new functions
osmux_handle_find_get() and osmux_handle_alloc().
2014-08-27 16:31:40 +02:00
Pablo Neira Ayuso
63650bbc5d osmux: encapsulate for osmux state information in struct mgcp_endpoint
Just a cleanup, wrap around the osmux state information in a struct.
2014-08-27 14:37:57 +02:00
Holger Hans Peter Freyther
a4faeb1a79 gprs: Attempt to fix distcheck by adding the header file
Due libdbi 0.9.x being broken I didn't run make distcheck and
apparently Jacob has a similar issue and didn't run it either.
2014-08-25 16:15:04 +02:00
Harald Welte
7ff4f0e0fc port over to libosmocore include/osmocom/gsm/meas_rep.h
Back in March 2013, some structures and defines related to decoded
measurement reports have been moved from openbsc to libosmocore
(libosmocore e128f4663104ed64e33e362cff2566f36d65e658) so that they can
be used also from osmo-bts.  This finally makes gsm_lchan follow suit
for osmo-bts.
2014-08-25 09:20:33 +02:00
Holger Hans Peter Freyther
5160996d4a gprs: Link gbproxy to -lrt for clock_gettime
On older GNU libc systems we need to link to this library to
use the clock_gettime symbol.
2014-08-25 07:29:15 +02:00
Harald Welte
55dc31e781 Use port number #defines for VTY and CTRL ports
.. as defined in libosmocore
2014-08-24 17:54:49 +02:00
Harald Welte
6e68808247 move GSM_RESERVED_TMSI to libosmocore
The gb_proxy shouldn't start to open the box of pandora by including the
gsm_data_shared.h file, particularly not without defining the BSC role.

In any case, as the reserved TMSI is something that's part of the GSM
specs, and not specific to the OpenBSC implementation, it should be part
of libosmocore.
2014-08-24 17:38:18 +02:00
Harald Welte
101c5c2a3a gsm_data_shared: Add new trx_power_params for osmo-bts 2014-08-24 16:44:43 +02:00
Holger Hans Peter Freyther
ddbbe695b3 Merge Jacob's GPRS GB Proxy related configs
All review feedback will be addressed _after_ the split of the
files. This is the only reasonable approach to get the split of
files merged. I didn't have the time to review all of the code
before the point of splitting.
2014-08-24 16:18:26 +02:00
Jacob Erlbeck
5f1faa3cd2 gbproxy: Move peer definitions to gb_proxy_peer.c
This patch moves the peer related definitions from gb_proxy.c to
gb_proxy_peer.c and adjusts the prefix of each global symbol to
gbproxy_:

Peer definitions (prefix adjusted to gbproxy_):
  peer_ctr_description -> gprs/gb_proxy_peer.c (static)
  peer_ctrg_desc -> gprs/gb_proxy_peer.c (static)
  *peer_by_* -> gprs/gb_proxy_peer.c
  gbproxy_peer_alloc -> gprs/gb_proxy_peer.c
  gbproxy_peer_free -> gprs/gb_proxy_peer.c
  gbprox_cleanup_peers -> gprs/gb_proxy_peer.c

Sponsored-by: On-Waves ehf
2014-08-24 16:16:40 +02:00
Jacob Erlbeck
9114bee242 gbproxy: Refactor gb_proxy.c into several files
This patch moves several functions and declarations out of gb_proxy.c
to make them reusable by other components and to separate them by
context and task.

Counter enums (prefix is changed to gbproxy_):
  enum gbprox_global_ctr -> gprs/gb_proxy.h
  enum gbprox_peer_ctr -> gprs/gb_proxy.h

Generic Gb parsing (prefix is changed to gprs_gb_):
  struct gbproxy_parse_context -> openbsc/gprs_gb_parse.h
  gbprox_parse_dtap() -> gprs/gprs_gb_parse.c
  gbprox_parse_llc() -> gprs/gprs_gb_parse.c
  gbprox_parse_bssgp() -> gprs/gprs_gb_parse.c
  gbprox_log_parse_context() -> gprs/gprs_gb_parse.c
  *_shift(), *_match() -> gprs/gprs_gb_parse.c (no prefix)
  gbprox_parse_gmm_* -> gprs/gprs_gb_parse.c (static)
  gbprox_parse_gsm_* -> gprs/gprs_gb_parse.c (static)

MI testing/parsing (prefix gprs_ added):
  is_mi_tmsi() -> gprs/gprs_utils.c
  is_mi_imsi() -> gprs/gprs_utils.c
  parse_mi_tmsi() -> gprs/gprs_utils.c

TLLI state handling (prefix is changed to gbproxy_):
  gbprox_*tlli* -> gprs/gb_proxy_tlli.c
  (except gbprox_patch_tlli, gbproxy_make_sgsn_tlli)

Message patching (prefix is changed to gbproxy_):
  gbprox_*patch* -> gprs/gb_proxy_patch.c
  gbprox_check_imsi -> gprs/gb_proxy_patch.c

Sponsored-by: On-Waves ehf
2014-08-24 16:16:40 +02:00
Jacob Erlbeck
6bd7ded71e gbproxy/test: Add test for TLLI patching
Add LLC test messages containing XID (SAPI LLGMM, U frame) and IP traffic
(SAPI LL11, UI frame).

Add a test case containing a complete SGSN session with TLLI/PTMSI
patching enabled.

Sponsored-by: On-Waves ehf
2014-08-24 16:16:40 +02:00
Jacob Erlbeck
0d37671824 gbproxy: Use different TLLI/P-TMSI for BSS and SGSN
This patch modifies gbprox_make_bss_ptmsi() to generate a new P-TMSI
when patch_ptmsi is set in the configuration instead of using the
P-TMSI assigned by the SGSN. It modifies gbprox_make_sgsn_tlli() to
either use a foreign TLLI based on the SGSN side P-TMSI or (if there
is none) generate a random TLLI if patch_ptmsi is set. Otherwise, the
TLLI used by the BSS is used.

The seeds for the pseudo-random sequences sre set based on time
initially. Note that these are neither cryptographically safe nor
protected against collisions.

Ticket: OW#1259
Sponsored-by: On-Waves ehf
2014-08-24 16:16:40 +02:00
Jacob Erlbeck
643d5228ed gbproxy: Add context info to log messages
This mainly adds the NSEI to the messages, similar to log messages
ogf the existing gbproxy code.

Sponsored-by: On-Waves ehf
2014-08-24 16:16:40 +02:00
Jacob Erlbeck
03ca10e863 gbproxy: Patch TLLI/P-TMSI
This patch adds code to modify TLLIs and P-TMSIs. Related counters
are also added.

Sponsored-by: On-Waves ehf
2014-08-24 16:16:39 +02:00
Jacob Erlbeck
e37487e083 gbproxy: Fix TLLI state handling
This patch contains fixes for the TLLI tracking and handling.
It adds and uses gbprox_map_tlli() the map the source TLLI to the
destination TLLI while respecting whether it is current or assigned.
It removes gbprox_register_tlli() from the downlink path. It fixes
TLLI validation and disables the use of the BSSGP TLLI IE.

Sponsored-by: On-Waves ehf
2014-08-24 16:16:39 +02:00
Jacob Erlbeck
3b23d639ab gbproxy: Also handle LLC non UI and LL11 messages
Currently, these messages lead to a parsing error which prevents them
from being processed any further.

This patch sets the return value of gbprox_parse_llc to 1 in these
cases and fixes a segfault which is triggered by any non-04.08
message.

Sponsored-by: On-Waves ehf
2014-08-24 16:16:39 +02:00
Jacob Erlbeck
12496dd7db gbproxy: Refactor gbprox_patch_raid(), use different RAI types properly
Currently gbprox_patch_raid() updates the local MCC/MNC with every
BSS originated message, even if the RAI is an 'old' one.

This patch separates state updating and patching into 2 functions
gbprox_update_current_raid and gbprox_patch_raid. In addition, a
field named old_raid_enc is added to gbproxy_parse_context, which is
used for 'old RAI' IEs in Attach Requests and RA Update Requests.
Only the bssg_raid_enc in BSS originated message is used to update
the BSS side 'local' MCC/MNC.

Sponsored-by: On-Waves ehf
2014-08-24 16:16:39 +02:00
Jacob Erlbeck
311592fc39 gbproxy: Refactor gbprox_get_detached_tlli_info
This patch splits the functionality of gbprox_get_detached_tlli_info
into 2 new functions:
  - gbprox_tlli_info_alloc to allocate an intialized and detached
    tlli_info
  - gbprox_detach_tlli_info to detach an already attached tlli_info

Sponsored-by: On-Waves ehf
2014-08-24 16:16:39 +02:00
Jacob Erlbeck
0d4236be54 gbproxy: Add 'patch-ptmsi' command to enable TLLI/P-TMSI patching
This VTY command add the following commands to the gbproxy node:
  - patch-ptmsi: Enables P-TMSI/TLLI patching
  - no patch-ptmsi: Disables P-TMSI/TLLI patching

Note that using these commands interactively can load to undefined
behavior of existing LLC connections.

Sponsored-by: On-Waves ehf
2014-08-24 16:16:39 +02:00
Jacob Erlbeck
9057bc3c72 gbproxy: Track SGSN and BSS TLLI/PTMSI separately
This patch separates BSS side from SGSN side TLLI/PTMSI tracking. When
TLLI/PTMSI patching is not enabled, the corresponding states shall be
identical. The TLLI/PTMSI state has been moved into the struct
gbproxy_tlli_state and is used twice in gbproxy_tlli_info.

Since the state handling for uplink and downlink messages is
diverging, gbprox_update_state() is replaced by two functions
gbprox_update_state_dl/gbprox_update_state_ul and
gbprox_process_bssgp_message() is replaced by
gbprox_process_bssgp_dl/gbprox_process_bssgp_ul.

Sponsored-by: On-Waves ehf
2014-08-24 16:16:39 +02:00
Jacob Erlbeck
c53f2a6961 gbproxy/test: Generate BSSGP and LLC layer for DTAP messages
This patch adds the functions send_bssgp_ul_unitdata(),
send_bssgp_dl_unitdata(), send_llc_ul_ui(), and send_llc_dl_ui().
They are used instead of send_ns_unitdata() in
test_gbproxy_ra_patching(). This make it easier to modify TLLI, N(U),
and other parameters.

Sponsored-by: On-Waves ehf
2014-08-24 16:16:39 +02:00
Jacob Erlbeck
425afaca2f gbproxy/test: Fix BSSGP/LLC test messages
The following parts of the messages have been fixed
  - Attach Accept: checksum
  - Attach Complete: checksum
  - RA Update Accept: Use the same MS Radio Access Capabilities and
    DRX Parameters like the other messages

The N(U) of most messages have not been fixed.

Sponsored-by: On-Waves ehf
2014-08-24 16:16:39 +02:00
Jacob Erlbeck
59748e653b gbproxy: Handle old and new P-TMSI/TLLI
Don't replace the current TLLI immediately, store it in an additional
'assigned_tlli' field and discard the old TLLI when both sides have
used the new one (see GSM 04.08, 4.7.1.5).

Add an Attach Complete message to test and check, whether the related
field of the corresponding tlli_info struct are set as expected
during the local TLLI validation cycle.

Sponsored-by: On-Waves ehf
2014-08-24 16:16:39 +02:00
Jacob Erlbeck
3c5b40fb75 gbproxy: Update enable_patching flag on existing tlli_info
Currently the enable_patching field in tlli_info is not updated,
when an IMSI is assigned to a TLLI that is already known.

This patch fixes this in gbprox_update_state() after the call to
gbprox_update_tlli_info().

The number of APN increases and the test output file is updated
accordingly.

Sponsored-by: On-Waves ehf
2014-08-24 16:16:39 +02:00
Jacob Erlbeck
3e23ddf88b gbproxy: Parse Detach Request messages
GSM 24.008 also allows a P-TMSI field in Detach request messages.

This patch adds gbprox_parse_gmm_detach_req() to parse Detach Request
messages which sets the ptmsi field if the IE is present.

In addition, when power_off is set to 1 (MO only), the
invalidate_tlli field is set, since Detach Request message is
expected in this case.

The second detach test (see 'RA update') is modified to use
power_off instead of relying on a Detach Accept from the network.
To make this work, the PTMSI of the RA Update Accept is fixed to
match the TLLI of the Detach Request.

Sponsored-by: On-Waves ehf
2014-08-24 16:16:39 +02:00
Harald Welte
1449c9f06f move gsm_bts_num() to gsm_data_shared.[ch]
this way we can drop a copy of this function from osmo-bts.
2014-08-24 12:47:12 +02:00
Holger Hans Peter Freyther
dd588ae2ce misc: Introduce a more neutral configure option for CTRL/VTY
We started with only testing the VTY but now test VTY and CTRL
interface with this python framework and might even extend this
to SMPP. So add and "--enable-external-tests" directive which
enables the external interface tests.
2014-08-22 00:29:04 +02:00
Jacob Erlbeck
29805da6d1 gbproxy: Add gbprox_clear_patch_filter() (Coverity)
Add a separate function to clear the IMSI filter to be used instead of
gbprox_set_patch_filter(cfg, NULL, ...). Albeit it fixes a Coverity
issue (Unchecked return value), it is a false positive, since the
return value is always 0 in these cases. Nevertheless it is more
obvious what happens when an explicit clear function is called. Using
NULL as filter argument of gbprox_set_patch_filter still clears the
filter.

Fixes: Coverity CID 1231255
Sponsored-by: On-Waves ehf
2014-08-22 00:21:56 +02:00
Harald Welte
d2eb5e911e fix missing '\' at end of line in Makefile.am
... causing header files to be missing from 'make dist'.

this was introduced in ba874b82be
2014-08-21 18:50:25 +02:00
Harald Welte
e263187a36 Fix bsc_ctrl_node_lookup after libctrl changes
As bsc_ctrl_node_lookup() is called for each iteration,
the variables 'bts' and 'trx' are no longer static accross multiple
calls, which means we need a different way to determine if we are in the
right node while matching for a trx or a ts.
2014-08-21 18:26:36 +02:00
Harald Welte
0ad2382131 configure.ac: Depend on libosmocore 0.7.0 2014-08-21 15:56:00 +02:00
Harald Welte
74d4adcbba libctrl: Follow rename of controlif_setup -> ctrl_interface_setup 2014-08-21 15:34:28 +02:00
Harald Welte
02cc2b668a libctrl: Move bulk of node lookup code into libosmocore
Now that the bulk of the control interface node lookup has
no reference to the BSC specific data structures, we are
moving it into libosmocore.

A control interface user now only registers an optional small
node lookup function like bsc_ctrl_node_lookup()
2014-08-21 15:34:28 +02:00
Harald Welte
a67455f8d8 ctrl_if: Split bsc_ctrl_cmd_handle() in two parts
The idea here is that bsc_ctrl_cmd_handle now has no dependency
at all to the BSC related data structures and thus can actually become
part of libctrl.

The new function bsc_ctrl_node_lookup however will remain bsc-specific.
2014-08-21 15:34:28 +02:00
Harald Welte
ba874b82be move libctrl from openbsc to libosmoctrl (libosmocore.git) 2014-08-21 15:34:28 +02:00
Daniel Willmann
0e167fc974 systemd: Add Install section to service files
That way the services can be enabled with
> systemctl enable <service>
2014-08-21 10:19:50 +02:00
Harald Welte
248b38539d Fix control interface build after IPA rename/migration 2014-08-21 00:28:55 +02:00
Harald Welte
4a88a49c03 adopt recent IPA related symbol rename
... which happened during recent migration of IPA functionality from
libosmo-abis into libosmocore.
2014-08-20 23:47:56 +02:00
Harald Welte
eb62301938 ipaccess-proxy: avoid namespace collision with libosmo-abis 2014-08-18 22:49:50 +02:00
Jacob Erlbeck
948b730fea gbproxy: Fix warnings (signed/unsigned)
Adresses:
gbproxy_test.c:1288:17: warning: comparison between signed and
unsigned integer expressions [-Wsign-compare]

Sponsored-by: On-Waves ehf
2014-08-13 11:22:03 +02:00
Jacob Erlbeck
5e68ecf3b2 gbproxy: Pass tlli_info around
This patch modifies the code to pass a pointer to the tlli_info
around once it has been acquired. To achieve this,
gbprox_register_tlli() and gbprox_update_state() are modified to
return it (if it has been found or created), and gbprox_patch_llc(),
gbprox_patch_bssgp(), and gbprox_update_state_after() are modified to
take it as parameter.

Add a new function gbprox_touch_tlli() to update timestamp and list
ordering for existing tlli_infos.

The motivation behind this patch is to make the tlli_info available to
the patching code and to avoid repeated searches for the same TLLI.

Sponsored-by: On-Waves ehf
2014-08-13 11:14:08 +02:00
Jacob Erlbeck
2dec9851bd gbproxy: Optimize gbprox_remove_stale_tllis
The current implementation of this function is O(N), where N is the
number of entries.

The new implementation is O(D), where D is the number of entries that
are going to be deleted.

Sponsored-by: On-Waves ehf
2014-08-13 10:42:27 +02:00
Jacob Erlbeck
f494620c55 gbproxy/test: More TLLI expiry testing
This patch adds a combined expiry test to remove one entry by list
length and another by age.

This patch also modifies the existing age based test to register both
TLLI with a different timestamp and to remove only one of the TLLI
entries by age based expiration.

Sponsored-by: On-Waves ehf
2014-08-13 10:42:27 +02:00
Jacob Erlbeck
7b821d031a gbproxy: Don't call time() in TLLI related functions
Currently time() is called at several places to control TLLI aging.
Beside calling time() more often than necessary, the decision which
timesource is to be used is coded into the TLLI handling, and testing
complex aging scenarios is cumbersome.

This patch passes the current time as a parameter instead. The call
to time() is moved to gbprox_process_bssgp_message().

Sponsored-by: On-Waves ehf
2014-08-13 10:42:27 +02:00
Jacob Erlbeck
aad32bccc0 gbproxy: Don't remove stale TLLI automatically
This patches removes the call to gbprox_remove_stale_tllis()
from gbprox_register_tlli(), so it must be called explicitly now.
The call is now done from within gbprox_update_state_after().

In addition, the TLLI cache size counter is also kept in sync when
gbprox_remove_stale_tllis is called manually. The call to
gbproxy_peer_free() in gbproxy_peer_free() is moved behind the TLLI
to allow for counter updates in gbprox_delete_tlli().

Sponsored-by: On-Waves ehf
2014-08-13 10:42:26 +02:00
Jacob Erlbeck
12828c1b30 gbproxy: Move parse_ctx logging into separate function
Sponsored-by: On-Waves ehf
2014-08-13 10:42:26 +02:00
Jacob Erlbeck
c812882dbf gbproxy: Refactor gbproxy_patch_bssgp_message
This patch refactors that function by separating the actual patch
code into a new function gbproxy_patch_bssgp(), similar to
gbproxy_patch_llc(). The remaining function is renamed to
gbproxy_process_bssgp_message. The existing function
gbproxy_parse_bssgp_message() is renamed to
gbproxy_process_bssgp_message to match gbproxy_parse_llc.

Sponsored-by: On-Waves ehf
2014-08-13 10:42:26 +02:00
Jacob Erlbeck
291f0508c5 gbproxy: Test and fix IMSI/TMSI matching
This adds a test for gbprox_set_patch_filter() and
gbprox_check_imsi().

It also fixes the masking of the type field when IMSIs are checked by
using GSM_MI_TYPE_MASK (0x07) instead of 0x0f.

Sponsored-by: On-Waves ehf
2014-08-13 10:41:23 +02:00
Jacob Erlbeck
89d3d343d1 gbproxy: Track TLLI even when the IMSI is not known
Currently only TLLIs for which it is known that they may be patched
are put into the TLLI list.

This patch changes this to add TLLIs even when the IMSI is not yet
known. A enable_patching flag is added to the gbproxy_tlli_info
structure to control patching.

Note that this puts every active TLLI into the list where accesses
are O(N) currently.

Sponsored-by: On-Waves ehf
2014-08-13 10:29:09 +02:00
Jacob Erlbeck
58da91d5d0 gbproxy: Make pointers to MI const in parse/check functions
The encoded mobile identity will never be modified in
is_mi_tmsi/is_mi_imsi/parse_mi_tmsi, thus the pointer is made const.

Sponsored-by: On-Waves ehf
2014-08-13 09:57:26 +02:00
Jacob Erlbeck
fb22ac52b0 gbproxy: Explicitly convert PTMSI to TLLI
This patch modifies the new_ptmsi handling by setting its two most
significant bits before using it as TLLI.

Sponsored-by: On-Waves ehf
2014-08-13 09:57:25 +02:00
Jacob Erlbeck
690768a171 gbproxy: Parse additional IMSI/PTMSI/TLLI fields
This adds parsing support for the following messages:
  - Attach Request: IMSI/PTMSI
  - Identity Response: IMSI/PTMSI
  - BSSGP: Optional TLLI IE
  - BSSGP/PAGING_PS: PTMSI

A new new_ptmsi_enc field is added for newly assigned PTMSI in
SGSN->BSS messages (instead of ptmsi_enc). The ptmsi_enc field is now
used for informational PTMSI IE in messages.

Sponsored-by: On-Waves ehf
2014-08-13 09:55:27 +02:00
Jacob Erlbeck
2db2512f4d gbproxy: Separate BSSGP parsing from patching
This adds a gbprox_parse_bssgp_message() function that contains the
parsing part of the former gbprox_patch_bssgp_message(). This
includes a call to gbprox_parse_llc().

The calls to gbprox_patch_llc(), gbprox_update_state() and
gbprox_update_state_after() have therefore been moved to
gbprox_patch_bssgp_message().

Sponsored-by: On-Waves ehf
2014-08-12 19:32:26 +02:00
Jacob Erlbeck
2bdd253d54 gbproxy: Unify TLLI tracking
This patch unifies the TLLI tracking for all LLC messages. The TLLI
state handling is moved into separate functions.

Only Detach Accept messages are taken into account to release a TLLI,
which is safe but not optimal.

Sponsored-by: On-Waves ehf
2014-08-12 19:30:48 +02:00
Jacob Erlbeck
0cee7ad2bf gbproxy: Move patching code out of the 04.08 specific functions
Currently, parsing and optionally patching is done in the same
functions (e.g. gbprox_patch_gmm_attach_req()).

This patch moves the patching code out of these functions into
gbprox_patch_llc() and just stores pointers to the relevant data
areas into parse_ctx. Consequently the len_change parameter is
removed and the _patch_ in the function's names is renamed to
_parse_. In addition, the patching_is_enabled checks and counter
increments are moved out of these functions, too.

Sponsored-by: On-Waves ehf
2014-08-12 19:29:12 +02:00
Holger Hans Peter Freyther
2c6b59ca6a sysmobts: Add variable for N(S) + 1 needed for the sysmobts
We could use the upper three bits of the ciph_state to store the
sequence number but make the code understandable first.
2014-08-09 09:43:53 +02:00
Holger Hans Peter Freyther
93dfa24f42 bsc: Add a ctrl command to send a ussdNotify for a call
Send a non-call related SS message for an active call indentified
by the CIC of that call. As an ugly hack the order of the SS
release and the invocation are changed. That was necessary for the
E71 on a TCH. The time between notify and release was just too short.
The right would be to wait for the returnResultLast but this would
involve keeping more local state. Let's see how far we get here. It
might be necessary to change the order in the other call sites as
well.
2014-08-08 21:17:36 +02:00
Holger Hans Peter Freyther
350de9fe80 ctrl: Allow the value to contain spaces. No need to split the string 2014-08-08 21:17:35 +02:00
Jacob Erlbeck
da4b492f56 gbproxy/test: Fix BSSGP RESET message size
The given msg array size doesn't match the initializer's size.

Sponsored-by: On-Waves ehf
2014-08-08 09:21:45 +02:00
Jacob Erlbeck
477c69a9c5 gbproxy: Track all TLLIs (not only LOCAL)
This patch removes all checks for the TLLI type.

Sponsored-by: On-Waves ehf
2014-08-08 08:50:14 +02:00
Holger Hans Peter Freyther
b773fbf335 sgsn: Make P-TMSI a local TLLI to avoid clash
Some broken equipment does not convert the P-TMSI to a Local TLLI.
This leads to the SGSN ignoring the GPRS Attach Complete message
from the phone. Proprietary SGSNs and some documentation we found
state that one should always set the two highest bits of a P-TMSI
to one. This will help broken equipment and will avoid a potential
P-TMSI/TLLI clash. The P-TMSI/Local TLLI mapping is now bijective.
2014-08-05 15:20:23 +02:00
Jacob Erlbeck
58cf664d28 gprs: Refactor gbprox_register_tlli()
Currently gbprox_register_tlli() is a rather complex function.

This patch splits it into several smaller functions to ease reviewing
and maintaining it.

Sponsored-by: On-Waves ehf
2014-08-05 15:11:11 +02:00
Holger Hans Peter Freyther
0196c9936c gbproxy/test: Test TLLI expiry
This adds a unit test for gbprox_register_tlli() and
gbprox_remove_stale_tllis().

The dump_peers() function is extended by a cfg parameter to support
a non-global gbproxy_config.

Done with Jacob
2014-08-05 15:02:06 +02:00
Jacob Erlbeck
d8a7e22709 gbproxy: Remove broken TLLI comparison
This comparison bit-ored the TLLI with 0xc000 instead of 0xc000000.

Since this has never worked properly yet and since normalizing to
local TLLIs doesn't seem sensible here, the comparison is removed
entirely.

Sponsored-by: On-Waves ehf
2014-08-04 17:13:17 +02:00
Holger Hans Peter Freyther
3fa26448d1 gbproxy: Kill the global gbprox_global_patch_state struct
Move this patching state into the gbproxy_config as well.

Done by Jacob
2014-08-04 16:27:11 +02:00
Holger Hans Peter Freyther
3748ada073 gbproxy: Add a hint to the compiler that all parameters are not NULL
In these functions we assume that peer is not NULL. Add a compiler
attribute in the hope that either coverity or GCC/Clang will help
us to find a misusage.

Done with Jacob
2014-08-04 16:06:20 +02:00
Holger Hans Peter Freyther
eece627799 gbproxy: Remove global state from the gbproxy
Global state prevents us from writing simple units tests for
single routines. Go through the code and add pointers to the
gbproxy configuration. Only the vty and the test code remain
using the global gbproxy instance.
2014-08-04 16:01:12 +02:00
Holger Hans Peter Freyther
fa7a8bc6eb gprs: The methods moved to gprs_utils.h remove them here
Stop declaring the apn routines in here.

Done with Jacob
2014-08-04 15:44:21 +02:00
Holger Hans Peter Freyther
ce1b22e817 gprs: Add testcases for the APN string/octet conversion and fix it
Create a testcase for the gprs_str_to_apn and gprs_apn_to_str
routines. While writing the testcase we noticed it is possible to
write more bytes than should have been allowed. This is fixed by
checking that the max_len is at least 1 (needed to write the first
length octet) and to do the size check before writing to the output.

Modify the signature of gprs_str_to_apn to put the length/size next
to the parameter that requires a size.

Done with Jacob
2014-08-04 15:00:54 +02:00
Holger Hans Peter Freyther
4d9fc422d2 gbproxy: Use gbprox_delete_tlli if possible
Make use of the delete routine in more places and get test coverage
for it.

Done with Jacob
2014-08-04 12:18:07 +02:00
Holger Hans Peter Freyther
7127b0295e gprs: Create a gprs_utils file and move to be shared code in there
We intend to move some of these routines to libosmocore but to avoid
a feature symbol clash we are prefixing these routines with gprs_.

Done with Jacob
2014-08-04 11:52:52 +02:00
Holger Hans Peter Freyther
1ddd9e518e gbproxy: Use gbproxy_ for all structures
The application is called gbproxy but the structures and functions
were inconsistently named as either gbprox or gbproxy. Rename all
structures to use gbproxy.

Done with Jacob
2014-08-04 11:37:50 +02:00
Holger Hans Peter Freyther
b900459e96 gbproxy: The dump routines are only used by the test, move it there
Done with Jacob
2014-08-04 11:37:47 +02:00
Holger Hans Peter Freyther
16f30b5373 gbproxy: Have a clear namespace for the public functions
Done with Jacob
2014-08-04 11:37:45 +02:00
Holger Hans Peter Freyther
a7027a04dd gbproxy: Remove the global rate counter and place it in the config
Move the global data into the struct and use it. gbprox_reset will
first free data and then re-initialize the structure. This code is
used by the unit test.

Done with Jacob
2014-08-04 11:37:40 +02:00
Holger Hans Peter Freyther
d4d36f22ee gbproxy: Correct the method name. We work on TLLIs
Done with Jacob
2014-08-04 11:37:33 +02:00
Holger Hans Peter Freyther
18739ea32d gbproxy: Move the VTY code into the vty file and create public API
Create public accessors to the core of the peer to allow to
simplify the test and separate concerns.

Done with Jacob.
2014-08-04 11:37:28 +02:00
Andreas Eversberg
035b874fdf MNCC: Add IMSI to CALL CONFIRM message
LCR requires IMSI to correlate calls for MPTY (multi party conference)
and ECT (call transfer).
2014-08-04 08:59:16 +02:00
Andreas Eversberg
723a751e5f dyn PDCH: Cleanup of rsl_chan_activate_lchan() and users
Timing advance is stored inside lchan structure, so it is removed from
arguments. This is useful, if other actions are required prior calling
rsl_chan_activate_lchan. (like deactivating PDCH first)

The "shifted TA value" that is required by BS11 is now calculated inside
rsl_chan_activate_lchan and not by each user.

[Rebased by Holger. So some hunks were skipped as the patch
depended on Jolly's HO code]
2014-08-04 08:59:16 +02:00
Harald Welte
1011d5b505 vty: Fix interactive VTY help for silent-sms transmission 2014-08-02 09:58:52 +02:00
Harald Welte
c7548a116c DB: produce a backtrace in case of a DB error
This helps us to identify where exactly in our code the DB error
originates from.
2014-08-02 09:58:52 +02:00
Holger Hans Peter Freyther
9b62580595 openbsc: Add new fields for the osmo-bts software
For the osmo-bts software we want to be able to slowly change the
output power. The state is kept inside the trx structure.
2014-07-30 18:20:51 +02:00
Max
a5cae441e2 Fix some packaging mistakes detected by lintian.
Signed-off-by: Max Suraev <max.suraev@fairwaves.co>
2014-07-30 08:46:47 +02:00
Holger Hans Peter Freyther
652cdb4699 trau: Cast to remove compiler warning
rtp_proxy.c: In function ‘rtp_decode’:
rtp_proxy.c:199:8: warning: assignment from incompatible pointer type
  frame = msgb_put(new_msg, sizeof(struct gsm_data_frame));
2014-07-24 21:09:31 +02:00
Holger Hans Peter Freyther
922ef5dc86 bts: Remember the last AMR mode that we received
Not every air message contains the AMR mode so we need to remember
it to not confuse receiving equipment like AudioCodes Media Gateways.
2014-07-24 21:05:32 +02:00
Jacob Erlbeck
03551e5f3c gprs: Move LLC IE length fix to BSSGP level
This commit moves the fixing code of the length field of the LLC
information element to the BSSGP patching level since that is not a
part of LLC itself.

Sponsored-by: On-Waves ehf
2014-07-22 17:13:32 +02:00
Jacob Erlbeck
2e2650f8f3 gprs: Parse PTMSI and update TLLI accordingly
This commit adds code to parse the PTMSI in network originated
messages

  - Attach Accept,
  - Routing Area Update Accept, and
  - P-TMSI Reallocation Command (see below)

to keep track of the TLLI identifying the LLC connection.

The P_TMSI Realloc Command specific code is not being tested yet, so
a corresponding notice is logged when such a message will be
received.

NOTE:
  The gbproxy will lose the TLLI when the MS doesn't receive/use
  the message (normally the SGSN remembers the old TLLI for some time
  to avoid this kind of problem). If this happens the MS will
  probably restart the procedure and the network will have to answer
  again eventually using one of the above messages which will
  re-associate the IMSI with the TLLI before the MS can send a
  PDP Context Request message.

Ticket: OW#1192
Sponsored-by: On-Waves ehf
2014-07-22 17:11:57 +02:00
Jacob Erlbeck
35cc03f97d gprs: Use struct to pass context information
Add a struct containing context information from the parts of the
message that have been parsed already. A pointer to this (temporary)
struct is passed to parse/patch functions.

Sponsored-by: On-Waves ehf
2014-07-22 17:10:51 +02:00
Jacob Erlbeck
aefaf92d1a gprs: Use shift functions instead of manual parsing
Currently the patching code directly accesses the single bytes to
parse the LLC/DTAP messages.

This patch uses the shift functions instead to parse tlv and similar
structures.

Sponsored-by: On-Waves ehf
2014-07-22 17:08:28 +02:00
Jacob Erlbeck
b138106423 gprs: Add TLV parse functions
This adds a set of function that parse a single tlv, lv, tv, or v
encoded information element. They are complementary to the *_put
functions defined in libosmocore's tlv.h file. The functions update
the data and data_len fields unless they are a 'match' function and
the tag field doesn't match.

Sponsored-by: On-Waves ehf
2014-07-22 17:08:10 +02:00
Jacob Erlbeck
040b4012a7 gprs: Fix TLLI cache size computation
Currently the enabled_tllis_count field isn't always decremented when
an element is removed from the TLLI cache list.

This patch adds the missing update and also adjusts the counter
accordingly.

Sponsored-by: On-Waves ehf
2014-07-22 17:05:16 +02:00
Jacob Erlbeck
aa3e334608 gprs/test: Rearrange for PTMSI parsing
Add TLLI cache output to gbprox_dump_peers() to include this info
into the test output.

Separate RA Update Req message handling from Attach Request handling.

Note: There is no test case for the P-TMSI Reallocation Command yet.

Sponsored-by: On-Waves ehf
2014-07-22 17:03:23 +02:00
Jacob Erlbeck
25049b93b1 gprs: Add counters related to LLC layer patching
This commit adds the following counters:

  - attach-reqs:   Number of Attach Request messages
  - attach-rejs:   Number of Attach Reject messages
  - tlli-cache:    Size of the TLLI cache

Sponsored-by: On-Waves ehf
2014-07-22 17:02:43 +02:00
Jacob Erlbeck
7dd498de64 gprs/vty: Add commands to manage the TLLI list
These commands manage the TLLI list used to decide whether an APN
shall be patched or not. Note that this list is (currently) only
maintained if IMSI matching is used.

VTY commands (enable node):
  show gbproxy tllis                   show all TLLI entries
  delete-gbproxy-tlli NSEI stale       purge all stale entries
  delete-gbproxy-tlli NSEI imsi IMSI   purge entry with the IMSI given
  delete-gbproxy-tlli NSEI tlli TLLI   purge entry with the TLLI given

Sponsored-by: On-Waves ehf
2014-07-22 17:02:34 +02:00
Jacob Erlbeck
7c101d922e gprs: Track IMSI/TLLI to control APN patching
This patch adds IMSI/TLLI connection tracking and uses it to control
APN patching based on the IMSI. TLLI entries can expire based on age
and/or by limiting the TLLI list size.

VTY config-gbproxy:
  no core-access-point-name                   disable APN patching
  core-access-point-name none                 remove APN if present
  core-access-point-name APN                  replace APN if present
  core-access-point-name none match-imsi RE   remove if IMSI matches
  core-access-point-name APN match-imsi RE    replace if IMSI matches
  tlli-list max-age SECONDS                   expire after SECONDS
  no tlli-list max-age                        don't expire by age
  tlli-list max-length N                      keep N entries only
  no tlli-list max-length                     don't limit list length

RE is an extended regular expression, e.g. ^12345|^23456

Ticket: OW#1192
Sponsored-by: On-Waves ehf
2014-07-22 16:56:33 +02:00
Jacob Erlbeck
006c038212 gprs: Store gbproxy patching state per peer
Currently, all patching state is stored globally in the gbproxy. Thus
the feature cannot be used safely with a concentrating gbproxy (NAT).

This patch moves the state and relevant counters to the gbprox_peer
structure. It adds code to resolve the corresponding peer when
packets are received by looking at BVCI, NSEI, and BSSGP IEs (BVCI,
RAI/LAI/LAC) when the peer is not passed to the
gbprox_patch_bssgp_message() function.

Test cases are also added for the SGSN->BSS case including test cases
with invalid identifiers.

Note that this patch should make it possible to use RAI patching at a
NAT gbproxy as long as the messages are not encrypted.

Ticket: OW#1185
Sponsored-by: On-Waves ehf
2014-07-22 16:53:41 +02:00
Jacob Erlbeck
cf02eb1b20 gprs/test: Add Detach messages to test
This patch adds a Detach Request (MO) / Detach Accept sequence to the
test, followed by another (here invalid) Act PDP Context Req which
should be APN patched.

Sponsored-by: On-Waves ehf
2014-07-22 16:19:57 +02:00
Jacob Erlbeck
1166974bca gprs/test: Added GMM Info and fixed TLLI
Add a DTAP GMM Information message with an IMSI in the BSSGP header
to enable the association between IMSI and TLLI.

The TLLI of the Routing Area Update messages is set to foreign.

Sponsored-by: On-Waves ehf
2014-07-22 16:18:40 +02:00
Jacob Erlbeck
736852825a gprs: Add APN patch support for LLC/GSM messages
Patch the APN in every 'Activate PDP Context Request' message to the
value given by the 'core-access-point-name' command. If the command is
given without an APN, the whole APN IE will be removed. If the
command is being prefixed by a 'no', the APN IE remains unmodified.

The patch mode 'llc-gsm' is added to selectively enable the patching
of LLC session management messages. This is enabled implicitely by
the patch mode 'llc'.

Note that the patch mode should not be set to a value not enabling
the patching of LLC GSM messages ('llc-gsm', 'llc', and 'default' are
sufficient to patch 'Activate PDP Context Request' messages).

Ticket: OW#1192
Sponsored-by: On-Waves ehf
2014-07-22 16:07:01 +02:00
Jacob Erlbeck
91fb680236 gprs: Add MCC/MNC patch support for LLC/GMM messages
This patch extends the BSSGP patch code to also patch LLC information
elements along with MCC/MNC patching support for the following messages:

- Attach Request
- Attach Accept
- Routing Area Update Request
- Routing Area Update Accept
- P-TMSI reallocation command

Note that encrypted packets will not be patched.

Ticket: OW#1185
Sponsored-by: On-Waves ehf
2014-07-22 16:05:59 +02:00
Jacob Erlbeck
67a4445675 gprs: Implement BSSGP MCC/MNC patching
This adds a feature to patch the BSSGP MNC/MCC fields of messages going
to and coming from the SGSN. To enable this feature, the gbproxy's
VTY commands 'core-mobile-country-code' and/or
'core-mobile-network-code' must be used. All packets to the SGSN are
patched to match the configured values. Packets received from the
SGSN are patched to the corresponding values as last seen from the BSS
side.

Note that this will probably not work with a gbproxy used for several
BSS simultaneously.

Note also, that MCC/MNC contained in a LLC IE will not be patched.

Ticket: OW#1185
Sponsored-by: On-Waves ehf
2014-07-22 16:04:54 +02:00
Jacob Erlbeck
fd636aed1e gprs: Use imsi field instead of imei
The wrong field has been use for the field length computation. This
hadn't any impact so far, since
  sizeof(ctx->imei) == sizeof(ctx->imsi)

This patch fixes the computation to use the right field.

Sponsored-by: On-Waves ehf
2014-07-22 15:51:55 +02:00
Jacob Erlbeck
ff0d65aaf6 gprs/test: Make test output more readable
This patch makes a few changes to improve readability:

- change the sendto() hexdump to start with NS instead of BSSGP
- use more specific message descriptions instead of 'UNITDATA'
- add a title line per test

Sponsored-by: On-Waves ehf
2014-07-22 15:48:53 +02:00
Holger Hans Peter Freyther
524edccb61 Merge branch 'zecke/fixes/osmux-nat'
The osmux code doesn't work if the MGCP MGW is behind a NAT (which
is likely to be the case). The usage of endp->ci is troublesome too
not only because of the uint8_t vs. uint32_t mismatch but because
this identity is generated by the MGCP MGW and can clash. This means
that with two clients the wrong call might be connected.

The next bigger thing is that old handles are never cleared. This
code is clearly not ready for deployment.
2014-07-22 15:21:57 +02:00
Holger Hans Peter Freyther
a563641d25 osmux: Drop the message in case we don't know the remote yet.
Avoid creating a bogus state that will never go away.
2014-07-22 15:15:13 +02:00
Holger Hans Peter Freyther
ea7ef38734 osmux: Qualify the handle by IPv4 address _and_ port
For our usecase several different systems might be behind the
same firewall so we need to distinguish the remote by more than
the IPv4 address.
2014-07-22 15:15:13 +02:00
Holger Hans Peter Freyther
48a071e366 osmux: Extract the dummy message, find the endpoint and set rtp port
Set the remote port for the endpoint. Somehow this needs to propagate
all the way to the handle.
2014-07-22 15:15:13 +02:00
Holger Hans Peter Freyther
07ec8eebe0 osmux: Send the CI as part of the dummy to help to identify a client
We need to discover the remote port as we are likely behind a NAT.
Right now the NAT code will just send to port 1984 on the BSC but
this might not arrive at the BSC. Include the CI (in the future we
need to include the endpoint address or send the dummy to the net
port). This is just an interim solution.
2014-07-22 15:15:06 +02:00
Holger Hans Peter Freyther
25a2db018e osmux: Using the "CI" and calling it "CID" is plain wrong
The CI is a MGCP value that is counted from 0 upwards. The code
is comparing a uint8_t with a uint32_t. This will only work for
up to UINT8_MAX calls and then will silently break. The code should
probably work with the endpoint number and not the CI. For now
truncate things and hope things work.
2014-07-22 15:11:07 +02:00
Holger Hans Peter Freyther
cb6ad70994 mgcp: Change API to remove memory management from the name
Jacob pointed out that "free_endp" refers to the memory of
the endpoint being freed. What we want is actually a way to
release an endpoint (and the resource it allocated) or in
the case of the testcase/testapp initialize the data structure
correctly. Introduce two names for that.
2014-07-22 15:00:52 +02:00
Holger Hans Peter Freyther
34a1976d5d Merge commit 'zecke/fixes/mgcp-transcoding'
Include the last bits of fixes for the transcoding code. These fixes
and the appropriate mgcp config are known to work.
2014-07-22 14:48:25 +02:00
Holger Hans Peter Freyther
b936278b2e mgcp: Fix/test the case of a time jump and the resync
In case the sender didn't send a couple of frames we will have
a time gap that is bigger than the accepted delta. Add a new
testcase for this and update the next_time.
2014-07-22 14:48:07 +02:00
Holger Hans Peter Freyther
4c18d79475 mgcp: Add a testcase for 160->80 ptime handling 2014-07-22 14:48:07 +02:00
Holger Hans Peter Freyther
c8b29083d2 mgcp: Initialise next_time in case the initial timestamp is not 0. 2014-07-22 14:48:07 +02:00
Holger Hans Peter Freyther
bd4109babc mgcp: Document transcoding semantic and follow it
Transcoding from GSM to PCMA can lead to the MGCP MGW sending
two PCMA packages with the same sequence number and timestamp.
Once with the encoded audio and once completely empty.

This is because "state->dst_packet_duration" is 0 in most cases
(unless a ptime is forced) and we attempt to encode audio even
if there are not enough samples. The encode_audio return will
return 0 in that case which is not trated as an error by the
mgcp network code.

Handle rc == 0 specially and document the semantic.
2014-07-22 14:42:53 +02:00
Holger Hans Peter Freyther
91eeeae312 mgcp: Fix/test reading/writing the sequence number
The sequence number was read from the wrong place and then
the wrong byte order conversion routine was used so we ended
up wirting 0x00, 0x00 into the patched sequence number. Add
a testcase for that.
2014-07-22 14:31:35 +02:00
Holger Hans Peter Freyther
1fc1ed23b2 mgcp: Patch and Count _after_ the transcoding
When going from a ptime of 10 to 20 a lot of alignment errors
are reported. In fact the alignment check should be done before
and after the transcoding. As this is not possible right now
only do it _after_ the patching.
2014-07-22 14:31:28 +02:00
Holger Hans Peter Freyther
77ceaaf7f5 mgcp: Add a comment about the return of the function 2014-07-22 13:51:39 +02:00
Holger Hans Peter Freyther
7bcbe2a9cc Merge branch 'zecke/fixes/mgcp-transociding-tests'
Various clean-ups and extensions to the tests. Share one test
set-up routine, capture more of the API inside the output files.
2014-07-22 13:13:12 +02:00
Holger Hans Peter Freyther
dd1f81512d mgcp: Make the internal state of the transcoder accessible
For the unit tests we need to look at the internal state.
2014-07-22 13:12:19 +02:00
Holger Hans Peter Freyther
4fb7e64da2 mgcp: Capture the return value of the of the transcode function 2014-07-22 13:12:12 +02:00
Holger Hans Peter Freyther
6041c8db27 mgcp: Do not use errx as finding a test failure is too hard
It took me a long time to figure out that errx just exits and
the test output didn't indicate that the application was exited
early. Use a printf and good old abort in case of a failure.
2014-07-22 13:12:05 +02:00
Holger Hans Peter Freyther
83cbac2ac0 mgcp: Re-factor testcase to separate test and setup
Separate the test from the code necessary for the setup. This is
somehow inspired by the PhExample framework of Pharo.
2014-07-22 13:11:59 +02:00
Holger Hans Peter Freyther
e52ca9aad1 mgcp: Warn when the buffer is being reset due a wrong seq number
When the sample buffer is being dropped write a warning so we can
see how often this event occurs.
2014-07-22 12:41:48 +02:00
Holger Hans Peter Freyther
a7992e0389 mgcp: Mention the packet duration in the error message 2014-07-22 12:41:32 +02:00
Holger Hans Peter Freyther
3d93d35a93 mgcp: Provide more information about configured endpoints 2014-07-22 12:41:25 +02:00
Holger Hans Peter Freyther
c5c239f361 mgcp: Fix memory leak in the transcoding code
The GSM handle was never released. This was found using valgrind
and the leak check.

==14933== 752 bytes in 1 blocks are definitely lost in loss record 15 of 19
==14933==    at 0x4028B4C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==14933==    by 0x4130201: gsm_create (in /usr/lib/i386-linux-gnu/libgsm.so.1.0.12)
==14933==    by 0x80517AE: mgcp_transcoding_setup (mgcp_transcode.c:199)
==14933==    by 0x8049691: given_configured_endpoint.isra.1 (mgcp_transcoding_test.c:198)
==14933==    by 0x8049C11: test_transcode_result (mgcp_transcoding_test.c:328)
==14933==    by 0x8049418: main (mgcp_transcoding_test.c:582)
2014-07-22 12:40:59 +02:00
Holger Hans Peter Freyther
24fc435dad trau_mux.c: Prevent out-of-bounds read in trau_decode_fr()
Haralds patch in 9f109dfb99 only fixed
the trau_encode_fr part but the issue seems to exist in the decode
function as well. Apply the same fix.
2014-07-22 12:23:03 +02:00
Holger Hans Peter Freyther
94f83e1787 smpp: Fix small typo in the comment 2014-07-19 19:02:46 +02:00
Holger Hans Peter Freyther
0d7efef394 gbproxy: Fix the NAME in the start script...
NAME is used by start-stop-daemon to stop the process.
2014-07-17 07:31:42 +02:00
Holger Hans Peter Freyther
d29b8a4745 bsc: Implement a way to relay a message to the remote MSC
This is analogue to the notification that is relayed locally and
now we have a way to relay a message back to the network.
2014-07-09 15:22:21 +02:00
Holger Hans Peter Freyther
c6e9049f9c osmux: Now that we have IPv4/port we might want to consider to expire handles 2014-07-09 13:51:29 +02:00
Holger Hans Peter Freyther
9d43cee88c osmux: Mention where the data was coming from 2014-07-09 13:51:04 +02:00
Holger Hans Peter Freyther
7239f574aa osmux: Be accurate. The label has been already created 2014-07-09 13:50:56 +02:00
Holger Hans Peter Freyther
6b0ba01bf3 osmux: Make sure to always use the right dummy sending method
Make sure to re-use the right method for nat traversal. Found
by Roch while looking at traces.
2014-07-08 13:08:00 +02:00
Holger Hans Peter Freyther
768580b3ec bsc: Use the word core network and not backbone. 2014-07-08 12:48:49 +02:00
Holger Hans Peter Freyther
891b0a857d osmux: Remove extra newline from the osmux log message
<000b> osmux.c:177 Cannot find endpoint with cid=7
!
<000b> osmux.c:253 Cannot find an endpoint for circuit_id=7

The extra newline and '!' do not provide any extra value and
make reading the output more difficult. Just remove it.
2014-07-08 09:08:34 +02:00
Jacob Erlbeck
627e7d9bfe gprs/test: Increase stderr log level
Enable the generation of more log messages.

Sponsored-by: On-Waves ehf
2014-07-07 20:07:34 +02:00
Holger Hans Peter Freyther
2840b3f6c3 gbproxy_test: Provide enough disabled categories to please valgrind
An empty log_info is not enough. We need to make sure that at least
DLGLOBAL is present. Instead of doing that make sure that we have
enough entries.

==26163== Conditional jump or move depends on uninitialised value(s)
==26163==    at 0x403B289: osmo_vlogp (logging.c:290)
==26163==    by 0x403B3DA: logp2 (logging.c:339)
==26163==    by 0x804D027: gbprox_relay2bvci (gb_proxy.c:347)
==26163==    by 0x804D3CF: gbprox_rx_sig_from_sgsn (gb_proxy.c:589)
==26163==    by 0x804DBFC: gbprox_rcvmsg (gb_proxy.c:685)
==26163==    by 0x4052CB0: gprs_ns_process_msg (gprs_ns.c:669)
==26163==    by 0x4052F70: gprs_ns_rcvmsg (gprs_ns.c:1053)
==26163==    by 0x804BB49: gprs_process_message (gbproxy_test.c:488)
==26163==    by 0x804BC4C: send_ns_unitdata (gbproxy_test.c:210)
==26163==    by 0x804BDE8: send_bssgp_reset_ack (gbproxy_test.c:243)
==26163==    by 0x804B54F: main (gbproxy_test.c:863)
==26163==
2014-07-07 19:48:14 +02:00
Holger Hans Peter Freyther
461966b8ef mgcp: Ignore the transcoding test 2014-07-07 19:24:43 +02:00
Holger Hans Peter Freyther
8d998a713e mgcp: Verify that the force-ptime is written back to the file
When the command was added it was not verified that. Add a very
basic MGCP VTY test and test that the string appears in the config.
2014-07-07 19:24:34 +02:00
Holger Hans Peter Freyther
2947411383 mgcp: Fix documentation issue in the force-ptime command
<command id='rtp force-ptime (10|20|40)'>
        <param name='10' doc='(null)' />
        <param name='20' doc='(null)' />
        <param name='40' doc='(null)' />
2014-07-07 19:24:28 +02:00
Holger Hans Peter Freyther
983c99113d rtp: Share the rtp header between the proxy and the mgcp code 2014-07-07 19:24:21 +02:00
Holger Hans Peter Freyther
6019b5a508 nat: Fix the documentation issue with the osmux command
Documentation error (missing docs):
<command id='osmux (on|off)'>
        <param name='off' doc='(null)' />
2014-07-07 19:24:14 +02:00
Holger Hans Peter Freyther
84db98fdbe gbproxy_test: Reset the gbproxy before we reset GPRS NS
The peers are (talloc) children of the GPRS NS. This means the
peers (and the rate counters) are currently being deleted twice.

==23446== Invalid write of size 4
==23446==    at 0x403C243: rate_ctr_group_alloc (linuxlist.h:66)
==23446==    by 0x4050974: gprs_nsvc_create (gprs_ns.c:209)
==23446==    by 0x405320D: gprs_ns_instantiate (gprs_ns.c:1330)
==23446==    by 0x804ABEB: main (gbproxy_test.c:666)
==23446==  Address 0x4300694 is 52 bytes inside a block of size 784 free'd
==23446==    at 0x4029DA8: free (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==23446==    by 0x4041B9D: _talloc_free (talloc.c:609)
==23446==    by 0x4043292: talloc_free (talloc.c:578)
==23446==    by 0x40532D3: gprs_ns_destroy (gprs_ns.c:1363)
==23446==    by 0x804ABD7: main (gbproxy_test.c:660)
2014-07-07 19:22:02 +02:00
Daniel Willmann
46d13268b8 gprs_llc: Prevent llme_alloc/lle_init from reading invalid memory
Make the llc_default_params structure from which data is initialized
large enough. Otherwise address sanitizer complains with out-of-bounds
reads.

Only SAPIs 1, 2, 3, 5, 7, 8, 9, 11 are defined for GPRS but the
struct gprs_llc_llme includes NUM_SAPIS lle's and they are populated
from the llc_default_params structure.
2014-07-07 19:17:54 +02:00
Daniel Willmann
8a485f0bec libbsc, osmo-bsc{, _nat}: Prevent unaligned access when casting TLVP_VAL
foo = *((uintXX_t *) TLVP_VAL(...) can lead to unaligned access. To
prevent that use tlvp_valXX_unal() to get the values.
2014-07-07 19:04:32 +02:00
Holger Hans Peter Freyther
99a20d6be1 gbproxy_test: Simplify the test setup by sharing code 2014-07-07 15:06:21 +02:00
Jacob Erlbeck
7fb42dbd27 gprs/test: Add additional gbproxy tests
This adds a test case with several messages to test BSSGP patching.
New messages:

- BSSGP/DTAP Attach Request
- BSSGP/DTAP Attach Accept
- BSSGP/DTAP Routing Area Update Request
- BSSGP/DTAP Routing Area Update Accept
- BSSGP/DTAP Activate PDP Context Request
- BSSGP SUSPEND
- BSSGP SUSPEND ACK

Sponsored-by: On-Waves ehf
2014-07-07 15:06:12 +02:00
Jacob Erlbeck
2e038f7336 gprs/test: Add connect_sgsn() function
This function abstracts identical code sequences that are used at
multiple places.

Sponsored-by: On-Waves ehf
2014-07-07 15:06:06 +02:00
Jacob Erlbeck
b32d3c041b gprs/test: Remove verbose parameter of gbprox_dump_* functions
This parameter is not used (the methods are always called with an
argument of 1 in the third position). Thus the parameter is removed
completely.

Sponsored-by: On-Waves ehf
2014-07-07 15:05:59 +02:00
Holger Hans Peter Freyther
b115cb6655 db: Use ulonglong to access the database for sqlite3
The type in the schema is integer but we need to use ulonglong to
read it as otherwise the read will fail.

DBI: -7: The requested variable type does not match what libdbi thinks it should be
2014-07-03 14:12:24 +02:00
Harald Welte
9f109dfb99 trau_mux.c: Prevent out-of-bounds read in trau_encode_fr()
found by -fsanitize=address the last iteration of the loop, where i ==
259 and o == 260.  It is read out-of-bounds but the content is never
used.
2014-06-23 09:49:29 +02:00
Holger Hans Peter Freyther
db0caf239e nitb: Only print channel activations once in show statistics
openbsc_vty_print_statistics will already print these counters
for us. No need to print them again.
2014-06-18 08:34:54 +02:00
Holger Hans Peter Freyther
421365eeaa mgcp: Allow to batch more than four messages 2014-06-16 14:12:02 +02:00
Jacob Erlbeck
8f50359ebf gprs: Use area terms LAI/RAI as defined in GSM 03.03
Currently the terms 'Routing area code' (RAC) and 'Location area
code' (LAC) are used in several places where 'Routing area
identification' (RAI) or 'Location area identification' (LAI) are
meant in fact.

This patch replaces RAC/LAC by RAI/LAI and 'code' by 'identification'
at these places.

Note that RAI := MCC MNC LAC RAC, and LAI := MCC MNC LAC (see GSM
03.03, sections 4.1 and 4.2).

Sponsored-by: On-Waves ehf
2014-06-15 19:23:38 +02:00
Jacob Erlbeck
cb04ca2fc3 mgcp: Fix SDP formatting of fmtp_extra (Coverity)
Currently when ftmp_extra is set, a doubled a=rtpmap line is emitted
instead of the fmtp_extra info.

This patch fixes replaces the formerly copied and pasted but not
modified snprintf parameters by the correct ones.

Fixes: Coverity CID 1220873
Sponsored-by: On-Waves ehf
2014-06-15 19:15:32 +02:00
Jacob Erlbeck
bebf92d7f0 mgcp/test: Add test case using the fmtp_extra info
Add tests setting the fmtp_extra field to check the response
generation. This triggers a bug found by Coverity.

Addresses: Coverity CID 1220873
Sponsored-by: On-Waves ehf
2014-06-15 19:15:09 +02:00
Holger Hans Peter Freyther
4e5f93ccdc proxy: Annotate the switch/case/fall through
Use the same comment as some lines earlier in that file.

Fixes: Coverity CID 1040737
2014-06-12 11:32:25 +02:00
Holger Hans Peter Freyther
b07df2bfd4 bsc: Do not use strdup on argv parameter
Fixes: Coverity CID 1206578
2014-06-12 11:19:38 +02:00
Jacob Erlbeck
efd266ae12 Merge remote-tracking branch 'origin/jerlbeck/features/mgcp-transcoding' 2014-06-05 14:45:07 +02:00
Jacob Erlbeck
452c183c5e mgcp: Set net_end audio params in recvonly mode
Currently, if there is no SDP data in the MGCP message received from
the net, the fields containing audio encoding information are not set
in net_end. So in recvonly mode transcoding would not be set up
correctly.

This patch changes the implementation of the code handling CRCX and
MDCX to use the codec signalled in the MGCP local connection options
(field 'a:') if there isn't any SDP data. This is only halfway
negotiation, because the codec is used blindly and not matched
against the supported ones.

Sponsored-by: On-Waves ehf
2014-06-05 14:09:52 +02:00
Jacob Erlbeck
909fac6689 mgcp: Move transcoding to libmgcp
This patch moves the files relevant to transcoding from
src/osmo-bsc_mgcp to src/libmgcp and src/include/openbsc. Makefiles
and include directives are being updated accordingly.

Sponsored-by: On-Waves ehf
2014-06-05 14:08:53 +02:00
Jacob Erlbeck
84a45cbf83 mgcp/test: Add test cases for transcoding and repacking
This patch adds test cases for transcoding and repacking.

Sponsored-by: On-Waves ehf
2014-06-05 14:08:53 +02:00
Jacob Erlbeck
07886d9b0a mgcp: Extend the CLI transcoding tool by ptime conversion
This modification allows it to set the number of samples per packet
that is written to the output.

Sponsored-by: On-Waves ehf
2014-06-05 14:08:53 +02:00
Jacob Erlbeck
42a833e89f mgcp: Add packet size (ptime) conversion
The current transcoder implemenation always does a 1:1 recoding
concerning the duration of a packet. So RTP timestamps and sequence
numbers are not modified.

This is not sufficient in some cases, e.g. when the BTS does only
allow for a single fixed ptime.

This patch decouples encoding from decoding and moves the decoded
samples to the state structure so that samples can be combined or
drain according to the packaging of incoming and outgoing packets.

This patch incorporates parts of Holger's experimental fixes in
0e669e05^..9eba68f9.

Ticket: OW#1111
Sponsored-by: On-Waves ehf
2014-06-05 14:08:45 +02:00
Jacob Erlbeck
136a319e91 mgcp: Add CLI tool to test audio conversion
This tool uses mgcp_transcode.c to convert audio data from stdin to
stdout.

Sponsored-by: On-Waves ehf
2014-06-05 14:00:47 +02:00
Jacob Erlbeck
239a853f40 mgcp: Add RTP audio transcoding
This patch implements audio transcoding between the formats GSM,
PCMA, L16, and optionally G.729.

The feature needs to be enabled by using the autoconf option
'--enable-mgcp-transcoding'. In this case mgcp_transcode.c will
be compiled and linked to osmo-bsc_mgcp, and the transcoding
functions provided will be registered as processing callbacks.

If G.729 support is required, libcg729 needs to be installed and
'--with-g729' must be passed to ./configure.

Ticket: OW#1111
Sponsored-by: On-Waves ehf
2014-06-05 14:00:47 +02:00
Jacob Erlbeck
997e1e8e9d mgcp: Only include SDP lines with valid content
Don't show media related lines if the payload type has not been set.
Don't show a 'a=rtpmap' line if the audio_name has not been set.

This patch unifies the SDP generation of create_response_with_sdp()
and send_msg().

Sponsored-by: On-Waves ehf
2014-06-05 14:00:46 +02:00
Jacob Erlbeck
168ca00b02 mgcp: Add a function to get media info for MGCP responses
This patch adds the get_net_downlink_format_cb() callback to provide
payload_type, subtype_name, and fmtp_extra suitable for use in a MGCP
response sent to the network. Per default, the BTS side values are
returned since these must be honoured by the net peer when sending
audio to the media gateway (unless transcoding is done).

Sponsored-by: On-Waves ehf
2014-06-05 14:00:46 +02:00
Jacob Erlbeck
845d0054b4 mgcp: Add audio info fields to struct mgcp_rtp_end
This patch adds the fields channels, subtype_name, and audio_name to
the struct. The field audio_name contains the full string that has
been used for the last part of a SDP a=rtpmap line. The others contain
decoded parts of that string. If no a=rtpmap line has been given
(e.g. because dynamic payload types are not used), values are
assigned when the payload type matches one of the predefined ones
(GSM, G729, PCMA).

The patch also moves the audio_name parsing code to a dedicated
set_audio_info() function.

Sponsored-by: On-Waves ehf
2014-06-05 14:00:41 +02:00
Jacob Erlbeck
a0d64ce063 mgcp: Add callbacks for payload processing
This patch adds the callbacks rtp_processing_cb and
setup_rtp_processing_cb to mgcp_config to support arbitrary RTP
payload processing.

Sponsored-by: On-Waves ehf
2014-06-05 12:19:46 +02:00
Jacob Erlbeck
b492d39177 gprs: Separate LLC parsing from LLC state handling
Currently LLC parsing is part of gprs_llc.c which needs large parts
of the SGSN code parsing to fulfill its link dependencies.

This patch moves the functions that just do plain parsing, dumping,
and FCS computation to a different file to avoid these dependencies
if LLC stateful processing is not needed. It also exposes
struct gprs_llc_hdr_parsed and enum gprs_llc_cmd publically.

Sponsored-by: On-Waves ehf
2014-06-04 16:29:30 +02:00
Jacob Erlbeck
def0391ec5 gprs/test: Use valid MCC/MNC for BVC RESET
The code currently uses an encoded sequence of (hex) 10 20 30 40 50
60 as RAI, for which no bijective mapping to the set of
representations MCC-MNC-LAC-RAC exists.

This patch changes the hard-coded RAI to 11 22 33 40 50 60 which maps
to 112-332-16464-96 (and vice-versa).

Sponsored-by: On-Waves ehf
2014-06-04 16:20:46 +02:00
Holger Hans Peter Freyther
cc84c9535c osmux: Fix the VTY online help in the osmux command
This should fix most of:

Documentation error (missing docs):
<command id='osmux (on|off)'>
        <param name='off' doc='(null)' />

Documentation error (missing docs):
<command id='osmux batch-factor &lt;1-4&gt;'>
        <param name='&lt;1-4&gt;' doc='(null)' />

Documentation error (missing docs):
<command id='osmux (on|off)'>
        <param name='off' doc='(null)' />

Documentation error (missing docs):
<command id='osmux (on|off)'>
        <param name='off' doc='(null)' />

Documentation error (missing docs):
<command id='osmux batch-factor &lt;1-4&gt;'>
        <param name='&lt;1-4&gt;' doc='(null)' />
2014-06-03 13:36:42 +02:00
Holger Hans Peter Freyther
889710c890 Merge branch 'hfreyther/fixes/channel-release-handling'
The patches were posted to the ML but didn't receive review
there. At the time I merge the change I did a Location Updating
Request and the channel was released in a successful way.
2014-06-03 13:25:02 +02:00
Holger Hans Peter Freyther
0e4e73a891 rsl: Check if the channel is active and then start the channel release
In case we receive ERROR INDICATION and CONNECTION FAILURE we only
want to RF Channel Release the lchan once. This code is more simple
and should work as reliable as the previous commit.
2014-06-03 12:51:16 +02:00
Holger Hans Peter Freyther
1e93b79cce rsl: Avoid double channel release procedure in error conditions
When we receive an ERROR INDICATION and CONNECTION FAILURE we
might call rsl_rf_chan_release multiple times. The channel release
handling is still a bit messy and there too many paths that lead
to the call.

1.) In case we receive an ERROR INDICATION for SAPI=3. A RLL
error signal will be emitted that leads to the release of the
channel through the SMS code in case of the NITB.  The call to
rsl_rf_chan_release might be a double release.

2.) In case a CONNECTION FAILURE is received when the release
process has already been started we would unconditionally
call rsl_rf_chan_release as well.

Because the lchan state is changed by the callers of the
rsl_rf_chan_release we can not move the state checking into this
code but need to do it in the caller. The issue was seen in a trace
from Rhizomatica and I created the DoubleRelease.st to re-produce
the issue and verified that we have no duplicate RF Channel Releses.

The other option would be to introduce a new state to track
the release process and see if we have already released SAPIs
deactivated the SACCH or such. We can not simply look at these
as for a channel that fails to activate they will be null already.
2014-06-03 12:51:16 +02:00
Holger Hans Peter Freyther
f0405068d8 lchan: Speculative "fix" for error and late reply
Looking at the code it seemed possible that a channel would
transition from BROKEN to NONE. Or worse from NONE to BROKEN.
Start the timer _after_ the channel has been released.
2014-06-03 12:51:16 +02:00
Holger Hans Peter Freyther
5308fffc53 bsc: Introduce a local notification scheme for the CTRL interface
Make it possible to inform local CTRL connections about some state.
The TRAP will be only sent to local connections. The notification
text may not contain spaces.
2014-05-31 08:42:29 +02:00
Holger Hans Peter Freyther
4f0381b1c3 mgcp: Address scanf issue already found by cppcheck and now ASAN
Use the right size for scanf.

=================================================================
==6106== ERROR: AddressSanitizer: unknown-crash on address 0xbffff4b0 at pc 0xb69d87fd bp 0xbffff248 sp 0xbffff21c
WRITE of size 65 at 0xbffff4b0 thread T0
    #0 0xb69d87fc (/usr/lib/i386-linux-gnu/libasan.so.0.0.0+0xa7fc)
    #1 0xb69d9239 (/usr/lib/i386-linux-gnu/libasan.so.0.0.0+0xb239)
    #2 0xb69d92d6 (/usr/lib/i386-linux-gnu/libasan.so.0.0.0+0xb2d6)
    #3 0x804f151 (/home/ich/source/gsm/openbsc/openbsc/tests/mgcp/mgcp_test+0x804f151)
    #4 0x80531e8 (/home/ich/source/gsm/openbsc/openbsc/tests/mgcp/mgcp_test+0x80531e8)
    #5 0x8051e6f (/home/ich/source/gsm/openbsc/openbsc/tests/mgcp/mgcp_test+0x8051e6f)
    #6 0x8049b0a (/home/ich/source/gsm/openbsc/openbsc/tests/mgcp/mgcp_test+0x8049b0a)
    #7 0x804bd9e (/home/ich/source/gsm/openbsc/openbsc/tests/mgcp/mgcp_test+0x804bd9e)
    #8 0xb6778a62 (/lib/i386-linux-gnu/i686/cmov/libc-2.18.so+0x19a62)
    #9 0x8049330 (/home/ich/source/gsm/openbsc/openbsc/tests/mgcp/mgcp_test+0x8049330)
Address 0xbffff4b0 is located at offset 416 in frame <parse_sdp_data> of T0's stack:
  This frame has 8 object(s):
    [32, 36) 'audio_payload'
    [96, 100) 'payload'
    [160, 164) 'channels'
    [224, 228) 'ptime'
    [288, 292) 'port'
    [352, 368) 'ipv4'
    [416, 480) 'audio_name'
    [512, 576) 'audio_codec'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are*
2014-05-28 17:00:56 +02:00
Holger Hans Peter Freyther
b691bf1d54 channel_test: Return a positive number to claim it was paged
This addresses an ASAN issue where the request was already deleted
by our callback function.

(gdb) where
 #0  0xb69e7810 in __asan_report_error () from /usr/lib/i386-linux-gnu/libasan.so.0
 #1  0xb69e0aff in __asan_report_store4 () from /usr/lib/i386-linux-gnu/libasan.so.0
 #2  0x0804ea64 in subscr_send_paging_request (subscr=subscr@entry=0xb5103cb0)
     at gsm_subscriber.c:212
 #3  0x0804edac in subscr_get_channel (subscr=subscr@entry=0xb5103cb0, type=type@entry=2,
     cbfn=cbfn@entry=0x804969d <subscr_cb>, param=param@entry=0x2342) at gsm_subscriber.c:246
 #4  0x080498f7 in main (argc=1, argv=0xbffff804) at channel_test.c:77

Breakpoint 3, subscr_paging_dispatch (hooknum=hooknum@entry=101, event=event@entry=200,
    msg=msg@entry=0x1323, data=<optimized out>, data@entry=0x8063900 <s_conn>,
    param=<optimized out>, param@entry=0xb5103cb0) at gsm_subscriber.c:126
126		llist_del(&request->entry);

 (gdb) b llist_del
 (gdb) bt
 #0  subscr_paging_dispatch (hooknum=hooknum@entry=101, event=event@entry=200,
     msg=msg@entry=0x1323, data=<optimized out>, data@entry=0x8063900 <s_conn>,
     param=<optimized out>, param@entry=0xb5103cb0) at gsm_subscriber.c:126
 #1  0x0804e8a9 in subscr_paging_cb (hooknum=101, event=200, msg=0x1323,
     data=0x8063900 <s_conn>, param=0xb5103cb0) at gsm_subscriber.c:187
 #2  0x080497e9 in paging_request (bts=0xb5b03e70, subscriber=subscriber@entry=0xb5103cb0,
     type=2, cbfn=cbfn@entry=0x804e881 <subscr_paging_cb>, data=data@entry=0xb5103cb0)
     at channel_test.c:51
 #3  0x0804ea39 in subscr_send_paging_request (subscr=subscr@entry=0xb5103cb0)
     at gsm_subscriber.c:207
 #4  0x0804edac in subscr_get_channel (subscr=subscr@entry=0xb5103cb0, type=type@entry=2,
     cbfn=cbfn@entry=0x804969d <subscr_cb>, param=param@entry=0x2342) at gsm_subscriber.c:246
 #5  0x080498f7 in main (argc=1, argv=0xbffff804) at channel_test.c:77
(gdb) q
2014-05-28 17:00:48 +02:00
Holger Hans Peter Freyther
f6b61e6154 mgcp: Use #pragma once instead of a possible clashing #ifdef
The filename is mgcp_internal.h but the define refers to MGCP_DATA.
Avoid having a potential clash by using the #pragma once option.
2014-05-26 08:17:45 +02:00
Holger Hans Peter Freyther
ee41ecff98 rsl: Remove obsolete FIXME comment.
The lchan state is set to none either on RF Channel Release ACK
or in case of an error after the error timer has expired.
2014-05-26 08:17:35 +02:00
Holger Hans Peter Freyther
4f200491ff osmux: Fix potential memory leak in the msgb handling 2014-05-22 16:46:11 +02:00
Holger Hans Peter Freyther
1cc5ff8e19 mgcp: Add proper length checking for line handling
In ae1997248c the handwritten tokenizer
was replaced with strtok_r. As part of this change the structural
checking of MGCP parameters was stopped. This means that a code like
"line + 3" might access beyond the first NUL and be possibly behind
the msgb. Manually add size checking again. Manually jumping to the
error label is not possible anymore as it has been removed. The result
is that invalid lines will be skipped. This is matching the general
approach by the IETF RFCs to be permissive in data being received.
2014-05-22 16:46:11 +02:00
Holger Hans Peter Freyther
f259bd8359 mgcp: Remove excessive logging for each frame 2014-05-22 14:42:09 +02:00
Pablo Neira Ayuso
cab6e7528c mgcp: add voice muxer support
This patch adds the voice muxer. You can use this to batch RTP
traffic to reduce bandwidth comsuption. Basically, osmux transforms
RTP flows to a compact batch format, that is later on decompacted
to its original form. Port UDP/1984 is used for the muxer traffic
between osmo-bsc_nat and osmo-bsc_mgcp (in the BSC side). This
feature depends on libosmo-netif, which contains the osmux core
support.

Osmux is requested on-demand via the MGCP CRCX/MDCX messages (using
the vendor-specific extension X-Osmux: on) coming from the BSC-NAT,
so you can selectively enable osmux per BSC from one the bsc-nat.cfg
file, so we have a centralized point to enable/disable osmux.

First thing you need to do is to accept requests to use Osmux,
this can be done from VTY interface of osmo-bsc_nat and
osmo-bsc_mgcp by adding the following line:

mgcp
  ...
  osmux on
  osmux batch-factor 4

This just initializes the osmux engine. You still have to specify
what BSC uses osmux from osmo-bsc_nat configuration file:

...
 bsc 1
  osmux on
 bsc 2
  ...
 bsc 3
  osmux on

In this case, bsc 1 and 3 should use osmux if possible, bsc 2 does
not have osmux enabled.

Thus, you can selectively enable osmux depending on the BSC, and
we have a centralized point for configuration from the bsc-nat to
enable osmux on demand, as suggested by Holger.

At this moment, this patch contains heavy debug logging for each
RTP packet that can be removed later to save cycles.

The RTP ssrc/seqnum/timestamp is randomly allocated for each MDCX that
is received to configure an endpoint.
2014-05-22 14:39:16 +02:00
Daniel Willmann
038f97a69f bsc_hack: Don't strdup the string arguments
Fixes CIDs #1206577, #1206578
2014-05-22 14:34:24 +02:00
Daniel Willmann
45fcb85236 rtp_proxy: Prevent out-of-bounds read in rtcp_sdes_cname_mangle
In rtcp_sdes_cname_mangle when skipping over additional zeroes at the
end of a chunk we should not read past the actual message (rtcp_end).

Fixes CID #1206579
2014-05-22 14:31:09 +02:00
Harald Welte
a4c63b0cdb chan_alloc: Fall-back to TCH/H, if we cannot find a TCH/F
I'm not entirely sure if this is the best approach.  However,
there are phones that send a RACH request for TCH/F on MO calls, even
though they actually do support TCH/H channels.
2014-05-19 08:31:39 +02:00
Harald Welte
ec75798644 rtp_proxy.c: Correctly set msg_type to GSM_TCH_FRAME_AMR on AMR
When forwarding AMR from RTP towards the MNCC interface, we need to set
the apropriate msg_type.  Before this patch it was unitialized,
resulting in improper/unknown msg_types of messages on the MNCC
interface.
2014-05-18 22:23:15 +02:00
Harald Welte
a87f8f9891 rtp_proxy: Simplify AMR handling
AMR frames on the MNCC interface are slightly different as they
include a single-byte payload_length indicator prior to the actual
payload.  Commit 3f201ac89952b68d05c0bb6cb41932b9cd898b19 introduced
more special-case handling than required, so I'm trying to simplify
things again.

We now also use msgb_put() more consistently, i.e. always put
before actually using the data, and use the return value of msgb_put()
rather than first making assumptions about the pointer, writing to it
and then calling msgb_put().
2014-05-18 22:23:15 +02:00
Andreas Eversberg
d8967f76a5 Add support for AMR frames to MNCC/RTP interface
AMR rate is currently fixed to 5.9k.
2014-05-18 22:23:15 +02:00
Andreas Eversberg
72c0dbd753 bsc_api/NITB: If TCH/H channel is used, indicate it to bsc_api
If we don't do this, OsmoNITB will send an assignment command from
a TCH/H to another TCH/H without any need.
2014-05-18 22:23:15 +02:00
Andreas Eversberg
a4d0e3cc6b Add check to tch_map(), if RTP sockets exist 2014-05-18 22:23:15 +02:00
Holger Hans Peter Freyther
20f6e946e1 ctrl: Use CTRL_CMD_DEFINE_STRUCT in CTRL_CMD_DEFINE_RANGE
Jacob pointed out that I didn't convert CTRL_CMD_DEFINE_RANGE.
This patch is doing it now.
2014-05-15 17:28:03 +02:00
Holger Hans Peter Freyther
b66f158b05 ctrl: Reduce code duplication and add a define to create the struct
This has been pointed out by Jacob and removes two more duplicates
of the struct. For the unused CTRL_CMD_DEFINE_STRING macro there
will be no verify command.
2014-05-15 15:50:55 +02:00
Holger Hans Peter Freyther
6e36255221 ctrl: Remove the param parameter as it was never used/implemented 2014-05-15 15:50:55 +02:00
Holger Hans Peter Freyther
1159005ae0 ctrl: Introduce a macro for read-only attributes and use it
Certain attributes are read-only. Add a macro to make it more
easy to define those.
2014-05-15 15:30:52 +02:00
Jacob Erlbeck
268b2e6544 ctrl: Fix handling of missing replies
Currently, if a CTRL method does not set the reply, an error is
logged ("cmd->reply has not been set"). It even complains when the
function implementing the command returns CTRL_CMD_HANDLED, where
a reply text is not needed.

This patch changes the logging level from ERROR to NOTICE. The logging
is now only done, when the retry has not been set and the
implementation returns either CTRL_CMD_ERROR or CTRL_CMD_REPLY. So
in these cases the reply field must be set.

This fixes the generation of log messages when doing NAT ctrl command
forwarding.

Ticket: OW#1177
Sponsored-by: On-Waves ehf
2014-05-15 14:22:56 +02:00
Holger Hans Peter Freyther
47d8f02c06 misc: Use the right mailinglist address for OpenBSC 2014-05-15 12:26:54 +02:00
Jacob Erlbeck
543e11496e contrib/rtp: Use payload data files directly by gen_rtp_header
This adds a --frame-size option to read payload binary files with a
fixed frame size directly. The file must not contain RTP headers.
In addition '--rate' and '--duration' can be used to configure the
timing.

Sponsored-by: On-Waves ehf
2014-05-09 16:38:28 +02:00
Nikola Kolev
10bad1031e ipa: Fix the compilation of ipaccess-find on FreeBSD
FreeBSD does not offer the SO_BINDTODEVICE option. The closest
thing is the IP_RECVIF option and this is used here now.
2014-05-09 04:40:23 +02:00
Nikola Kolev
b9f45987b3 bsc: Fix compilation on FreeBSD
FreeBSD uses POSIX netinet/in.h for representing socket addresses
data types.

[Holger removed the #ifdef and changed the order of includes to
have specific ones first and system includes later]
2014-05-09 04:38:58 +02:00
Holger Hans Peter Freyther
abddd6aa44 nat/bsc: Check proto before calling ipaccess_rcvmsg_base
The code in the BSC/NAT called ipaccess_rcvmsg_base without
checking if the protocol is IPA. This lead the BSC to respond
to SCCP messages with an "ID ACK". From a quick look neither
the code of ipaccess_rcvmsg_base in OpenBSC nor the copy of
libosmo-abis ever checked the protocol header. So this code
has been wrong since initially being created in 2010.
2014-05-06 06:50:39 +02:00
Holger Hans Peter Freyther
3c9068f185 db: Fix next fall-out with make distcheck 2014-05-01 07:53:42 +02:00
Holger Hans Peter Freyther
f242e7afef db: Fix fall-out with the subscriber removal in the subscriber deletion code
The sender_id is gone so the code that attempted to delete SMS
didn't work anymore. Delete the SMS based on src_addr or the
dest_addr.

Fixes:
======================================================================
ERROR: testSubscriberAddRemove (__main__.TestCtrlNITB)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "tests/ctrl_test_runner.py", line 379, in testSubscriberAddRemove
    r = self.do_set('subscriber-delete-v1', '2620345')
  File "tests/ctrl_test_runner.py", line 114, in do_set
    return self.recv_msgs()[id]
KeyError: 1002
2014-04-30 20:51:28 +02:00
Holger Hans Peter Freyther
edfdc9829c Merge branch 'zecke/features/sms-db-changes'
This branch allows a SMPP user to fully specify the sender id. It
requires a change in schema, database migration code and exposed
some issues in the libdbi and the sqlite3 driver.
2014-04-30 15:32:41 +02:00
Holger Hans Peter Freyther
6114401b9b db: Add testcase for the db migration. 2014-04-30 15:31:57 +02:00
Holger Hans Peter Freyther
e7cc9aa447 sms: Add code to migrate the database to the new schema
This is mostly based on Alexander's migration code. The code
adds transaction handling and some sanity checks and cleanups
to the code. We made the decision to fork the sms_from_result
method and freeze it to that version. This way sms_from_result
can move forward without having to deal with legacy.
2014-04-30 15:31:57 +02:00
Alexander Chemeris
ca7ed2d2df sms: Do not store received id in the SMS database.
That was a bad idea from the very beginning. A visible result of this is a wrong
SMS routing when you change subscriber extensions, while having queued SMS. It's
also a very wrong thing from the code layering perspective.

I think the next logical step should be to remove "receiver" pointer from
the gsm_sms structure into a structure, special for the internal SMS queue.
2014-04-30 15:31:57 +02:00
Holger Hans Peter Freyther
73bc51deea db: Add testcase for storing/loading/comparing a sms
Use the already created subscriber, create a sms and read it
back from the subscriber.
2014-04-30 15:31:57 +02:00
Holger Hans Peter Freyther
ca3c256579 sms: Kill the sms->sender and use addr/ton/npi throughout the code
This is an incompatible database schema change. Store the type of
the address in the database for both the sender and the receiver.

Currently it is possible to use SMPP to store a SMS and the NPI
and TON will be lost on the delivery of the SMS. The schema is
changed to make the delivery always use the right NPI/TON. This
patch is not ready for the master branch as there is no upgrade
path for the HLR yet.
2014-04-30 15:31:57 +02:00
Álvaro Neira Ayuso
1b148ec100 openbsc/gsm_data_shared.h: Added the attribute reduce_power in TRX
Signed-off-by: Alvaro Neira Ayuso <anayuso@sysmocom.de>
2014-04-29 11:59:40 +02:00
Holger Hans Peter Freyther
e9faa6f3a4 ctrl: Extend the testcase for using '09' as numbers on the interface
Verify that '0X' numbers are parsed correctly from the wire
interface.
2014-04-24 10:30:05 +02:00
Holger Hans Peter Freyther
86decfb53c gbproxy: Fix the start script for gbproxy
* Use the right name
* Refer to the right config file
2014-04-24 10:09:08 +02:00
Holger Hans Peter Freyther
5dd295ff44 bsc: Timers are in seconds, clarify that in the online help 2014-04-11 19:30:53 +02:00
Holger Hans Peter Freyther
444d7d8e65 ipa: Fix compiler warnings about aliasing
Use memcpy to copy from the OML message into the stack and then
convert the network byte order.

network_listen.c: In function ‘test_rep’:
network_listen.c:145:2: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
  test_rep_len = ntohs(*(uint16_t *) &foh->data[3]);
  ^
network_listen.c:153:3: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
   ferr_list_len = ntohs(*(uint16_t *) &foh->data[7]);
   ^
network_listen.c:164:3: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
   ferr_list_len = ntohs(*(uint16_t *) &foh->data[7]);
   ^
network_listen.c:130:11: warning: variable ‘test_rep_len’ set but not used [-Wunused-but-set-variable]
  uint16_t test_rep_len, ferr_list_len;
2014-04-04 13:01:28 +02:00
Holger Hans Peter Freyther
686191a1c9 oml: Fix compiler warning about aliasing
Make the fill_fom_hdr return the header and use it throughout.

  CC       abis_nm.o
In file included from ../../include/openbsc/debug.h:8:0,
                 from abis_nm.c:38:
abis_nm.c: In function ‘abis_nm_opstart’:
abis_nm.c:1763:34: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
  abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
                                  ^
/home/ich/install/openbsc/include/osmocom/core/logging.h:23:74: note: in definition of macro ‘DEBUGP’
 #define DEBUGP(ss, fmt, args...) logp(ss, __FILE__, __LINE__, 0, fmt, ## args)
                                                                          ^
abis_nm.c:1763:2: note: in expansion of macro ‘abis_nm_debugp_foh’
  abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
  ^
abis_nm.c:1763:34: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
  abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
                                  ^
/home/ich/install/openbsc/include/osmocom/core/logging.h:23:74: note: in definition of macro ‘DEBUGP’
 #define DEBUGP(ss, fmt, args...) logp(ss, __FILE__, __LINE__, 0, fmt, ## args)
                                                                          ^
abis_nm.c:1763:2: note: in expansion of macro ‘abis_nm_debugp_foh’
  abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
  ^
abis_nm.c:1763:34: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
  abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
                                  ^
/home/ich/install/openbsc/include/osmocom/core/logging.h:23:74: note: in definition of macro ‘DEBUGP’
 #define DEBUGP(ss, fmt, args...) logp(ss, __FILE__, __LINE__, 0, fmt, ## args)
                                                                          ^
abis_nm.c:1763:2: note: in expansion of macro ‘abis_nm_debugp_foh’
  abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
  ^
abis_nm.c:1763:34: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
  abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
                                  ^
/home/ich/install/openbsc/include/osmocom/core/logging.h:23:74: note: in definition of macro ‘DEBUGP’
 #define DEBUGP(ss, fmt, args...) logp(ss, __FILE__, __LINE__, 0, fmt, ## args)
                                                                          ^
abis_nm.c:1763:2: note: in expansion of macro ‘abis_nm_debugp_foh’
  abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
  ^
abis_nm.c:1763:34: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
  abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
                                  ^
/home/ich/install/openbsc/include/osmocom/core/logging.h:23:74: note: in definition of macro ‘DEBUGP’
 #define DEBUGP(ss, fmt, args...) logp(ss, __FILE__, __LINE__, 0, fmt, ## args)
                                                                          ^
abis_nm.c:1763:2: note: in expansion of macro ‘abis_nm_debugp_foh’
  abis_nm_debugp_foh(DNM, (struct abis_om_fom_hdr *) oh->data);
2014-04-04 12:56:34 +02:00
Holger Hans Peter Freyther
90e9a445c8 gprs: Fix compiler warnings in sgsn_main.c
sgsn_main.c: In function ‘main’:
sgsn_main.c:345:2: warning: implicit declaration of function ‘gprs_sndcp_vty_init’ [-Wimplicit-function-declaration]
  gprs_sndcp_vty_init();
  ^
sgsn_main.c:354:2: warning: implicit declaration of function ‘sgsn_gtp_init’ [-Wimplicit-function-declaration]
  rc = sgsn_gtp_init(&sgsn_inst);
  ^
2014-04-04 12:51:28 +02:00
Holger Hans Peter Freyther
5a1b329a9e gprs: Fix compiler warnings ini gprs_sndcp_vty.c
CC       gprs_sndcp_vty.o
gprs_sndcp_vty.c: In function ‘vty_dump_sne’:
gprs_sndcp_vty.c:46:15: warning: unused variable ‘i’ [-Wunused-variable]
  unsigned int i;
2014-04-04 12:49:38 +02:00
Holger Hans Peter Freyther
65762e0455 gprs: Fix compiler warnings in sgsn_libgtp.c
CC       sgsn_libgtp.o
sgsn_libgtp.c: In function ‘create_pdp_conf’:
sgsn_libgtp.c:262:6: warning: variable ‘rc’ set but not used [-Wunused-but-set-variable]
  int rc;
      ^
sgsn_libgtp.c: In function ‘cb_data_ind’:
sgsn_libgtp.c:432:6: warning: variable ‘rc’ set but not used [-Wunused-but-set-variable]
  int rc;
2014-04-04 12:49:00 +02:00
Holger Hans Peter Freyther
744568b569 gprs: Fix compiler warnings in the gprs_llc.c code
CC       gprs_llc.o
gprs_llc.c: In function ‘t200_expired’:
gprs_llc.c:322:2: warning: enumeration value ‘GPRS_LLES_UNASSIGNED’ not handled in switch [-Wswitch]
  switch (lle->state) {
  ^
gprs_llc.c:322:2: warning: enumeration value ‘GPRS_LLES_ASSIGNED_ADM’ not handled in switch [-Wswitch]
gprs_llc.c:322:2: warning: enumeration value ‘GPRS_LLES_REMOTE_EST’ not handled in switch [-Wswitch]
gprs_llc.c:322:2: warning: enumeration value ‘GPRS_LLES_ABM’ not handled in switch [-Wswitch]
gprs_llc.c:322:2: warning: enumeration value ‘GPRS_LLES_TIMER_REC’ not handled in switch [-Wswitch]
gprs_llc.c: In function ‘gprs_llc_hdr_rx’:
gprs_llc.c:564:2: warning: enumeration value ‘GPRS_LLC_NULL’ not handled in switch [-Wswitch]
  switch (gph->cmd) {
  ^
gprs_llc.c:564:2: warning: enumeration value ‘GPRS_LLC_RR’ not handled in switch [-Wswitch]
gprs_llc.c:564:2: warning: enumeration value ‘GPRS_LLC_ACK’ not handled in switch [-Wswitch]
gprs_llc.c:564:2: warning: enumeration value ‘GPRS_LLC_RNR’ not handled in switch [-Wswitch]
gprs_llc.c:564:2: warning: enumeration value ‘GPRS_LLC_SACK’ not handled in switch [-Wswitch]
gprs_llc.c: In function ‘gprs_llc_rcvmsg’:
gprs_llc.c:791:23: warning: unused variable ‘udh’ [-Wunused-variable]
  struct bssgp_ud_hdr *udh = (struct bssgp_ud_hdr *) msgb_bssgph(msg);
                       ^
gprs_llc.c: At top level:
gprs_llc.c:311:13: warning: ‘t200_expired’ defined but not used [-Wunused-function]
 static void t200_expired(void *data)
             ^
gprs_llc.c:337:13: warning: ‘t201_expired’ defined but not used [-Wunused-function]
 static void t201_expired(void *data)
2014-04-04 12:47:32 +02:00
Holger Hans Peter Freyther
cfee952e23 gprs: Fix compiler warnings in gprs_sndcp.c
CC       gprs_sndcp.o
gprs_sndcp.c: In function ‘defrag_input’:
gprs_sndcp.c:188:25: warning: variable ‘scomph’ set but not used [-Wunused-but-set-variable]
  struct sndcp_comp_hdr *scomph = NULL;
                         ^
gprs_sndcp.c: In function ‘sndcp_llunitdata_ind’:
gprs_sndcp.c:512:11: warning: variable ‘npdu_num’ set but not used [-Wunused-but-set-variable]
  uint16_t npdu_num;
           ^
gprs_sndcp.c: At top level:
gprs_sndcp.c:565:12: warning: ‘sndcp_ll_reset_ind’ defined but not used [-Wunused-function]
 static int sndcp_ll_reset_ind(struct gprs_sndcp_entity *se)
            ^
gprs_sndcp.c:573:12: warning: ‘sndcp_ll_status_ind’ defined but not used [-Wunused-function]
 static int sndcp_ll_status_ind()
            ^
2014-04-04 12:43:08 +02:00
Holger Hans Peter Freyther
1768a5765d gprs: Reduce the number of compiler warnings in gprs_gmm.c
CC       gprs_gmm.o
gprs_gmm.c: In function ‘gsm48_tx_gmm_att_ack’:
gprs_gmm.c:350:11: warning: unused variable ‘ptsig’ [-Wunused-variable]
  uint8_t *ptsig, *mid;
           ^
gprs_gmm.c: In function ‘gsm48_rx_gmm_auth_ciph_resp’:
gprs_gmm.c:524:6: warning: variable ‘rc’ set but not used [-Wunused-but-set-variable]
  int rc;
      ^
gprs_gmm.c: In function ‘gsm48_rx_gmm_att_req’:
gprs_gmm.c:703:9: warning: implicit declaration of function ‘sgsn_acl_lookup’ [-Wimplicit-function-declaration]
         !sgsn_acl_lookup(mi_string))) {
         ^
gprs_gmm.c:632:40: warning: variable ‘old_ra_info’ set but not used [-Wunused-but-set-variable]
  uint8_t *cur = gh->data, *msnc, *mi, *old_ra_info, *ms_ra_acc_cap;
                                        ^
gprs_gmm.c: In function ‘gsm48_rx_gmm_ra_upd_req’:
gprs_gmm.c:915:6: warning: variable ‘rc’ set but not used [-Wunused-but-set-variable]
  int rc;
      ^
gprs_gmm.c:910:11: warning: variable ‘ms_ra_acc_cap’ set but not used [-Wunused-but-set-variable]
  uint8_t *ms_ra_acc_cap;
           ^
gprs_gmm.c: At top level:
gprs_gmm.c:458:12: warning: ‘gsm48_tx_gmm_auth_ciph_req’ defined but not used [-Wunused-function]
 static int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm, uint8_t *rand,
            ^
gprs_gmm.c:501:12: warning: ‘gsm48_tx_gmm_auth_ciph_rej’ defined but not used [-Wunused-function]
 static int gsm48_tx_gmm_auth_ciph_rej(struct sgsn_mm_ctx *mm)
            ^
gprs_gmm.c:1169:13: warning: ‘msgb_put_pdp_addr_ipv4’ defined but not used [-Wunused-function]
 static void msgb_put_pdp_addr_ipv4(struct msgb *msg, uint32_t ipaddr)
             ^
gprs_gmm.c:1180:13: warning: ‘msgb_put_pdp_addr_ppp’ defined but not used [-Wunused-function]
 static void msgb_put_pdp_addr_ppp(struct msgb *msg)
2014-04-04 12:41:03 +02:00
Holger Hans Peter Freyther
4766524d17 rsl: Add missing breaks in the code
Given that the method is only called for a traffic channels the
missing breaks didn't hurt.

Fixes: Coverity CID 1040731, CID 1040732, CID 1040733,
       CID 1040734
2014-04-04 12:17:28 +02:00
Holger Hans Peter Freyther
d219507d63 sgsn: Comparing array to NULL is not useful
.v is a unsigned char array with up-to 255 elements. We do not
need to add a null check here.

Fixes: Coverity CID 1040719
2014-04-04 11:55:21 +02:00
Holger Hans Peter Freyther
bd30cd3e1f bsc/msc: Extension can never be NULL use strlen instead
Fixes: Coverity CID 1040717
2014-04-04 11:53:18 +02:00
Holger Hans Peter Freyther
cb4567f117 msc: Name is never NULL use strlen to check if it is empty
Fixes: Coverity CID 1040716
2014-04-04 11:50:41 +02:00
Holger Hans Peter Freyther
8a080be4ad abis: Check for failure of ftell
In case ftell -1 will be returned. Coverity complained that the
pos we pass to fseek might be negative. In case the ftell fails
we are at the last line for sure.

Fixes: Coverity CID 1040721
2014-04-04 11:49:45 +02:00
Jacob Erlbeck
4ace424fa7 ipa: Be consistent in checking conn->cfg (Coverity)
Coverity complains about checking connection->cfg in
bsc_close_connection() at one place but not at the second.

This patch fixes this by adding a check before accessing cfg when
generating the 'partial message' log message.

Fixes: Coverity CID 1195180
Sponsored-by: On-Waves ehf
2014-04-03 12:42:04 +02:00
Holger Hans Peter Freyther
c8b2c2f10e nat: Mention the the BSC the SCCP connection was on
The log message lacked a lot of context. A SCCP connection is
created on behalf of a configured BSC. This way we should be
able to always list this information.
2014-04-03 12:30:34 +02:00
Holger Hans Peter Freyther
27aab2e1c5 gbproxy/debian: Add a start script for the GBproxy
Fixes: OW#1164
2014-04-03 12:20:15 +02:00
Holger Hans Peter Freyther
bb8d68196c nat/debian: Create an init script for the nat application 2014-04-03 12:20:15 +02:00
Jacob Erlbeck
e827812051 ipa: Use enhanced ipa_msg_recv_buffered() to cope with partioned IPA messages
The old ipa_msg_recv() implementation didn't support partial receive,
so IPA connections got disconnected when this happened.

This patch adds the handling of the temporary message buffers and uses
ipa_msg_recv_buffered().

It has been successfully tested by jerlbeck with osmo-nitb and
osmo-bsc.

Ticket: OW#768
Sponsored-by: On-Waves ehf
2014-04-01 13:40:59 +02:00
Holger Hans Peter Freyther
8a158bb1ea ctrl/abis: When the max_power_reduction changes, send it to the BTS
In case the max_power_reduction changes, issue a new Set Radio
Carrier Attributes command. OML 12.21 allows to not include the
ARFCN list and the semantic I picked/understand is that a partial
update is possible.

Fixes: SYS#267
2014-03-26 18:08:22 +01:00
Holger Hans Peter Freyther
a27303094a sgsn/ctrl: Add ctrl interface, implement listing subscribers
Add the control interface with no hierachy right now and implement
the first command to list IMSI + Context Address of active sessions.
sgsn_cmd_handle could share more code with bsc variant.

Fixes: SYS#264, SYS#265
2014-03-23 18:34:58 +01:00
Holger Hans Peter Freyther
49f9e5b6b4 ctrl: Move the lookup into a separate file in preparation for GPRS
For GPRS the look-up via bts/trx does not make any sense and would
introduce bad depdencies for the SGSN. Move the look-up code to a
new file and introduce new setup methods.
2014-03-23 16:25:16 +01:00
Holger Hans Peter Freyther
d883db027b nitb/ctrl: Implement a command to list all active subscribers
This is only useful for small networks. List the IMSI and MSISDN
of all active subscribers.

Fixes: SYS#266
2014-03-23 16:22:55 +01:00
Holger Hans Peter Freyther
2d99eeb7f2 nitb/ctrl: Implement creating and deleting subscribers
Sadly there is no proper foreign key relationship on the tables
that related to the Subscriber. This means we can't use a DELETE
with Cascade and need to delete everything by hand. To make things
worse maybe the SMS/Paging code is still using the subscriber
making the operation more dangerous. I had added NULL checks for
sender_id/receiver_id at 30C3 so we should not crash in this
situation.

Fixes: SYS#274
2014-03-23 14:05:49 +01:00
Holger Hans Peter Freyther
9dbc3f8db7 nitb/ctrl: Add command to add/modify a subscriber to the database
The test has been manually verified. Executing the select for
the subscribers showed:

sqlite> select * from Subscriber;
1|2014-03-23 12:12:46|2014-03-23 12:19:09|2620345||445567|1||0|

This created a subscriber with the right IMSI, MSISDN and has
it authorized.

Fixes: SYS#275
2014-03-23 14:05:49 +01:00
Holger Hans Peter Freyther
d092f48648 nitb/ctrl: Add ctrl command to set the TRX max_power_reduction
In case the BTS is connected the new attribute should be set
through OML. This is left as a todo item.

Addresses: SYS#267
2014-03-23 14:05:22 +01:00
Holger Hans Peter Freyther
ebe55aa95a systemd: Add service for the osmo-sgsn
Fixes: SYS#175
2014-03-21 17:43:19 +01:00
Holger Hans Peter Freyther
2826cb58bb systemd: Saying these services restart once should be enough 2014-03-21 17:41:45 +01:00
Holger Hans Peter Freyther
870cc0fdac Merge branch 'jolly/mncc'
Merge the interface changes to the MNCC protocol
2014-03-20 22:36:27 +01:00
Andreas Eversberg
63bfdd83ea mncc: Add support for half rate V1 frames to MNCC/RTP interface 2014-03-20 22:36:16 +01:00
Andreas Eversberg
9acbe4cefe mncc: Use helper function to check if an MNCC frame is data (speech/traffic)
Rename method mncc_rcv_tchf() to mncc_rcv_data(), because the check applies
to all types of data frames, not only TCH/F data.
2014-03-20 22:36:16 +01:00
Andreas Eversberg
f78fc4e76e mncc: Complete definitions for all speech traffic frames at MNCC interface
The new definitions are: half rate and AMR

Change of definition name for bad frame, because it applies to all types of
traffic, not only TCH/F.

Increase MNCC interface version to 4. Version 3 is skipped, because it was
used by older version of Linux-Call-Router which is incompatible with the
current version of the MNCC interface.
2014-03-20 22:36:16 +01:00
Holger Hans Peter Freyther
f50f70452f mgcp: The valid payload types start at 0. Fix the VTY 2014-03-20 22:34:37 +01:00
Holger Hans Peter Freyther
162a0becc5 systemd: Remove the second occurance of Restart=always 2014-03-13 18:37:19 +01:00
Nikola
9e55636fe0 trau: Fix linking on FreeBSD by using LIBRAY_DL 2014-03-11 15:41:50 +01:00
Alexander Chemeris
9e15e187cc sms: Rename gsm340_gen_tpdu() to gsm340_gen_sms_deliver_tpdu()
Rename gsm340_gen_tpdu() to gsm340_gen_sms_deliver_tpdu() to
show that it generates SMS-DELIVER TPDU and is not a generic function.
2014-03-09 19:27:46 +01:00
Alexander Chemeris
1e77e3dc5b db,sms: Rename db_sms_mark_sent() to db_sms_mark_delivered()
In MT-SMS the message is being delivered. Make the naming follow
that. The schema still refers to "sent" while it should be "delivered"
too.
2014-03-09 10:26:11 +01:00
Alexander Chemeris
82a1858eb0 db: Add more tests for retrieving subscribers from a DB. 2014-03-09 10:24:11 +01:00
Alexander Chemeris
7e20f64f27 db: Remove the german from the log message 2014-03-07 17:05:23 +01:00
Holger Hans Peter Freyther
e0bd8efcc0 Merge branch 'daniel/smpp-fixes' 2014-03-06 23:48:49 +01:00
Holger Hans Peter Freyther
ed0d4f6222 nitb/smpp: Add simple test runner for the issues found by daniel
Send the two strings that caused the read handling to misbehave.
Verify that we handle this correctly by still being able to issue
a VTY command. The CPU load issue could not be verified like this.
2014-03-06 23:48:17 +01:00
Daniel Willmann
1fc8ec66a3 smpp_smsc: Fix integer overflow in read return value and msgb_alloc()
The size parameter of msgb_alloc is uint16_t so any length value above
65535 will allocate a msgb with incorrect size.

This patch changes the type of rdlen and rc to ssize_t (the return value
of read) and guards against the read length being larger than
UINT16_MAX.

To reproduce the issue run:
echo -en "\x00\x01\x00\x01\x01" |socat stdin tcp:localhost:2775
2014-03-06 23:20:30 +01:00
Daniel Willmann
b6f01e77b1 smpp_smsc: Check that the size is large enough to hold actual data
The first 4 bytes are the length including the length field. For
length < 4 the subsequent msgb_put(msg, sizeof(uint32_t)) will fail,
resulting in an abort. The code also expects (in smpp_msgb_cmdid()) the
existence of 4 more bytes for the SMPP command ID.

This patch checks that the length received is large enough to hold all
8 bytes in the msgb and drops the connection if that's not the case.

The issue is reproducible with:
echo -e "\x00\x00\x00\x02\x00" |socat stdin tcp:localhost:2775
2014-03-06 23:20:30 +01:00
Daniel Willmann
a4540b2c3b smpp_smsc: Fix socket read() error handling
Read returning -1 is an error here so make sure to print the actual
reason and close the socket. Before this patch we just looped over the
fd with read returning -1 every time.

EINTR is handled to not cause an error and we don't need to check
EAGAIN/EWOULDBLOCK since the callback is only called in case there is
something to read.

To avoid copy&paste issues the check is implemented as a macro and the
log message moved into a separate if.
2014-03-06 23:20:30 +01:00
Ciaby
ec6e4f8b3d nitb: Add a test for "show network" in the python testsuite.
Make sure that bsc_gsmnet->bsc_data->rf_ctrl is initialized for
NITB. In commit a9fae1ae66 the
conditions for the rf_ctrl was removed but it was still needed
for the NITB.

Fixes regression from:
a9fae1ae66
bsc: rf_ctrl will always be created, remove the NULL checks
2014-03-06 17:31:23 +01:00
Holger Hans Peter Freyther
1a1463725b Merge branch 'zecke/features/extended-control' 2014-03-06 11:10:30 +01:00
Holger Hans Peter Freyther
4ecc6877a2 nat: Add CTRL command test case for the new control commands 2014-03-06 11:04:56 +01:00
Holger Hans Peter Freyther
472f3bd198 nat: Introduce command to remove an access-list-name 2014-03-04 20:39:38 +01:00
Holger Hans Peter Freyther
bc3780a73f nat: Implement setting the access-control-name through CTRL interface
For operation we want to switch the access-list of a BSC at runtime
in a programatic way.

Sponsored-by: On-Waves ehf
2014-03-04 20:39:27 +01:00
Holger Hans Peter Freyther
ecdf912ffb bsc: Include the MCC/MNC in the location trap
It is of interest to know the MCC/MNC that is broadcasted at the
specific position.

Sponsored-by: On-Waves ehf
2014-03-04 20:39:16 +01:00
Holger Hans Peter Freyther
3adb772853 libbsc: Add command to set MNC/MCC and apply it if something changed
Change the splitting of the ctrl_test_runner.py. Make sure that
we get one element and all the rest.
2014-03-04 20:38:49 +01:00
Holger Hans Peter Freyther
6ca9f4f5c3 libbsc: Add ctrl command to apply the configuration
Right now this only works for IP based BTS like the sysmoBTS and
by dropping the OML link.
2014-03-04 14:45:48 +01:00
Holger Hans Peter Freyther
f8c42191de libbsc: Add ctrl command for MNC, MCC, short-name and long-name
Add the framework for adding more setting commands.
2014-03-04 14:45:48 +01:00
Holger Hans Peter Freyther
93de8b2591 sms: Address the TODO and schedule the next SMS for an active subscriber
When one SMS has been delivered check if a second SMS can be scheduled
to that subscriber. If nothing can be scheduled kick the normal SMS queue
as one slot has become free now. Otherwise send the SMS and create a
pending entry.
2014-02-24 16:13:04 +01:00
Holger Hans Peter Freyther
024dc77de2 sms: Do not interfere with the SMS queue from within gsm_04_11
It was possible that two SMS would be delivered at the same time
which violates GSM 04.11. We should solely rely on the sms queue
to schedule more SMS to the subscriber.
2014-02-24 14:31:39 +01:00
Holger Hans Peter Freyther
98258dbbc6 bsc: Add vty command to send location trap through VTY
I have manually tested this by entering the VTY command and
observing the CTRL interface using wireshark.

Ticket: OW#1129
2014-02-22 10:36:14 +01:00
Harald Welte
7e40be3949 SMPP: UCS2 data_coding is 0x08, not 0x80!
As can clearly be seen from SMPP Spec v3.4 Chapter 5.2.19,
a SUBMIT-SM with data_coding == 0x08 is UCS2, not with 0x80.

Thanks to ciaby@rhizomatica.org for reporting the bug.
2014-02-21 13:21:03 +01:00
Holger Hans Peter Freyther
ca114432be sms: Increment the RP Message Reference for each transaction
Each RP-DATA should have a unique msg reference. Currently 42 is
used for all of these. Remember the last reference we used and
increment it on the next SMS. Do not track if the reference is
still in use a clash is a lot less likely now. First unless SMPP
is used only one SMS is delivered at a time, second the transaction
space is a lot smaller than the one for the reference.
2014-02-20 11:35:56 +01:00
Holger Hans Peter Freyther
6ab5d4f861 trau: Fix compiler warning about decoded_trau_frame
In file included from bsc_api.c:34:0:
../../include/openbsc/trau_mux.h:62:15: warning: ‘struct decoded_trau_frame’ declared inside parameter list [enabled by default]
  const struct decoded_trau_frame *tf);
               ^
../../include/openbsc/trau_mux.h:62:15: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]
../../include/openbsc/trau_mux.h:64:15: warning: ‘struct decoded_trau_frame’ declared inside parameter list [enabled by default]
  const struct decoded_trau_frame *tf);
               ^
../../include/openbsc/trau_mux.h:66:2: warning: ‘struct decoded_trau_frame’ declared inside parameter list [enabled by default]
  const unsigned char *data);
  ^
../../include/openbsc/trau_mux.h:68:2: warning: ‘struct decoded_trau_frame’ declared inside parameter list [enabled by default]
  const unsigned char *data);
2014-02-20 11:19:32 +01:00
Holger Hans Peter Freyther
34235294d7 tests: Remove unused file 2014-02-20 11:19:32 +01:00
Holger Hans Peter Freyther
a9fae1ae66 bsc: rf_ctrl will always be created, remove the NULL checks 2014-02-08 12:47:39 +01:00
Holger Hans Peter Freyther
362d10f20a libbsc: Create the RF interface all the time
The interface can be accessed through CTRL and a socket. But currently
it is only available when the socket interface has been configured.
Create the interface all the time but only listen on the socket when
a path has been specified.
2014-02-08 12:47:32 +01:00
Holger Hans Peter Freyther
8cedb11350 ctrl: Make it possible to re-use the string get and set routine
This can be used for the description field that requires some
special handling for newlines.
2014-02-04 19:35:32 +01:00
Holger Hans Peter Freyther
2c7032e4eb ctrl: Make the int range set, get and verify methods available
For the max power reduction we will need to have a different range
method. It will need to check if the value is even. Make the set,
get and verify methods available through a macro.
2014-02-04 19:35:16 +01:00
Holger Hans Peter Freyther
cdfc2061bb mgcp: Round the frame time otherwise we have porting issues
With the current multiplication we might end up with 19999 as
time on i386. When we round it ends up as 20000 on i386 and
should work the same on AMD64.
2014-02-03 13:32:34 +01:00
Holger Hans Peter Freyther
ba41978b97 mgcp: transit is a signed variable and should be printed like this
On AMD64 we had a difference in the test result most likely due
the bigger size of integers.
2014-02-03 09:20:06 +01:00
Holger Hans Peter Freyther
757971ade8 mgcp: Use the length modifier for the size_t in the printf
Should fix on AMD64:
mgcp_test.c: In function ‘sendto’:
mgcp_test.c:318:10: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘size_t’ [-Wformat]
2014-02-03 09:18:51 +01:00
Jacob Erlbeck
b281e4e6f4 mgcp/rtp: Base jitter calculation on input timestamps
So far, the jitter computation has been based on output timestamps.

This patch uses the input timestamps instead and resets jitter
computation on SSRC changes.

Sponsored-by: On-Waves ehf
2014-01-31 11:45:25 +01:00
Jacob Erlbeck
eacc9b92a1 mgcp/rtp: Compute delta timestamp based on wallclock
Currently, when the SSRC changes within a stream and SSRC fixing is
enabled, the RTP timestamp between the last packet that has been
received with the old SSRC and the first packet of the new SSRC
is always incremented by one packet duration.
This can lead to audio muting (at least with the nanoBTS) when the
wallclock interval between these packets is too large (> 1s).

This patch changes the implementation to base the RTP timestamp offset
on the wallclock interval that has passed between these two packets.

Ticket: OW#466
Sponsored-by: On-Waves ehf
2014-01-31 11:44:16 +01:00
Jacob Erlbeck
303b54a2a4 mgcp/rtp: Fix transit computation units
Currently micro-secs and RTP rate get mixed when the transit value is
computed in mgcp_patch_and_count().

This patch changes get_current_ts() to accept the desired rate as
argument and to use it for the time conversion instead of always
converting to microseconds. If microseconds are needed,
get_current_ts(1000) can be used.
The arrival_time is now measured in 1/rtp_end->rate seconds so that
it can be directly compared to RTP timestamps as required by RFC3550
(section 6.4.1, see definition of 'interarrival jitter').

Sponsored-by: On-Waves ehf
2014-01-31 11:18:25 +01:00
Jacob Erlbeck
e763f3e73e mgcp/test: Fake wallclock for RTP timing/stats tests
Currently the stats (jitter, transit) cannot be checked properly,
since they depend on the wallclock time.

This patch fakes clock_gettime (CLOCK_MONOTONIC) to reflect the
scheduling time of the RTP packets. In addition, the RTP statistical
value are written to stdout.
A RTP test case with a SSRC change along with a reference time delay
has been added.

Sponsored-by: On-Waves ehf
2014-01-31 11:18:25 +01:00
Jacob Erlbeck
cf577c3492 mgcp/test: Only include conn_mode into test output
Currently the conn_mode and the output_enabled flags are printed to
stdout.

This patch modifies this to print the output_enabled flags to stderr
instead. The bits in conn_mode are shown as RECV, SEND, and LOOP.
This does not reduce the significance of the test, since there is an
assertion already that verifies the values of the output_enabled
flags with respect to the conn_mode.

Sponsored-by: On-Waves ehf
2014-01-31 11:18:25 +01:00
Jacob Erlbeck
8e68b56fe5 sms/dtap: Add log messages to analyse SMS message loss
Incoming DTAP messages from MS are discarded during silent calls,
which leads to the repeated delivery of SMS since the ACKs are not
being processed.

This patch adds some log messages that have been helpful to track
this down.

Sponsored-by: On-Waves ehf
2014-01-31 11:17:44 +01:00
Andreas Eversberg
dcf38e1c96 Add function to update TRAU muxer after assignment or handover
E1 based BTS use TRAU muxer to decode TRAU frames. After changing
channel from one timeslot to another (due to handover or assignment),
the TRAU muxer must be updated. The call reference of the call is
disconnected from the old channel and connected to the new channel.
2014-01-27 14:39:06 +01:00
Andreas Eversberg
88012b6e87 Use 'defines' for length and duration of RTP payload 2014-01-26 08:49:35 +01:00
Holger Hans Peter Freyther
6419018e68 nat: Make the access-list deny cause configurable
Add two optional arguments to the imsi-deny rule
for the reject cause and verify that it is saved
out.
2014-01-20 10:14:05 +01:00
Holger Hans Peter Freyther
415cd2eebb nat: Introduce reject cause to bsc_nat_acc_lst_entry
The filtering architecture already allowed to specify a reject
reason but this has not been used for the access-lists. Extend
the access-list to include a reject reason and extend the test
case to honor it.
2014-01-20 10:13:36 +01:00
Jacob Erlbeck
ead0529e07 mgcp/test: Don't reset conn_mode between messages
Currently, the conn_mode field is reset after it has been checked.

This patch disables this behaviour and only adds a mark (bit) to
detect modifications.

Sponsored-by: On-Waves ehf
2014-01-20 08:27:03 +01:00
Jacob Erlbeck
e35fd13697 mgcp: Synchronize conn mode bits and output enabled flags
This patch changes implementation and the mgcp_connection_mode enum
in a way that net_end.output_enabled (bts_end.output_enabled) flag
always matches the MGCP_CONN_SEND_ONLY (MGCP_CONN_RECV_ONLY) bit of
conn_mode.

Based on this, the conn_mode bits are then used instead of the
output_enabled fields within mgcp_protocol.c.

Sponsored-by: On-Waves ehf
2014-01-20 08:27:03 +01:00
Jacob Erlbeck
8857c90e36 mgcp: Disable output enabled on initialisation
Currently RTP output_enabled is set to 1 on initialisation, which
does not semantically match the initial value of conn_mode
(MGCP_CONN_NONE).

This patch changes this initial value to 0.

Sponsored-by: On-Waves ehf
2014-01-20 08:27:03 +01:00
Harald Welte
94bc1e0b5e Fix more hidden TSC bugs for Ericsson BTS
It seems that also the Ericsson RBS2000 code was assuming that
we always use the bts-global TSC, rather than the possibly different
TS-specific TSC.
2014-01-19 17:32:59 +01:00
Harald Welte
1fe2412949 TSC: Add new gsm_ts_tsc() function to resolve TSC of TS
We don't want every caller to check for ts->tsc == -1 and then
using ts->trx->bts->tsc instead.  Rather, introduce a new inline
function to retrieve the correct value.
2014-01-19 17:32:59 +01:00
Harald Welte
903aaea668 Do not expect all BTSs support TSC != BCC
We introduce a new feature indicating if the given BTS model
supports a TSC that is different from the BCC (lower 3 bits of BSIC).
2014-01-19 17:32:56 +01:00
Harald Welte
cd4e74df95 Make gsm48_lchan2chan_desc() reflect a ts-specific TSC
If the TS has a specific, different TSC than the BTS (beacon),
we should use that with preference over the TSC of the BTS.
2014-01-19 16:55:16 +01:00
Jacob Erlbeck
1dc022cb62 openbsc: Fix coverity issues
This patch (hopefully) fixes the new defects reported by coverity.

Addresses:
** CID 1156986:  Negative array index read  (NEGATIVE_RETURNS)
/tests/gsm0408/gsm0408_test.c: 419 in test_si_range_helpers()
/tests/gsm0408/gsm0408_test.c: 423 in test_si_range_helpers()
/tests/gsm0408/gsm0408_test.c: 427 in test_si_range_helpers()

** CID 1156987:  Unchecked return value from library
(CHECKED_RETURN)
/src/libmgcp/mgcp_protocol.c: 1150 in mgcp_keepalive_timer_cb()

** CID 1156988:  Unchecked return value from library
(CHECKED_RETURN)
/src/libmgcp/mgcp_protocol.c: 983 in handle_modify_con()

Sponsored-by: On-Waves ehf
2014-01-17 14:36:51 +01:00
Andreas Eversberg
caae10b71f Remove obsolete check of conn and lchan pointers not beeing NULL
The check is removed from gsm48_cc_rx_setup() and gsm48_cc_rx_call_conf().
Receiving a layer 3 message implies that the transaction has a subscriber
connection and a logical channel.

This patch fixes the Coverity issues with CID 115311 and CID 1155312.
2014-01-16 20:49:07 +01:00
Holger Hans Peter Freyther
fbb1c8f6fe Merge branch 'jerlbeck/features/mgcp-rtp-keep-alive' 2014-01-16 14:08:16 +01:00
Jacob Erlbeck
075a9ebdcc mgcp: Send RTP keepalive dummy packets to net
So far, a single dummy packet has been sent immediately after the
reception of a MDCX message. There is no dedicated keep alive
mechanism (it just worked because the audio from the MS has always
been forwarded to the NAT until the 'mgcp: Set output_enabled flags
based on the MGCP mode' patch).

This patch adds explicit, timer based keep alive handling that can be
enable per trunk. A VTY command 'rtp keep-alive' command is added for
configuration which can be used to set the interval in seconds, to
send a single packet after the reception of a CRCX/MDCX when RTP data
from the net is expected ('once'), or to disable the feature
completely ('no rtp keep-alive'). In 'send-recv' connections, only
the initial packet is sent if enabled (even when an interval has been
configured). The default is 'once'.

Note that this removes the mgcp_change_cb() from mgcp_main.c.

Sponsored-by: On-Waves ehf
2014-01-16 13:20:51 +01:00
Jacob Erlbeck
34bdc9f8fe mgcp/rtp: Send dummy packet to the RTCP destination, too
Currently a dummy packet is only sent to the RTP port. This is not
enough if RTCP must also cross the SNAT.

This patch sends an additional dummy packet to the RTCP net
destination if omit_rtcp is not set.

Sponsored-by: On-Waves ehf
2014-01-16 13:20:49 +01:00
Jacob Erlbeck
785e3c95d7 mgcp/rtp: Make offset computation understandable
Rename the timestamp variable to make in clear, that the input
timestamp is meant. Add a helper variable to illustrate the offset
computation.

Sponsored-by: On-Waves ehf
2014-01-16 13:20:47 +01:00
Jacob Erlbeck
2645c9e7fc mgcp: Set output_enabled flags based on the MGCP mode
This patch enhances parse_conn_mode() to set the output_enabled flags
of each end based on the MGCP mode.

Ticket: OW#1044
Sponsored-by: On-Waves ehf
2014-01-16 13:20:44 +01:00
Jacob Erlbeck
84dfba1579 mgcp/test: Show the number of dummy packets sent
This patch extends the test_messages test to show the number of dummy
packets that has been passed to sendto(). This way, dummy packets are
even being counted when sendto() itself failes (e.g. due to the fd
being -1).

Sponsored-by: On-Waves ehf
2014-01-16 13:20:37 +01:00
Jacob Erlbeck
68c74f59a4 mgcp/test: Reset pkt_period_* after each test
Currently these value may leak into the next test.

This patch will reset them after each message has been processed.

Sponsored-by: On-Waves ehf
2014-01-16 12:17:24 +01:00
Jacob Erlbeck
1b653af283 mgcp/test: Test the connection mode parser
This modifies the test MGCP messages to include M:recvonly (CRCX),
M:sendrecv (MDCX) and M:sendonly (MDCX) outputs the resulting
output_enabled flags and the conn_mode after processing the message.

Sponsored-by: On-Waves ehf
2014-01-16 12:17:24 +01:00
Jacob Erlbeck
0970bab2a3 mgcp/rtp: Add flag to disable RTP output
This patch make it possible to have a valid endpoint that drops all
outgoing RTP packets. The number of dropped packets is shown by the
VTY 'show mgcp' command. By default, this feature is disabled. To
enable packet dropping, the corresponding output_enabled field must
be set to 0.

Ticket: OW#1044
Sponsored-by: On-Waves ehf
2014-01-16 12:17:24 +01:00
Jacob Erlbeck
b830008020 mgcp/rtp: Refactor mgcp_send to avoid code duplication
Currently there are two symmetric code paths which are selected by
the packet destination (NET or BTS).

This patch introduces 3 variables that take the different values
and unifies both code paths into one.

Sponsored-by: On-Waves ehf
2014-01-16 12:17:24 +01:00
Holger Hans Peter Freyther
d9c1d31a6a Merge remote-tracking branch 'origin/jerlbeck/features/range-encode' 2014-01-16 12:06:41 +01:00
Jacob Erlbeck
64277e6514 si: Implement range 128, 256, 1024 encoding
This commit adds the implementation of these range formats to the
encoder. In addition, the work-around that tried range 512 first is
removed, so that the selection is primarily based on the max distance
between frequencies.

Ticket: OW#1061
Sponsored-by: On-Waves ehf
2014-01-16 12:04:30 +01:00
Jacob Erlbeck
f8f72e23ca si: Add generic range w(k) encoder
Currently the encoding of the chan_list is done by a hard-coded
sequence of macros that closely resembles figure 10.5.16 in
3GPP TS 04.08.

This patch replaces this by an algorithmic solution that can be used
for all range encodings and is based on the property

    W(2^i) to W(2^(i+1)-1) are on w1_len-i bits when present

(see section 10.5.2.13 in TS 04.08).

Ticket: OW#1061
Sponsored-by: On-Waves ehf
2014-01-16 12:04:30 +01:00
Jacob Erlbeck
45014a0cad si: Fix range1024 encoding
f0 is currently set to arfcns[0] in range_enc_determine_range(),
while GSM 04.08 requires f0 to be ARFCN 0 in range1024 encoding.

This patch modifies range_enc_determine_range() to force f0 to be 0
if this encoding is used. This way the case distinction in
range_enc_filter_arfcns() is not longer necessary.

Sponsored-by: On-Waves ehf
2014-01-16 12:04:30 +01:00
Jacob Erlbeck
131406c86d si: Fix range512 encoding
This patch fixes a bug in the range encoder that leads to wrong
encoding when 17 or more ARFCNs are encoded.

Sponsored-by: On-Waves ehf
2014-01-16 12:04:30 +01:00
Jacob Erlbeck
9444d4f8e2 si/test: Merge si tests into gsm48 tests
Currently tests covering features of the GSM 04.08 specification are
spread over the si and gsm0408 subdirs in tests.

This commit merges all tests from 'si' into 'gsm0408' and removes the
'si' test sub-directory.

Sponsored-by: On-Waves ehf
2014-01-16 12:04:30 +01:00
Jacob Erlbeck
4b903b4afb si/test: Add tests for range encoding/decoding
This commit adds test range encoding tests. They check the property
decoding(encoding(L)) = L and optionally dump the results and
encoded sequences to stdout.

There a 2 test modes:

 - A list of fixed tests
 - A random number based test loop per ARFCN list size (only dumps
   the first failing test)

Sponsored-by: On-Waves ehf
2014-01-16 12:04:29 +01:00
Jacob Erlbeck
65d114fe43 si: Add a config option to disable SI2ter/SI2bis/SI5ter/SI5bis messages
The iPhone5 (US) appears to have some issues with the SIs generated,
or the nanoBTS is not sending them correctly.

Add a configurable hack to put all bands into the SI2/SI5 message.
It is enabled by the bts VTY command 'force-combined-si'.

This is a quick change without much reflection and watching for side
effects. I have verfied that a network with ARFCN 134 and neighbors
ARFCN 130 and 512 do not get generate the SI2ter and announce everything
inside the SI2.

This patch is conceptually based on 'si: Add a hack to disable
SI2ter/SI2bis/SI5ter/SI5bis messages' (692daaf2d2).

Ticket: OW#1062
Sponsored-by: On-Waves ehf
2014-01-16 12:04:22 +01:00
Andreas Eversberg
a83d511b61 Each BTS can be configured for speech support (other than GSM full rate)
Speech codings which are not supported by BTS will be removed from the
bearer capability information element after parsing. This way it is not
required for the MNCC application to consider support of each BTS.

Only GSM full rate is supported by default.
2014-01-14 17:37:02 +01:00
Andreas Eversberg
7d8fa3418f Add VTY option for Nokia BTS that does not send RELease CONFirm message
This option is a workarround for a bug found in Nokia InSite BTS firmware
version 3.0.0. There is no RELease CONFirm message for local end release.
Nokia MetroSite with firmware version 4.178.16 is not affected.

TS 04.06 Chapter 5.4.4.4 "Local end release procedure" states that a
confirm must be sent by layer 2 when receiving a local end release
request.

In order to correctly switch a channel (handover or assignment), local
end release is required.
2014-01-09 08:12:14 +01:00
Jacob Erlbeck
f46e226428 nitb: Set the DST field in generated MM info messages
Currently the NET_DST information element (see GSM 24.008) is not
included in generated MM info messages even when the DST field in the
timezone info has been set via the VTY or the control interface.

This patch modifies gsm48_tx_mm_info() to append this information
element if (and only if) a non-zero DST has been configured. The
DST IE is not part of GSM 4.8. Therefore it will only be sent, if the
DST offset is configured to a value != 0.

The DST functionality has been verified with wireshark by Jacob.

Sponsored-by: On-Waves ehf
2014-01-08 10:49:26 +01:00
Holger Hans Peter Freyther
095bd36627 smpp: In case we know the receiver set the context for logging 2013-12-29 20:30:02 +01:00
Holger Hans Peter Freyther
249b3f38c5 mncc: Add the context we get from the MNCC interface
Currently we only set the SUBSCR on RSL messages. Extend it to
messages that go through MNCC. For call control/bridging it is
difficult to pick the right subscriber. We should support a list
or at least two legs in the imsi filter context.
2013-12-29 20:24:37 +01:00
Tobias Engel
ea730327d1 ussd: Reject and release unhandled SS requests/interrogation
In case the unpack of a USSD request is failing the channel would
remain open and the phone would not receive a response. Simply
reject the interrogation.

Example interrogation:
0000   1b 7b 1c 0d a1 0b 02 01 01 02 01 0e 30 03 04 01
0010   11 7f 01 00
2013-12-28 17:52:23 +01:00
Holger Hans Peter Freyther
f76ed2d089 sms: Fix crash on RLL Establish Request timeouts with active call
Sylvain pointed out that in the current crash log the transaction
we try to read the SMS from is actually a transaction for Call
Control. On AMD64 the struct layout is different and that leads to
a crash when the CC transaction is in front of the SMS transaction.

Look at the trans->protocol to fix the crash. The issue got
introduced in 6a3d765bf9 (2010)
when I added the SAPI N Reject handling.

 #0  smpp_sms_cb (subsys=1, signal=4, handler_data=0xbb8270, signal_data=0x7fff33574ea0)
     at smpp_openbsc.c:284
 284		if (sms->source != SMS_SOURCE_SMPP)
 (gdb) bt
 #0  smpp_sms_cb (subsys=1, signal=4, handler_data=0xbb8270, signal_data=0x7fff33574ea0)
     at smpp_openbsc.c:284
 #1  0x00007f424e4a094c in osmo_signal_dispatch (subsys=1, signal=4,
     signal_data=0x7fff33574ea0) at signal.c:105
 #2  0x000000000042b070 in send_signal (sig_no=<optimized out>, trans=<optimized out>,
     sms=<optimized out>, paging_result=<optimized out>) at gsm_04_11.c:125
 #3  0x000000000042ccd2 in gsm411_sapi_n_reject (conn=0xec6790) at gsm_04_11.c:1000
 #4  0x0000000000408983 in send_sapi_reject (link_id=<optimized out>, conn=<optimized out>)
     at bsc_api.c:733
 #5  rll_ind_cb (_data=<optimized out>, lchan=<optimized out>, link_id=<optimized out>,
     rllr_ind=<optimized out>) at bsc_api.c:755
 #6  rll_ind_cb (lchan=<optimized out>, link_id=<optimized out>, _data=<optimized out>,
     rllr_ind=<optimized out>) at bsc_api.c:736
 #7  0x000000000041f8d2 in complete_rllr (rllr=<optimized out>, type=<optimized out>)
     at bsc_rll.c:55
 #8  0x00007f424e4a03bc in osmo_timers_update () at timer.c:243
 #9  0x00007f424e4a069b in osmo_select_main (polling=0) at select.c:133
 #10 0x0000000000407394 in main (argc=<optimized out>, argv=0x7fff33575238) at bsc_hack.c:346
 (gdb) frame 3
 #3  0x000000000042ccd2 in gsm411_sapi_n_reject (conn=0xec6790) at gsm_04_11.c:1000
 1000				send_signal(S_SMS_UNKNOWN_ERROR, trans, sms, 0);
 (gdb) p trans
 $1 = (struct gsm_trans *) 0xedba80
 (gdb) p *trans
  ....
          data = 0x1}}, sms = 0x3439323400000003}}}
 (gdb) p trans->protocol
 $4 = 3 '\003'
2013-12-27 22:57:56 +01:00
Holger Hans Peter Freyther
900394acf3 db: Avoid crash we have seen with the dbi code when reading a SMS
Avoid a crash when reading a SMS and a Subscriber could not be resolved.
It is not clear why the read was failing. The sender_id and the receiver_id
was valid for the given sms. I assume that the database has been locked
due external access to it.

The side-effect is that in case of such a failure the sms_queue will start
to deliver starting from subscriber id = 0 again.

 #1  0x0000000000428bec in sms_from_result (net=0x156a270, result=0x15eda30) at db.c:1146
 #2  0x000000000042a8e0 in db_sms_get_unsent_by_subscr (net=0x156a270,
     min_subscr_id=<optimized out>, failed=<optimized out>) at db.c:1255
 #3  0x000000000042e900 in take_next_sms (smsq=<optimized out>) at sms_queue.c:193
 #4  sms_submit_pending (_data=0x158e300) at sms_queue.c:227
 #5  0x00007f3fd30de3bc in osmo_timers_update () at timer.c:243
 #6  0x00007f3fd30de69b in osmo_select_main (polling=0) at select.c:133
 #7  0x0000000000406fbc in main (argc=9, argv=<optimized out>) at bsc_hack.c:346
 (gdb) frame 1
 #1  0x0000000000428bec in sms_from_result (net=0x156a270, result=0x15eda30) at db.c:1146
 1146		strncpy(sms->src.addr, sms->sender->extension, sizeof(sms->src.addr)-1);
 (gdb) p *sms
 (gdb) p sms->sender
 $1 = (struct gsm_subscriber *) 0x0
 (gdb) p sender_id
 $2 = <optimized out>
2013-12-27 20:20:55 +01:00
Holger Hans Peter Freyther
b1d71d4267 bsc: Reduce the RLL timeout to be smaller than TC1/max_retr+1
Sylvain pointed out that the RLL and the SMC timeout is the same.
This can lead to have a SMC re-transmission before the first RLL
Establish Request has timed out. Reduce the RLL timeout. GSM 08.58
does not specify a timeout so right now I just reduce it to seven
seconds.
2013-12-27 19:21:58 +01:00
Holger Hans Peter Freyther
8effcb747d libmsc: Set the "trans->conn" to NULL to catch invalid usage
Make finding use-after-free more easy and set it to NULL.
2013-12-27 18:07:23 +01:00
Holger Hans Peter Freyther
1a345ca48f lu crash: Fix a crash that likely occurred during the LU procedure
conn->loc_operation is already NULL (e.g. due a five second timeout but
we are still processing a RSL message after we initiated the release
procedure). Do not attempt to authorize a subcriber without knowing the
key_sequence.

This can cause more problems but we will need to test this in the field.

(gdb) bt
 #0  gsm0408_authorize (conn=0x19fc2f0, msg=<optimized out>) at gsm_04_08.c:323
 #1  gsm0408_authorize (conn=0x19fc2f0, msg=<optimized out>) at gsm_04_08.c:319
 #2  0x000000000043a99a in mm_rx_id_resp (conn=0x19fc2f0, msg=<optimized out>)
     at gsm_04_08.c:495
 #3  gsm0408_rcv_mm (msg=<optimized out>, conn=0x19fc2f0) at gsm_04_08.c:1041
 #4  gsm0408_dispatch (conn=0x19fc2f0, msg=<optimized out>) at gsm_04_08.c:3232

(gdb) p *conn
 $5 = {entry = {next = 0x1746930, prev = 0x1a14270}, subscr = 0x1745eb0,
  expire_timer_stopped = 1 '\001', loc_operation = 0x0, sec_operation = 0x0,
  anch_operation = 0x0, silent_call = 0, put_channel = 0, sccp_con = 0x0, in_release = 0,
  lchan = 0x7f8c79007218, ho_lchan = 0x0, bts = 0x1719f90, T10 = {node = {
      rb_parent_color = 0, rb_right = 0x0, rb_left = 0x0}, list = {next = 0x0, prev = 0x0},
    timeout = {tv_sec = 0, tv_usec = 0}, active = 0, cb = 0, data = 0x0},
  secondary_lchan = 0x0}
2013-12-27 17:37:27 +01:00
Holger Hans Peter Freyther
2147bc4cc9 periodic/lu: Attempt to implicitly attach a subscriber instead of rejecting
When modern Smartphones receive "Not in VLR". The baseband firmware
apparently does not try to do an IMSI ATTACH but just remains un-happy
and will not connect to the network anymore.
2013-12-27 17:22:32 +01:00
Holger Hans Peter Freyther
defb10fa62 Revert "gsm_04_11: Speculative fix for MT SMS and SAPI 'n Reject"
Let's revert it and see if we can find the real issue about the
sms being invalid. Sylvain has pointed out that we get invoked
from a timer and might not have stopped it properly.

This reverts commit 80ba9b5dd6.
2013-12-27 16:32:59 +01:00
Holger Hans Peter Freyther
80ba9b5dd6 gsm_04_11: Speculative fix for MT SMS and SAPI 'n Reject
I am not sure why it is crashing so this is a speculative fix based on
something we already did in 3e9b2ec257.

 #0  sms_find_pending (smsq=0x2706300, sms=<optimized out>) at sms_queue.c:77
 #1  sms_sms_cb (subsys=<optimized out>, signal=4, handler_data=0x26e2270,
     signal_data=0x7fffdac256c0) at sms_queue.c:396
 #2  0x00007fcdea94394c in osmo_signal_dispatch (subsys=1, signal=4,
     signal_data=0x7fffdac256c0) at signal.c:105
 #3  0x000000000042acc0 in send_signal (sig_no=<optimized out>, trans=<optimized out>,
     sms=<optimized out>, paging_result=<optimized out>) at gsm_04_11.c:124
 #4  0x000000000042c8e2 in gsm411_sapi_n_reject (conn=0x2722d30) at gsm_04_11.c:999
 #5  0x00000000004085d3 in send_sapi_reject (link_id=<optimized out>, conn=<optimized out>)
     at bsc_api.c:733
 #6  rll_ind_cb (_data=<optimized out>, lchan=<optimized out>, link_id=<optimized out>,
     rllr_ind=<optimized out>) at bsc_api.c:755
 #7  rll_ind_cb (lchan=<optimized out>, link_id=<optimized out>, _data=<optimized out>,
     rllr_ind=<optimized out>) at bsc_api.c:736
 #8  0x000000000041f522 in complete_rllr (rllr=<optimized out>, type=<optimized out>)
     at bsc_rll.c:55
 #9  0x00007fcdea9433bc in osmo_timers_update () at timer.c:243
 #10 0x00007fcdea94369b in osmo_select_main (polling=0) at select.c:133
 #11 0x0000000000406fbc in main (argc=9, argv=<optimized out>) at bsc_hack.c:346
2013-12-27 15:26:42 +01:00
Holger Hans Peter Freyther
91acfa0720 sms: Move to gsm_7bit_encode_n in the sms sending code
Do not rely on the potential wrong gsm_7bit_encode result but
use gsm_7bit_encode_n with maximum available space.
2013-12-26 22:33:02 +01:00
Holger Hans Peter Freyther
1f229b344e ussd: Move to use gsm_7bit_encode_n_ussd for USSD encoding
The legacy functions have a bad/wrong return value for the number
of septets in the string. Change the code to use the new functions
which will fix encoding issues as well.
2013-12-26 22:17:45 +01:00
Kevin Redon
c9763a3de4 db: Fetch the authorized key using ulonglong
Location Update Requests time out and get rejected because the
subscriber is not authorized. Authorizing the subscriber through
openBSC or sqlite3 doesn't help the subscriber is still seen and
shown as not authorized

The value is read as uint, this is the wrong type it's a (u)longlong
in libdbi 0.9.0 and later.
2013-12-26 16:02:03 +01:00
Jacob Erlbeck
4bbddc6de9 mgcp/rtp: Only patch timestamp alignment errors
Currently, all timestamps are force to SeqNo*d + C which is more than
required by the nanoBTS which seems to be sensitive to alignment
errors only (dTS != k*d, d = ptime * rate = 160).

This patch replaces the force_constant_timing feature by a
force_aligned_timing feature. The timestamp offset will only be
changed (and timestamp errors counted) when the alignment does not
match to the raster based on ptime (default 20ms).

The VTY interface does not change.

Sponsored-by: On-Waves ehf
2013-12-19 11:56:11 +01:00
Jacob Erlbeck
65c7a4551a mgcp/test: Use differential output for counters and timestamp
Currently the counter and output timestamp values are written out for
each packet. This makes it difficult to see in the diffs what has
been changed significantly.

This patch changes this by showing differences for those
values. The absolute input values are also shown now. In addition,
the sequence numbers (the difference for the output value) are
written, too.

Sponsored-by: On-Waves ehf
2013-12-19 11:56:11 +01:00
Jacob Erlbeck
93c9da3b37 mgcp/test: Add test cases for constant RTP sequence number
This adds two test cases:
  1. Packet repetition (dSeq=0, dTS=0)
  2. Broken seqNo (dSeq=0, dTS=160)

The second had been already present in the test cases, but it was a
mere copy&paste mistake which turned out to be rather helpful. This
patch therefore turns it into a documented test case.

Sponsored-by: On-Waves ehf
2013-12-19 11:56:11 +01:00
Andreas Eversberg
d074f8f396 Add EFR support to TRAU muxer + test case
Decoding and encoding of FR and EFR TRAU frames are put into seperate
functions. CRC check is done to detect bad EFR TRAU frames.

The test case includes FR and EFR transcoding.

EFR support was tested with Nokia InSite BTS and Siemens BS11.
2013-12-19 10:12:28 +01:00
Andreas Eversberg
b6f9516193 Fix: Nokia requires VTY's "oml e1" parameters also
When writing config file, OML configuration must be written for all
E1 based BTS, which includes Nokia *Site BTS.
2013-12-18 16:23:39 +01:00
Jacob Erlbeck
eddaa9f19e contrib/rtp: Fix default payload case
There is the wrong record field selection being used to extract the
default value. It returns the tuple offset instead of the value.

This patch fixes this.

Sponsored-by: On-Waves ehf
2013-12-18 16:16:42 +01:00
Holger Hans Peter Freyther
daf2a38eb6 Merge branch 'jerlbeck/features/mgcp-get-info-from-sdp' 2013-12-13 13:51:50 +01:00
Jacob Erlbeck
0a1bc56e5a mgcp: Optionally send ptime in SDP
Currently the SDP 'ptime' media attribute is never set in generated
MGCP responses.

This patch optionally includes the 'ptime' attribute if
packet_duration_ms is != 0. This behaviour can be enabled/disabled
by using the VTY command "sdp audio-payload send-ptime" (enabled by
default).

Sponsored-by: On-Waves ehf
2013-12-13 13:51:29 +01:00
Jacob Erlbeck
24754f0490 mgcp: Parse SDP to get rate and packet duration
This patch parses the 'ptime' and 'maxptime' SDP attributes, and the
SDP rate information and sets up packet_duration_ms accordingly. If
the packet duration is unknown or allows for different values (e.g.
because 'ptime' uses a range or 'maxptime' allows for more than one
frame) the duration is set to 0.

Sponsored-by: On-Waves ehf
2013-12-13 13:49:32 +01:00
Jacob Erlbeck
2c2ca4df38 mgcp: Put local connection options into a struct
Currently the local connection options have been stored as a string.

This patch replaces this string by a struct (that still contains a
string) along with the parsed fields (only the packetization period
at the moment).

It also re-adds the calls to set_local_cx_options() to the
handle_create_con() and handle_modify_con() functions. Except for
the test program this has no side effects, since the LCO values
aren't used yet.
2013-12-13 13:48:04 +01:00
Jacob Erlbeck
ba477d2ba3 mgcp/test: Output the packet duration after MGCP parsing
This also adds additional MDCX tests (based on MDCX4) to test the
analysis of different combinations of 'p' and 'ptime' fields.

Sponsored-by: On-Waves ehf
2013-12-13 13:45:19 +01:00
Jacob Erlbeck
33f300915a mgcp/rtp: Refactor timestamp offset calculation into own function
Currently the timestamp offset calculation is done in two different
places.

This patch moves and unifies both code parts into a separate function.

Sponsored-by: On-Waves ehf
2013-12-13 13:45:19 +01:00
Jacob Erlbeck
e8ae1ac76a contrib/rtp: Add tool to create RTP state files
This tool provides the following features:
  - Output formats: state, C arrays
  - Optionally take RTP payload from existing state files
  - Generate streams with RTP timestamp jumps and/or delays
  - Set/change SSRC or payload type

Requires erlang to be installed.

Example:
  Generate 300 packets, set playout time offset to 1s, set
  RTP timestamp offset to 8000 (1s), generate another 100
  packets, the RTP payload is copied from rtp.state:

  ./gen_rtp_header.erl --type=98 --file=rtp.state  --
      0 300 0 --delay=1.0 100 8000

Sponsored-by: On-Waves ehf
2013-12-13 13:40:11 +01:00
Jacob Erlbeck
8b66649883 contrib/rtp: Enhance RTP replay tool
This patch adds optional parameters to pass the state file, the
destination address (default 127.0.0.1), the destination port
(default 4000), the source port (default 0). So it is called as
follows:

    gst rtp_replay.st -a [FILE [HOST [SOURCEPORT [DESTPORT]]]]

In addition, nonexistant FILEs are no longer created but opened
read-only instead.

Sponsored-by: On-Waves ehf
2013-12-13 13:40:09 +01:00
Holger Hans Peter Freyther
e828b661a7 build: db_test does not use dlopen/dlsym.. remove LIBRARY_DL from deps 2013-12-13 10:18:33 +01:00
Holger Hans Peter Freyther
a066d38fbf build: channel_test does not use dlopen/dlsym remove LIBRARY_DL dep 2013-12-13 10:18:32 +01:00
Holger Hans Peter Freyther
fd465bcdf1 build: osmo-nitb does not use dlopen/dlsym remove LIBRARY_DL
osmo-nitb does not use dlopen/dlsym so we can remove the depedency
to LIBRARY_DL.
2013-12-13 10:18:32 +01:00
Holger Hans Peter Freyther
5b0e8706e8 build: Remove bogus depends from ipaccess-config
The code does not use libmsc and doesn't use dlsym/dlopen etc. So
let us remove LIBRARY_DL as dependency.
2013-12-13 10:18:32 +01:00
Nikola
876b55af33 freebsd: dlopen/dlsym/dlerror is part of libc, use LIBRARY_DL for linking
In FreeBSD there is no spearate library for dlopen, dlsym and dlerror.
Use LIBRARY_DL to check for this condition.
2013-12-13 10:18:19 +01:00
Holger Hans Peter Freyther
27a788ddb9 si: Make sure to not overwrite orig_arfcn_hi in the range encoding
Andreas highlighted that the doubel assignment is not needed and
wrong. Change the code to assign chan_list[0] before writing the
base frequency to the header. Update the testcase to make the highest
bit set and update the test result.
2013-12-12 17:00:57 +01:00
Holger Hans Peter Freyther
e18209c975 ipa-proxy: Socket creation can fail, address coverity issue
Fixes: Coverity CID 1040722
2013-12-12 16:20:19 +01:00
Holger Hans Peter Freyther
7f180e83c3 vty: Address coverity issue with subscr->name never being NULL
Coverity points out that subscr->name is an array and never NULL.
Use strlen instead in this check.

Fixes: Coverity CID 1040717
2013-12-12 16:20:12 +01:00
Holger Hans Peter Freyther
a5ddf489e1 subscriber: Address coverity warning and truncate the IMSI
The IMSI can only be 15 characters in length, our define gives
us a length of 17. This means we have place for two NULs. Use
strncpy and make sure it is null-terminated.

Fixes: Coverity CID 1040707
2013-12-12 16:20:07 +01:00
Holger Hans Peter Freyther
7672db33bd smpp_mirror: Initialize rc when cmd_id is not DELIVER_SM
Fixes: Coverity CID 1042369
2013-12-12 16:20:01 +01:00
Holger Hans Peter Freyther
109583dacb build: Ignore file generated by automake 2013-12-12 13:08:48 +01:00
Holger Hans Peter Freyther
a80100644c mgcp: Address compiler error for sprintf misusage...
The hardening flags of debian have highlighted this sprintf mis-usage
in the testcase. Address it.
2013-12-12 13:08:26 +01:00
Holger Hans Peter Freyther
12355ae658 debian: Enable hardening for the OpenBSC packages 2013-12-12 13:08:26 +01:00
Holger Hans Peter Freyther
65f7427e02 debian: Build debug packages for each of the target packages 2013-12-12 13:08:26 +01:00
Holger Hans Peter Freyther
9f4f4e6c29 Merge remote-tracking branch 'jerlbeck/features/rtp-header-patching' 2013-12-10 12:50:38 +01:00
Jacob Erlbeck
f6ec0e9fc4 mgcp/rtp: Refactored packet_duration computation
Since the packet duration is given in ms with the 'ptime' RTP media
attribute and also with the 'p' MGCP local connection option, the
computation is changed to use this value (if present). The
computation assumes, that there are N complete frames in a packet and
takes into account, that the ptime value possibly had been rounded
towards the next ms value (which is never the case with a frame length
of exact 20ms).

Sponsored-by: On-Waves ehf
2013-12-10 11:17:44 +01:00
Jacob Erlbeck
58340e5b5b mgcp/rtp: Fix RTP timestamps if enabled
This forces the output timing to fulfill
   dTS = dSegNo * fixedPacketDuration
where dSegNo = seqNo - lastSeqNo.

If timestamp patching is enabled, the output timestamp will be set
to lastTimestamp + dTS. This kind of relative updating is used to
handle seqNo- and timestamp-wraparounds properly.

The updating of timestamp and SSRC has been separated and the patch
field of mgcp_rtp_state has been renamed to patch_ssrc to reflect
it's semantics more closely. The offset fields are now used always
and will change the corresponding header field if they are != 0.

Ticket: OW#1065
Sponsored-by: On-Waves ehf
2013-12-10 11:17:44 +01:00
Jacob Erlbeck
e2292f3aa1 mgcp/rtp: Only patch SSRC once after MDCX if enabled
Currently the output SSRC is always forced to be the same if SSRC
patching is enabled.

This patch modifies this to optionally restrict the number of SSRC
changes that will be corrected.

Note that the configuration only allows for the 'once' mode and 'off'.

Sponsored-by: On-Waves ehf
2013-12-10 11:17:42 +01:00
Jacob Erlbeck
3da9e4e441 mgcp/rtp: Use SSRC in proper byte ordering
The ssrc has been used without respect to proper byte ordering in
mgcp_patch_and_count(). This only affected log messages.

This patch introduces a new variable 'ssrc' that takes the value of
the SSRC in proper byte order.

Sponsored-by: On-Waves ehf
2013-12-10 11:13:22 +01:00
Jacob Erlbeck
30ce42250f mgcp/rtp: Compute default packet duration at state initialisiation
This patch adds a packet_duration field to mgcp_rtp_state which
contains the RTP packet's duration in RTP timestamp units or 0, when
the duration is unknown or not fixed.

Sponsored-by: On-Waves ehf
2013-12-10 11:13:22 +01:00
Jacob Erlbeck
b35a77751b mgcp/rtp: Only update RTP header field offsets if enabled
Currently seq_offset and timestamp_offset are updated on each SSRC
change even when SSRC patching is not allowed.

This patch fixes this by changing mgcp_patch_and_count() to only
update these fields when SSRC patching is allowed.

Sponsored-by: On-Waves ehf
2013-12-10 11:13:22 +01:00
Jacob Erlbeck
5e9549e6a9 mgcp/rtp: Change the log message shown when the SSRC changes
Show old and new SSRC. Move logging command upward to show the values
immediately after the change has been detected and before any fixing
attempt is made.

Sponsored-by: On-Waves ehf
2013-12-10 11:13:22 +01:00
Jacob Erlbeck
db2d431697 mgcp/rtp: Add RTP header patch mode configuration
This adds datastructures and a VTY frontend to configure the
different type of RTP header patching: SSRC and timestamp.

Note that timestamp patching is not yet implemented.

Sponsored-by: On-Waves ehf
2013-12-10 11:11:42 +01:00
Jacob Erlbeck
55ba140da1 mgcp/rtp: Fix output timing error counter
The tsdelta computation and error detection didn't handle the
intialisation phase properly.

This patches fixes this by skipping the output timing validation
when the SSRCs don't match.

Sponsored-by: On-Waves ehf
2013-12-05 16:55:39 +01:00
Jacob Erlbeck
83c0523739 mgcp/rtp: Add more test cases for RTP header patching
This patch extends the existing RTP error check test by adding a
check for timestamp errors after SSRC changes and a check for a
segno delta of 2 (with a timestamp delta of 320).

To test SSRC patching too, a corresponding line will be written on
each SSRC change that has been detected in the output stream.

In addition there is now support for selectively enabling/disabling
SSRC and timestamp patching. The RTP test sequence is repeated for
all combinations thereof.

Sponsored-by: On-Waves ehf
2013-12-05 16:54:25 +01:00
Holger Hans Peter Freyther
598b1c7231 Merge branch 'jerlbeck/mgcp-cleanups' 2013-12-05 10:32:06 +01:00
Jacob Erlbeck
78a9501cfd mgcp: Handle SDP in CRCX received by the MGW
So far the SDP part of the CRCX message has been ignored by the MGW.

This patch adds SDP parsing for this case, eventually updating the
net end's payload type and connection parameters.

Sponsored-by: On-Waves ehf
2013-12-05 10:28:51 +01:00
Jacob Erlbeck
3dff27d38d mgcp/nat: Take payload type from SDP data
So far the payload type used in RTP streams has been taken from the
trunk configuration in NAT mode.

This patch changes the implementation to use the payload type
announced in the SDP part of MGCP messages and responses. SDP
descriptions more than one m=audio line are not yet supported
properly (always the last one is taken).

Ticket: OW#466
Sponsored-by: On-Waves ehf
2013-12-05 10:28:48 +01:00
Jacob Erlbeck
9107e2da13 mgcp: NUL-terminate MGCP message
The MGCP message isn't always NUL-terminated when arriving at
mgcp_handle_message(). This may lead to undefined results.

This patch ensures that the message text is NUL-terminated by
setting *msg->tail to '\0' in mgcp_handle_message().

Addresses:
<000b> mgcp_protocol.c:642 Unhandled option: 'r'/114 on 0x3
<000b> mgcp_protocol.c:593 Unhandled SDP option: '='/61 on 0x3
<000b> mgcp_protocol.c:871 Unhandled option: '.'/46 on 0x2

Sponsored-by: On-Waves ehf
2013-12-05 10:28:23 +01:00
Jacob Erlbeck
1771171e05 mgcp: Refactor MGCP/SDP parsing
This patch separates the SDP parsing from the (message specific) MGCP
parsing.

Sponsored-by: On-Waves ehf
2013-12-05 10:27:33 +01:00
Jacob Erlbeck
a52ac66e52 mgcp: Add tests for payload types in MGCP messages
These tests mainly check whether the SDP parsing works properly by
looking at the payload type detected.

Sponsored-by: On-Waves ehf
2013-12-05 10:27:32 +01:00
Jacob Erlbeck
2bee7f96ff mgcp: Add new for_each_line macro that also returns empty lines
This patch add the for_each_line macro based on a strline_r()
function (similar to strtok_r()), that is also part of this patch.
This strline_r() function is tolerant with respect to line endings,
it supports CR-only, CRLF, and LF-only and any combinations thereof
(note that a CRLF is always detected as a single line break).

Similar to for_each_non_empty_line (the former for_each_line) where
the 'save' pointer needed to be initialised by a call to strtok_r(),
the new for_each_line macro expects, that the 'save' pointer has been
initialised by a call to strline_r(). Also note, that
for_each_line/strline_r and for_each_non_empty_line/strtok_r may use
the 'save' pointer differently, so calls to them can not be mixed.

Sponsored-by: On-Waves ehf
2013-12-05 10:27:32 +01:00
Jacob Erlbeck
a01bd60851 mgcp: Rename for_each_line to for_each_non_empty_line
The implementation of for_each_line is based on strtok() and skips
any sequence of CR and LF. Thus empty lines are never detected. There
exists code which tests for an empty line to detect the beginning of
the SDP part which is dead code currently (the parser works
nevertheless due to other reasons). So the semantics of this macro
have been misunderstood at least once.

This patch renames the macro to reflect the semantics more precisely.

Sponsored-by: On-Waves ehf
2013-12-05 10:27:32 +01:00
Harald Welte
19d8742820 osmo-nitb: don't print 'bac_hack' in usage/help output 2013-11-27 01:28:21 +01:00
Jacob Erlbeck
72c309021a mgcp/rtp: Fix timestamp offset when patching RTP packets
The current implementation increments the seqno but does not increment
the RTP timestamp, leading to two identical timestamps following one
after the other.

This patch fixes this by adding the computed tsdelta when the offset
is calulated. In the unlikely case, that a tsdelta hasn't been
computed yet when the SSRC changes, a tsdelta is computed based on
the RTP rate and a RTP packet duration of 20ms (one speech frame per
channel and packet). If the RTP rate is not known, a rate of 8000 is
assumed.

Note that this approach presumes, that the per RTP packet duration
(in samples) is the same for the last two packets of the stream being
replaced (the first one).

Sponsored-by: On-Waves ehf
2013-11-25 18:30:50 +01:00
Jacob Erlbeck
d62419b574 mgcp/rtp: Add test case for RTP timestamp patching and stats
This patch adds a test case to check, whether RTP timestamps are
generated properly after SSRC changes and whether the error counters
work properly.

Sponsored-by: On-Waves ehf
2013-11-25 18:13:35 +01:00
Jacob Erlbeck
50079a1843 mgcp/rtp: Add counter for invalid RTP timestamp deltas
This patch modifies the patch_and_count() function to check for RTP
timestamp inconsistencies. It basically checks, whether dTS/dSeqNo
remains constant. If this fails, the corresponding counter is
incremented. There are four counter for this: Incoming and outgoing,
each for streams from the BTS and the net.

Note that this approach presumes, that the per RTP packet duration
(in samples) remains the same throughout the entire stream. Changing
the number of speech frames per channel and packet will be detected
as error.

In addition, the VTY command 'show mgcp' is extended by an optional
'stats' to show the counter values, too.

Ticket: OW#964
Sponsored-by: On-Waves ehf
2013-11-25 18:07:21 +01:00
Holger Hans Peter Freyther
ec37bb2956 bsc: Add a VTY command to show the paging group for a BSC/IMSI 2013-11-22 16:00:00 +01:00
Jacob Erlbeck
d9e4039516 rtp: Fixed size check in padded RTP packets
This patch fixes a corner case (padding 1, payload size incl padding
0) which is not being detected correctly.

Sponsored-by: On-Waves ehf
2013-11-21 20:00:55 +01:00
Holger Hans Peter Freyther
33b9641025 bsc: Use the right string for the notification 2013-11-15 16:47:59 +01:00
Holger Hans Peter Freyther
92ce02e644 rtp: Take the parameter from the arguments
$ gst rtp_replay.st -a FILE
2013-11-14 09:45:51 +01:00
Holger Hans Peter Freyther
558bdb4330 ipa: Explain that one needs to get the IP address of the BTS as argument 2013-11-11 14:30:09 +01:00
Holger Hans Peter Freyther
49976f4c1e shared: Introduce/Add procedure pending to the MO
GSM 12.21 specifies that "No elementary procedure shall be
initiated to an object instance which has not yet replied to
a previously initiated elementary procedure with a response,
an ACK or a NACK within a layer 3 time-out. The layer 3
timeout for ACK, NACK and responses shall have a default value
of 10 seconds."

We are using this flag in the BTS to enforce/safe-guard
this situation.
2013-11-05 16:06:17 +01:00
Holger Hans Peter Freyther
82e644b572 gbproxy: The "[stats]" option was not documented, document it
Documentation error (missing docs):
<command id='show gbproxy [stats]'>
        <param name='[stats]' doc='(null)' />
2013-11-03 17:34:17 +01:00
Jacob Erlbeck
aff2d62b8c bsc/ussd: Rename bsc_send_ussd_notification()
Rename this function to bsc_send_ussd_no_srv() since it's a rather
specialised function and not a generic USSD notification function.

Sponsored-by: On-Waves ehf
2013-11-01 17:12:41 +01:00
Jacob Erlbeck
b1250312ba bsc/ussd: Send faked CM Service Accept before sending USSD
The MS do not show the USSD messages yet. This patch modifies the
implementation to insert a CM Service Accept to finish the
establishment of the MM connection according to 3GPP TS 04.10/3.2.1
before the USSD notification is sent.

This fix has been tested with a Blackberry phone that has shown
an ussd_grace_txt after rf_locked has been set to '1'. Without this
patch, that message wasn't shown. The phone has sent a CC Setup
and other messages before processing the channel release message sent
by the BSC, but these messages have not been forwarded to the MSC (as
expected).

Ticket: OW#957
Sponsored-by: On-Waves ehf
2013-11-01 17:12:39 +01:00
Jacob Erlbeck
24d3b91d46 bsc: Move gsm48_tx_mm_serv_ack/rej to gsm_04_08_utils.c
These functions are currently located in libmsc/gsm_04_08.c together
with other symbols that (transitively) depend on many external
symbols (and thus libraries) that aren't otherwise needed by e.g.
osmo-bsc.

Since gsm48_tx_mm_serv_ack() will be needed by osmo-bsc, these
functions are moved to avoid the dependency on gsm_04_08.o.

Sponsored-by: On-Waves ehf
2013-11-01 17:12:37 +01:00
Holger Hans Peter Freyther
28e183f385 Revert "bsc/ussd: Send faked CM Service Accept before sending USSD"
This reverts commit 61bd965b04.

No, we should not link to dbi.. and these libraries..
2013-10-31 13:35:28 +01:00
Jacob Erlbeck
61bd965b04 bsc/ussd: Send faked CM Service Accept before sending USSD
The MS do not show the USSD messages yet. This patch modifies the
implementation to insert a CM Service Accept before the ussdNotify
to finish the establishment of the MM connection according to
3GPP TS 04.10/3.2.1.

This fix has been tested with a Blackberry phone that has shown
an ussd_grace_txt after rf_locked has been set to '1'. Without this
patch, that message wasn't shown. The phone has sent a CC Setup
and other messages before processing the channel release message sent
by the BSC, but these messages have not been forwarded to the MSC (as
expected).

Ticket: OW#957
Sponsored-by: On-Waves ehf
2013-10-31 13:29:51 +01:00
Jacob Erlbeck
6e919dbb65 vty: Enable the end/exit test for libosmocore nodes
This patch replaces the calls to ignoredCheckForEndAndExit by calls
to checkForEndAndExit to test the libosmocore nodes, too. The former
method is removed.

Sponsored-by: On-Waves ehf
2013-10-30 15:19:02 +01:00
Jacob Erlbeck
36722e13da vty: Use vty_install_default() instead of bsc_install_default()
Remove ournode_exit_cmd, ournode_end_cmd, and bsc_install_default()
since this functionality is provided by the current libosmocore.

Replace calls to bsc_install_default() by call to
vty_install_default() with the following semantic patch:

    @rule1@
    expression N;
    @@
    - bsc_install_default(N);
    + vty_install_default(N);

Ticket: OW#952
Sponsored-by: On-Waves ehf
2013-10-30 15:19:00 +01:00
Holger Hans Peter Freyther
fc7a75f5df bts: Add a flag to remember the kind of activation/release
When the PCU is activating a channel we don't want to tell the
BSC using RSL. Add a flag so we can keep track of who asked for
the activation/release of the channel.
2013-10-25 18:58:30 +02:00
Jacob Erlbeck
64cb924634 gbproxy: Fix handling of NSEI changes
The gbproxy looses NSEI changes on BVC_RESET and then tries to send
later messages to the wrong (not longer existing) destination.

This patch fixes this by updating the peer's nsei field on BVC_RESET.

Ticket: OW#874
Sponsored-by: On-Waves ehf
2013-10-24 18:02:38 +02:00
Jacob Erlbeck
72b401f33d gbproxy: Add test for NSEI and NSVCI changes
This checks the behavior of the gbproxy when the BSS peer changes the
NSEI and the NSVCI. It also tests BVC_RESET and other UNITDATA
messages after these changes between BSS and SGSN and vice versa (via
the gbproxy).

Ticket: OW#874
Sponsored-by: On-Waves ehf
2013-10-24 18:02:36 +02:00
Jacob Erlbeck
4211d79cd1 gbproxy/vty: Enhance delete-gbproxy-peer command
This adds the option to delete all BVC peers and/or NS_VC with a
given NSEI with a single command. Static (configured) NS-VC are not
affected. In addition, all connections for this NSEI that can be
deleted by this command can be listed without deleting them by
appending 'dry-run' to the command.

Sponsored-by: On-Waves ehf
2013-10-24 18:02:33 +02:00
Holger Hans Peter Freyther
90267a961c gbproxy: Add a command to delete peers from the GBProxy
This just deletes the peer entry based on NSEI and BVCI. The NS-VC
are not touched.
2013-10-24 08:22:45 +02:00
Jacob Erlbeck
02ca7783ab gbproxy: Fix rate counter group leak in peer_free()
This also frees the counter group pointed to by peer->ctrg when the
peer gets freed.

Sponsored-by: On-Waves ehf
2013-10-24 08:22:45 +02:00
Jacob Erlbeck
6d23371805 gbproxy: Add basic VTY tests
This checks for the ns and gbproxy config nodes and show commands.

Sponsored-by: On-Waves ehf
2013-10-24 08:21:29 +02:00
Jacob Erlbeck
7587727445 vty: Fix whitespace in test script
Expands leading tabs and removes trailing whitespace.

Sponsored-by: On-Waves ehf
2013-10-24 08:21:22 +02:00
Jacob Erlbeck
f0f63a4113 gbproxy: Reject SGSN UNITDATA messages with an invalid BVCI
Currently such messages lead to a creation of a new peer with the
SGSN's NSEI, which results in echoing the message back to the SGSN.

This patch modifies this by sending a STATUS response (invalid BVCI)
instead back to the SGSN.

Sponsored-by: On-Waves ehf
2013-10-19 12:10:24 +02:00
Jacob Erlbeck
da890c7733 gbproxy: Test invalid BVCI from SGSN
This adds a test with a UNITDATA SGSN message that is addressed to an
invalid (unknown) BVCI. The test shows, that the message is echoed to
the SGSN.

Sponsored-by: On-Waves ehf
2013-10-19 12:10:21 +02:00
Jacob Erlbeck
bc555742aa gbproxy: Add global and per peer counters
This adds counters that are incremented when errors are detected.
It also modifies the VTY command 'show gbproxy' so that
'show gbproxy stats' shows the counters.

Sponsored-by: On-Waves ehf
2013-10-19 12:10:19 +02:00
Jacob Erlbeck
c5085f9d3d gbproxy: Fix warning and log message
Add the unused attribute to peer_free() that isn't used currently.
Change 'RAC' to 'NSEI' in the log message, since the latter has been
examined before the log message is generated.

Sponsored-by: On-Waves ehf
2013-10-19 12:10:16 +02:00
Jacob Erlbeck
2082afa76e gbproxy: Extended test program to simulate SGSN, too
This adds a simulation of the SGSN side of the Gbproxy. The VC is set
up correctly and several combinations of BSSGP messages are sent.

Sponsored-by: On-Waves ehf
2013-10-19 12:10:13 +02:00
Jacob Erlbeck
e75fec60d0 gbproxy: Replace NS-VC references by NSEI
Currently in most places in gb_proxy.c a reference to a NS-VC object
is used where the peer is meant instead. The patch changes this by
using the NSEI instead in these cases.

Sponsored-by: On-Waves ehf
2013-10-15 15:19:29 +02:00
Jacob Erlbeck
51a869c80c gbproxy: Add test program to test gbproxy message handling
This program tests the gbproxy implementation by passing NS messages
to a modified gbproxy that dumps the resulting messages, signals, and
state.

It focusses on testing abnormal situations like port changes.

Ticket: OW#874
Sponsored-by: On-Waves ehf
2013-10-15 15:10:22 +02:00
Alexander Huemer
475f513aea ussd: Fix test for RELEASE COMPLETE
A correcsponding change in libosmocore sets text[0] to '\0'.
The test for 0xFF could never have been true.
2013-10-15 13:29:25 +02:00
Holger Hans Peter Freyther
8c90f47b09 misc: Require libosmocore 0.6.4 and libosmogb 0.6.4 2013-10-15 13:29:25 +02:00
Holger Hans Peter Freyther
7634ec1de1 db: Remove the struct gsm_network from the database layer
The database code should not know about the network. Move the
setting of the network pointer into the subscriber layer.
2013-10-13 13:44:54 +02:00
Alexander Chemeris
0c48fc7c62 abis: Consistent usage of LOGP/DEBUGP for "RSL CONNECT NACK" 2013-10-08 11:29:44 +02:00
Holger Hans Peter Freyther
caa98d51b6 osmo-bts: Kill the different ROLE_BSC as e1inp_sign_link is used now 2013-10-06 15:52:14 +02:00
Alexander Chemeris
bd6d40f1fb nitb: Add "subscriber create" VTY command.
It may be useful in production, but it's really required for
VTY testing of subscriber related commands.
2013-10-05 10:27:47 +02:00
Alexander Chemeris
4ad593c8f6 sms: Possiqble meamleak fix gsm340_rx_tpdu()
Slight clean up of the code in gsm340_rx_tpdu() and a fix for
an unlikely, but possible memory leak there.
2013-10-04 08:18:32 +02:00
Alexander Chemeris
a3d41c9124 Fix typo in console output: "PEROIDOC" -> "PERIODIC". 2013-10-04 08:18:14 +02:00
Alexander Chemeris
8c16928beb Fix typo ',' -> ';' at the end of a line.
Funny, this is a correct C expression and doesn't change execution, thus it
stayed unnoticed for quite a while.
2013-10-04 08:18:01 +02:00
Alexander Chemeris
86d46c5c7a Fix copy-paste error in console output in db_test. 2013-10-04 08:17:52 +02:00
Jacob Erlbeck
cc391b8880 bsc: Add control command to set timezone
This adds a per BTS control command 'timezone' which expects a value
of the format '<hours>,<mins>,<dst>' or 'off' to set the value of
bts->tz. It has the same functionality like the existing VTY command
'timezone' in network/bts.

Sponsored-by: On-Waves ehf
Ticket: OW#978
2013-10-01 17:25:44 +02:00
Holger Hans Peter Freyther
55e34a3325 smpp: Fix the make distcheck for smpp
DISTCHECK_CONFIGURE_FLAGS="--enable-smpp" make distcheck
2013-09-19 11:08:43 +02:00
Holger Hans Peter Freyther
cb78612689 nat: Fix make distcheck for the nat
The jenkins runs make distcheck in the default configuration and
not with the nat enabled.

DISTCHECK_CONFIGURE_FLAGS="--enable-nat" make distcheck
2013-09-19 11:01:14 +02:00
Jacob Erlbeck
946d1415c2 bsc/mminfo: Patch timezone and DST in MM Info messages
This adds in-place patching of the time information in the
MM INFORMATION message. The timezone in the 'Local time zone' and
the 'Universal time and local time zone' information elements
and the offset in the 'Network Daylight Saving Time' information
element are optionally set.

The new values are determined by the 'timezone' vty command in the
config_net_bts node. That command is extended by an optional
DST offset parameter.

Tests are provided for the vty part and for the plain
bsc_scan_msc_msg() function.

Sponsored-by: On-Waves ehf
Ticket: OW#978
2013-09-19 10:57:13 +02:00
Ivan Kluchnikov
6792059d50 bsc: Add vty command for setting Access control classes. 2013-09-18 16:14:44 +02:00
Jacob Erlbeck
4f13d03213 ctrl: Set a generic reply when it hasn'n been set
When verification failed and the reply string was not updated, the
message "Someone forgot to fill in the reply." was shown instead
of the default "Value failed verification." message.

This patch changes the default reply handling in ctrl_cmd_handle()
by setting the reply to NULL initially and then checking it at the
end. If it hasn't been set, a generic message is assigned and an
error is logged.
2013-09-16 14:07:20 +02:00
Jacob Erlbeck
0760a83910 ctrl: Add test script for the BSC control interface
This script is similar to vty_test_runner.py but tests the control
interface instead.

It currently tests some error cases, BTS status queries, and
setting/clearing rf_locked.
2013-09-16 14:03:43 +02:00
Holger Hans Peter Freyther
cd40fb4dea vty: Cosmetic change to the writing of the bts->model
Based on the feedback of Peter from the mailinglist, move the
writing code to a new method and return early if there is no
bts->model.
2013-09-16 14:03:43 +02:00
Jacob Erlbeck
779a72819d ctrl: Remember last 'rf_locked' control command
This stores the last SET rf_locked control command along with a
timestamp. The 'show network' vty command is extended to show
this information.

Ticket: OW#659
2013-09-11 20:27:08 +02:00
Jacob Erlbeck
733bec8626 vty: Hide unconfigured BTS on 'write'
This prevents the application from crashing when there is a half
configured BTS (e.g. by using the command 'bts 1' when there isn't
a BTS 1) and the 'write' command is used.
2013-09-11 20:20:33 +02:00
Jacob Erlbeck
56595f8647 ussd: Send USSD on call setup on MSC errors
Send an USSD message to the mobile station requesting a connection
for a call or a SMS when the link to the MSC is down or in the
grace period.

The messages can be set (and this feature activated) by setting
bsc/missing-msc-text resp. msc/bsc-grace-text via the vty.

The generation of both messages has been tested manually.

Ticket: OW#957
2013-09-11 20:18:42 +02:00
Holger Hans Peter Freyther
3ffd9bc0a4 bsc_msc: Fix possible null pointer dereference
In case the allocation of con is failing, do not attempt to
print con->name as this will be a null pointer dereference.

Fixes: Coverity CID 1076318
2013-09-04 08:45:48 +02:00
Holger Hans Peter Freyther
1b9902c128 nat: Remember the original dest local reference in the parsed struct
In case of the RLSD coming from the MSC we are patching the address
in-situ but for local calls set con = NULL. We then answered the RLSD
with the wrong reference and the MSC kept on trying.
2013-09-03 15:04:43 +02:00
Holger Hans Peter Freyther
ff98b3cffa nat: Fix the log message of the code in case of an allocation failure
This wrong log message appears to be the result of copy and paste
2013-09-03 15:04:31 +02:00
Holger Hans Peter Freyther
33eb5873d9 bsc_msc: Stop the re-connect timer in case the msc is lost
It was possible to cause a crash by enabling and disabling the
MSC connection. The enabling lead to scheduling a connection
and the second call was not stopping the timer.
2013-09-03 15:04:17 +02:00
Holger Hans Peter Freyther
c1a8687cb8 bsc_msc: Add a name field to the MSC Connection to differentiate links
Assign a static name to a MSC Connection and use it. In case there
are multiple connections we can now more easily identify them.

This is only used for the NAT right now, the BSC could start to
name the various MSC connections too.
2013-09-03 15:02:46 +02:00
Holger Hans Peter Freyther
0df1ab97a2 vty: Attempt to fix the build when SMPP is not enabled 2013-09-02 21:55:56 +02:00
Jacob Erlbeck
4c9dff5d8e vty: Rename 'mgcp-through-msc-ipa' command to 'use-msc-ipa-for-mgcp'
Currently the 'mgcp' command fails in the 'config-nat' node, because
it get confused with 'mgcp-through-msc-ipa' which is executed
instead because of the prefix based command selection. Thus the
latter command is renamed by this patch to avoid the common prefix.

The workaround in the test suite is removed.
2013-09-02 20:25:51 +02:00
Jacob Erlbeck
0ae92a950a vty: Use generic 'end' and 'exit' commands
Add bsc_install_default() and replace all install_default()

This patch adds bsc_install_default() which calls install_default()
and add 'exit' and 'end'. All other calls to install_default() are
replaced by calls to bsc_install_default().

Since 'exit' and 'end' are now added automatically to each node, the
explicit registrations of these commands are removed by this patch,
too.

The related tests succeed now without work-arounds (except for the
'config' node itself which is part of libosmocore).
2013-09-02 20:25:35 +02:00
Jacob Erlbeck
190acf6fd0 vty: Generalize ournode_exit() and ournode_end()
ournode_exit() duplicates most of bsc_vty_go_parent(). This patch
fixes the inconsistencies of both functions within
bsc_vty_go_parent() and replaces the implementation of
ournode_exit() by a call to it. This makes 'exit' behave exactly
like ^D in all openbsc nodes.

ournode_end() has been changed to walk through the intermediate
nodes until one of the top nodes is reached. This allows for
cleanups to be done on the way.

Note that in config mode if the tree is searched along the nodes
toward the config node and a command is not found this way, a
rollback is done by just replacing the vty's node and index member
variable by the saved old values which might break the whole thing, when
there has been a free() on the way.
2013-09-02 20:20:05 +02:00
Jacob Erlbeck
96903c4b2d vty: Add test to check vty node hierarchy and related commands
These tests check for the availability of 'exit' and 'end' in each
configuration node and for the node specific commands to traverse
the tree.
In addition, using these commands from within inner contexts is
checked. This will detect problems, when an outer command word is
a prefix of an inner command, like with 'mgcp' and
'mgcp-through-msc-ipa'.

Several assertions are disabled due to inconsistencies and missing
commands (see above).
2013-09-02 20:12:00 +02:00
Harald Welte
6a399efb72 SMPP: add missing VTY parameter 'deliver-src-imsi' for ESME
the parameter was already used in the code and saved from VTY code,
but somehow the functions for parsing it didn't make it into master.
2013-09-02 16:41:00 +02:00
Holger Hans Peter Freyther
6fcc3a9e8a nat: Attempt to follow the MODULE_METHOD pattern for methods
Rename methods to be like bsc_ussd_ACTION.
2013-09-02 11:11:16 +02:00
Holger Hans Peter Freyther
5741256703 nat: Use bsc_nat_msc_is_connected instead of accessing it directly 2013-09-02 11:00:09 +02:00
Holger Hans Peter Freyther
c85ed4e8db bsc: Fix compiler warning about undeclare functions
Addresses:
osmo_bsc_sccp.c:280:2: warning: implicit declaration of function ‘gsm0480_send_ussdNotify’ [-Wimplicit-function-declaration]
osmo_bsc_sccp.c:281:2: warning: implicit declaration of function ‘gsm0480_send_releaseComplete’ [-Wimplicit-function-declaration]
2013-09-02 10:58:35 +02:00
Holger Hans Peter Freyther
9303df22bd nanobts: Fix initialization of two concurrent BTS.
It was possible that the wrong NSEI information was sent to the
BTS. This is because patch_nm_tables is not called before sending
the data to the BTS. This will break when two BTS connect more or
less at the same time.

Stop using the arrays directly and instead introduce a method
that will patch the table and return the data and length. This
makes sure that all users patch the table before we send the
data to the BTS.

I bootstrapped a sysmoBTS and I can bring up rsl. The device is
running with a dummy load so I couldn't do more verification.
2013-09-02 10:20:14 +02:00
Jacob Erlbeck
0b4f1b9e75 vty: Fix BSC_NODE prompt string
Change '%s(bsc)#' to '%s(config-bsc)# '. The missing trailing blank
breaks osmopy's VTYInteract.command() because the blank is contained
in the end patterns which are checked to decide whether to leave the
select loop. Thus trying to execute the 'bsc' command there blocks
the test script forever.
2013-08-31 15:55:16 +02:00
Jacob Erlbeck
97e139f267 bsc/vty: Add 'no bsc-welcome-text' command
There was no command to reset a bsc-welcome-text string, so it has
been added.
2013-08-28 11:10:44 +02:00
Jacob Erlbeck
1b894022fd bsc/ussd: Optionally send USSD message on MSC disconnection
Send an USSD message on each MS connection if the connection to
the MSC has been lost.
Add a vty config command 'bsc-msc-loss-txt' in 'config-msc' to set
the notification string and to enable the feature.

Ticket: OW#957
2013-08-28 11:10:44 +02:00
Holger Hans Peter Freyther
0c0e1c308f nat: Add example bsc entry for pablo 2013-08-27 21:32:29 +02:00
Pablo Neira Ayuso
326b5d80b3 libmgcp: add enum mgcp_role
This enum indicates if the mgcp is running on the BSC or the BSC-NAT.
2013-08-27 12:21:43 +02:00
Pablo Neira Ayuso
d81fec021e libmgcp: attach mgcp_ prefix to udp_send
This patch is a cleanup.
2013-08-27 12:21:24 +02:00
Andreas Eversberg
a874b8d396 Fix: Handle CM service request on already secured channel correctly
Second part of the previous patch. Log an error message in case
we receive a location updating request on an already authenticated
channel.
2013-08-18 10:32:45 +02:00
Pablo Neira Ayuso
66b52c1df8 libmgcp: add mgcp prefix to functions and constants
Functions and constants that belong to the libmgcp scope are prefixed
with mgcp_ and MGCP_. This patch is a cleanup.
2013-08-14 16:20:37 +02:00
Jacob Erlbeck
6cb2cccc8d nat/ussd: Add 'show ussd-connection' vty command
This command returns the current state of the connection to the USSD
side channel provider. It shows whether a provider has been connected
and authorized or not.

Fixes: OW#953
2013-08-14 12:07:07 +02:00
Holger Hans Peter Freyther
27876a2df0 nat: Fix potential memory leak when reading a message
Spotted while going through the code with Jacob. We could have
leaked the msgb in case of error.
2013-08-13 14:48:44 +02:00
Holger Hans Peter Freyther
9962151230 nat: Misc changes spotted while going through the file with Jacob
* Spell Configure correctly
* Use %s and VTY_NEWLINE instead of \n
2013-08-13 11:36:33 +02:00
Holger Hans Peter Freyther
3db24b5fe4 Merge branch 'laforge/smpp-fixes'
These commits have been deployed by sysmocom and it should qualify
as some form of smoke testing. Let's see how things go from here.
The by IMSI alertion has not been used, the rest should have been
executed by the system.
2013-08-03 19:22:38 +02:00
Harald Welte
045f402298 SMPP: use VTY setting for E212/E164 in ALERT NOTIFICATION
There's a VTY option by which for every ESME the user can specify if the
E.212 or E.164 number should be used in DELIVER-SM.  The ALERT
notifications generate by subscriber LU have so far always contained the
E.212 (IMSI) rather than E.164 (MSISDN) which is a bit inconsistent.

Rather than copying code, we create a new function that implements
ALERTing all ESMEs.
2013-08-03 19:20:37 +02:00
Harald Welte
99e273db00 SMPP: convert a SMMA to a SMPP ALERT NOTIFICATION 2013-08-03 19:20:36 +02:00
Harald Welte
1aeb2af75d SMPP: don't get stuck in case of SMS memory exceeded
If the MS memory for SMS is exceeded and we get an RP-layer error, we
need to report that back to the (transaction-mode) ESME.  Otherwise the
ESME will wait forever after sending a SUBMIT-SM without ever receiving
a response to it.

Thanks to Holger for catching this.
2013-08-03 19:20:36 +02:00
Holger Hans Peter Freyther
14d1177735 Merge branch 'zecke/features/big-rewrite' 2013-07-31 16:41:22 +02:00
Holger Hans Peter Freyther
52f705eaab nat: Use the DCC region for number rewriting and increase debug output 2013-07-31 16:36:40 +02:00
Holger Hans Peter Freyther
67e423c256 nat: Implement a post-routing for the NAT software
* The post-routing is applied after the first re-writing. To do this
  the new number is copied back into the called data structure.

* Add a testcase that goes from 0172 to 0049 and then back to 0049
  using the post rule with a table lookup.
2013-07-31 16:36:40 +02:00
Holger Hans Peter Freyther
3615a30d3d nat: Fix some memory leaks in the testcases.
The test cases did not free some of the resources it allocated.
Improve the situation a bit. There is still data allocated that
is not freed at exit.
2013-07-31 16:36:40 +02:00
Holger Hans Peter Freyther
ddf191eafc nat: Allow to use the prefix lookup to rewrite numbers
* Increase the rewritten rule to five digits (this is the easiest
  for the unit test). This will add another 40kb to the runtime size.

* Create a unit test that tests adding and removing the prefix rules.

* Use the regexp match to replace from one package
2013-07-31 16:36:40 +02:00
Holger Hans Peter Freyther
85d3b34ed2 nat: Introduce a prefix lookup tree (trie) for number rewriting
* It is a trie. The max depth of the trie is the length of the
longest prefix. The lookup is O(lookuped_prefix), but as the prefix
length is limited, the lookup time is constant.

* Each node can hold the entire prefix, has place for the rewrite
  rule with up to three digits.

* A trie with 20k entries will take about 3MB ram.

* Filling the trie 100 times takes ~800ms on my i7 laptop

* 10.000.000 lookups take 315ms.. (for the same prefix).

* 93/99 lines are tested, 6/6 functions are tested, 49 of 54 branches
  are tested. Only memory allocation failures are not covered

* A late addition is to handle the '+' sign and to increase the number
  of chars in the rewrite prefix. The timing/line coverage has not
  been updated after this change.
2013-07-31 16:36:40 +02:00
Holger Hans Peter Freyther
b718ad397e nat: Add a no number-rewrite command and call it through a VTY test
The test is just testing the invocation but does not verify that
the side effect of this call. It is good enought for now.
2013-07-31 16:36:13 +02:00
Holger Hans Peter Freyther
aa93bac34b gprs_gmm: Avoid assertion in the sending code during routing area update
Use old and new tlli as specified by the caller.

WIP

<000f> sgsn_libgtp.c:321 Received DELETE PDP CTX CONF, cause=128(Request accepted)
<0013> gprs_sndcp.c:320 SNSM-DEACTIVATE.ind (lle=0x8095d08, TLLI=e3ddd574, SAPI=11, NSAPI=5)
<0011> gprs_bssgp.c:376 BSSGP TLLI=0xe3ddd574 Rx UPLINK-UNITDATA
<0012> gprs_llc.c:551 LLC SAPI=1 C   FCS=0xb85a96CMD=UI DATA
<0011> gprs_bssgp.c:376 BSSGP TLLI=0xe3ddd574 Rx UPLINK-UNITDATA
<0012> gprs_llc.c:551 LLC SAPI=1 C   FCS=0xbe5a96CMD=UI DATA
<0002> gprs_gmm.c:214 Starting MM timer 3350 while old timer 3350 pending
<0012> gprs_llc.c:417 LLC TX: unknown TLLI 0xe3ddd574, creating LLME on the fly
Assert failed msgb_tlli(msg) == mmctx->llme->tlli || msgb_tlli(msg) == mmctx->llme->old_tlli || tlli_foreign2local(msgb_tlli(msg)) == mmctx->llme->tlli || tlli_foreign2local(msgb_tlli(msg)) == mmctx->llme->old_tlli gprs_llc.c:123
backtrace() returned 18 addresses
/home/ich/install/openbsc/lib/libosmocore.so.4(osmo_generate_backtrace+0x16) [0xb7bb6a36]
/home/ich/source/gsm/openbsc/openbsc/src/gprs/osmo-sgsn() [0x805224a]
/home/ich/source/gsm/openbsc/openbsc/src/gprs/osmo-sgsn() [0x804a2f6]
/home/ich/source/gsm/openbsc/openbsc/src/gprs/osmo-sgsn() [0x804b687]
/home/ich/source/gsm/openbsc/openbsc/src/gprs/osmo-sgsn() [0x804bc35]
/home/ich/source/gsm/openbsc/openbsc/src/gprs/osmo-sgsn() [0x804bd4e]
/home/ich/source/gsm/openbsc/openbsc/src/gprs/osmo-sgsn() [0x804d20c]
/home/ich/source/gsm/openbsc/openbsc/src/gprs/osmo-sgsn() [0x8052be4]
/home/ich/source/gsm/openbsc/openbsc/src/gprs/osmo-sgsn(bssgp_prim_cb+0x55) [0x804f5a4]
/home/ich/install/openbsc/lib/libosmogb.so.2(bssgp_rcvmsg+0x3b8) [0xb7b626b8]
/home/ich/source/gsm/openbsc/openbsc/src/gprs/osmo-sgsn() [0x804f4f1]
/home/ich/install/openbsc/lib/libosmogb.so.2(gprs_ns_rcvmsg+0x8c7) [0xb7b5ecf7]
/home/ich/install/openbsc/lib/libosmogb.so.2(+0x4311) [0xb7b5f311]
/home/ich/install/openbsc/lib/libosmocore.so.4(osmo_select_main+0x192) [0xb7bb2ed2]
/home/ich/source/gsm/openbsc/openbsc/src/gprs/osmo-sgsn() [0x804fbcd]
/lib/i386-linux-gnu/i686/cmov/libc.so.6(__libc_start_main+0xf5) [0xb796a8f5]
/home/ich/source/gsm/openbsc/openbsc/src/gprs/osmo-sgsn() [0x8049db1]

Program received signal SIGABRT, Aborted.
0xb7fde424 in __kernel_vsyscall ()
(gdb) bt
 #0  0xb7fde424 in __kernel_vsyscall ()
 #1  0xb797f83f in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
 #2  0xb7982cf3 in __GI_abort () at abort.c:90
 #3  0x0805224f in _bssgp_tx_dl_ud (mmctx=0x80932d0, msg=0x80963a8) at gprs_llc.c:120
 #4  gprs_llc_tx_ui (msg=0x80963a8, sapi=1 '\001', command=0, mmctx=0x80932d0)
    at gprs_llc.c:496
 #5  0x0804a2f6 in gsm48_gmm_sendmsg (msg=0x80963a8, command=0, mm=0x80932d0) at gprs_gmm.c:241
 #6  0x0804b687 in gsm48_tx_gmm_ra_upd_ack (mm=0x80932d0) at gprs_gmm.c:851
 #7  0x0804bc35 in gsm48_rx_gmm_ra_upd_req (mmctx=0x80932d0, msg=0x8091ce8, llme=0x8095630)
    at gprs_gmm.c:1004
 #8  0x0804bd4e in gsm0408_rcv_gmm (mmctx=0x80932d0, msg=0x8091ce8, llme=0x8095630)
    at gprs_gmm.c:1036
 #9  0x0804d20c in gsm0408_gprs_rcvmsg (msg=msg@entry=0x8091ce8, llme=0x8095630)
    at gprs_gmm.c:1566
 #10 0x08052be4 in gprs_llc_rcvmsg (msg=0x8091ce8, tv=0xbfffdcb0) at gprs_llc.c:882
 #11 0x0804f5a4 in bssgp_prim_cb (oph=oph@entry=0xbfffdc8c, ctx=ctx@entry=0x0)
    at sgsn_main.c:114
 #12 0xb7b626b8 in bssgp_rx_ul_ud (tp=0xbfffdcb0, msg=0x8091ce8, ctx=<optimized out>)
    at gprs_bssgp.c:398
 #13 bssgp_rx_ptp (bctx=0x8091a08, tp=0xbfffdcb0, msg=0x8091ce8) at gprs_bssgp.c:820
 #14 bssgp_rcvmsg (msg=0x8091ce8) at gprs_bssgp.c:1016
 #15 0x0804f4f1 in sgsn_ns_cb (event=GPRS_NS_EVT_UNIT_DATA, nsvc=0x8090740, msg=0x8091ce8,
    bvci=1801) at sgsn_main.c:92
 #16 0xb7b5ecf7 in gprs_ns_rx_unitdata (msg=0x8091ce8, nsvc=0x8090740) at gprs_ns.c:616
 #17 gprs_ns_rcvmsg (nsi=nsi@entry=0x807fd38, msg=msg@entry=0x8091ce8,
    saddr=saddr@entry=0xbfffedc0, ll=ll@entry=GPRS_NS_LL_UDP) at gprs_ns.c:841
 #18 0xb7b5f311 in handle_nsip_read (bfd=0x807fd58) at gprs_ns.c:991
 #19 nsip_fd_cb (bfd=0x807fd58, what=1) at gprs_ns.c:1024
 #20 0xb7bb2ed2 in osmo_select_main (polling=0) at select.c:158
 #21 0x0804fbcd in main (argc=3, argv=0xbffff234) at sgsn_main.c:369
(gdb) frame 5
 #5  0x0804a2f6 in gsm48_gmm_sendmsg (msg=0x80963a8, command=0, mm=0x80932d0) at gprs_gmm.c:241
241		return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command, mm);
(gdb) p msgb_tlli(msg)
$1 = 3822966132
(gdb) frame 4
 #4  gprs_llc_tx_ui (msg=0x80963a8, sapi=1 '\001', command=0, mmctx=0x80932d0)
    at gprs_llc.c:496
496		return _bssgp_tx_dl_ud(msg, mmctx);
(gdb) p mmctx
$2 = (void *) 0x80932d0
(gdb) frame 3
 #3  0x0805224f in _bssgp_tx_dl_ud (mmctx=0x80932d0, msg=0x80963a8) at gprs_llc.c:120
120			OSMO_ASSERT(msgb_tlli(msg) == mmctx->llme->tlli
(gdb) p mmctx
$3 = (struct sgsn_mm_ctx *) 0x80932d0
(gdb) p *mmctx
$4 = {list = {next = 0x8092e28, prev = 0x805c318 <sgsn_mm_ctxts>},
  imsi = "901700000003094\000", mm_state = GMM_REGISTERED_NORMAL, p_tmsi = 296043751,
  p_tmsi_old = 2075232571, p_tmsi_sig = 0, imei = "353943044782210\000",
  msisdn = '\000' <repeats 14 times>, ra = {mnc = 70, mcc = 901, lac = 1, rac = 0 '\000'},
  cell_id = 0, cell_id_age = 0, sac = 0, sac_age = 0, new_sgsn_addr = 0,
  ciph_algo = GPRS_ALGO_GEA0, ms_radio_access_capa = {len = 11 '\v',
    buf = "4\307\003*\240B|\255\341\030\v", '\000' <repeats 38 times>}, ms_network_capa = {
    len = 2 '\002', buf = "\345\200\000\000\000\000\000"}, drx_parms = 3329, mnrg = 0,
  ngaf = 0, ppf = 0, recovery = 0, radio_prio_sms = 0 '\000', pdp_list = {next = 0x8093390,
    prev = 0x8093390}, llme = 0x8095630, tlli = 3822966132, tlli_new = 3517269223,
  nsei = 1801, bvci = 1801, ctrg = 0x8096048, timer = {node = {rb_parent_color = 3082574944,
      rb_right = 0x0, rb_left = 0x0}, list = {next = 0x80933b8, prev = 0x80933b8}, timeout = {
      tv_sec = 1375260414, tv_usec = 864196}, active = 1, cb = 0x804bfd0 <mmctx_timer_cb>,
    data = 0x80932d0}, T = 3350, num_T_exp = 0, t3350_mode = GMM_T3350_MODE_RAU,
  t3370_id_type = 1 '\001'}
(gdb) p msgb_tlli(msg)
No symbol "msgb_tlli" in current context.
(gdb) frame 5
 #5  0x0804a2f6 in gsm48_gmm_sendmsg (msg=0x80963a8, command=0, mm=0x80932d0) at gprs_gmm.c:241
241		return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command, mm);
(gdb) frame 6
 #6  0x0804b687 in gsm48_tx_gmm_ra_upd_ack (mm=0x80932d0) at gprs_gmm.c:851
851		return gsm48_gmm_sendmsg(msg, 0, mm);
(gdb) p msgb_tlli(msg)
$5 = 3822966132
(gdb) p mmctx->tlli
No symbol "mmctx" in current context.
(gdb) p mm->tlli
$6 = 3822966132
(gdb) p mm->tlli_new
$7 = 3517269223
(gdb) p mm->llme->tlli
$8 = 3517269223
(gdb) p mm->llme->tlli_old
There is no member named tlli_old.
(gdb) p mm->llme->old_tlli
$9 = 4222716219
(gdb) bt
 #0  0xb7fde424 in __kernel_vsyscall ()
 #1  0xb797f83f in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
 #2  0xb7982cf3 in __GI_abort () at abort.c:90
 #3  0x0805224f in _bssgp_tx_dl_ud (mmctx=0x80932d0, msg=0x80963a8) at gprs_llc.c:120
 #4  gprs_llc_tx_ui (msg=0x80963a8, sapi=1 '\001', command=0, mmctx=0x80932d0)
    at gprs_llc.c:496
 #5  0x0804a2f6 in gsm48_gmm_sendmsg (msg=0x80963a8, command=0, mm=0x80932d0) at gprs_gmm.c:241
 #6  0x0804b687 in gsm48_tx_gmm_ra_upd_ack (mm=0x80932d0) at gprs_gmm.c:851
 #7  0x0804bc35 in gsm48_rx_gmm_ra_upd_req (mmctx=0x80932d0, msg=0x8091ce8, llme=0x8095630)
    at gprs_gmm.c:1004
 #8  0x0804bd4e in gsm0408_rcv_gmm (mmctx=0x80932d0, msg=0x8091ce8, llme=0x8095630)
    at gprs_gmm.c:1036
 #9  0x0804d20c in gsm0408_gprs_rcvmsg (msg=msg@entry=0x8091ce8, llme=0x8095630)
    at gprs_gmm.c:1566
 #10 0x08052be4 in gprs_llc_rcvmsg (msg=0x8091ce8, tv=0xbfffdcb0) at gprs_llc.c:882
 #11 0x0804f5a4 in bssgp_prim_cb (oph=oph@entry=0xbfffdc8c, ctx=ctx@entry=0x0)
    at sgsn_main.c:114
 #12 0xb7b626b8 in bssgp_rx_ul_ud (tp=0xbfffdcb0, msg=0x8091ce8, ctx=<optimized out>)
    at gprs_bssgp.c:398
 #13 bssgp_rx_ptp (bctx=0x8091a08, tp=0xbfffdcb0, msg=0x8091ce8) at gprs_bssgp.c:820
 #14 bssgp_rcvmsg (msg=0x8091ce8) at gprs_bssgp.c:1016
 #15 0x0804f4f1 in sgsn_ns_cb (event=GPRS_NS_EVT_UNIT_DATA, nsvc=0x8090740, msg=0x8091ce8,
    bvci=1801) at sgsn_main.c:92
 #16 0xb7b5ecf7 in gprs_ns_rx_unitdata (msg=0x8091ce8, nsvc=0x8090740) at gprs_ns.c:616
 #17 gprs_ns_rcvmsg (nsi=nsi@entry=0x807fd38, msg=msg@entry=0x8091ce8,
    saddr=saddr@entry=0xbfffedc0, ll=ll@entry=GPRS_NS_LL_UDP) at gprs_ns.c:841
 #18 0xb7b5f311 in handle_nsip_read (bfd=0x807fd58) at gprs_ns.c:991
 #19 nsip_fd_cb (bfd=0x807fd58, what=1) at gprs_ns.c:1024
 #20 0xb7bb2ed2 in osmo_select_main (polling=0) at select.c:158
 #21 0x0804fbcd in main (argc=3, argv=0xbffff234) at sgsn_main.c:369
(gdb) frame 3
 #3  0x0805224f in _bssgp_tx_dl_ud (mmctx=0x80932d0, msg=0x80963a8) at gprs_llc.c:120
120			OSMO_ASSERT(msgb_tlli(msg) == mmctx->llme->tlli
(gdb) p msgb_tlli(msg)
No symbol "msgb_tlli" in current context.
(gdb) frame 4
 #4  gprs_llc_tx_ui (msg=0x80963a8, sapi=1 '\001', command=0, mmctx=0x80932d0)
    at gprs_llc.c:496
496		return _bssgp_tx_dl_ud(msg, mmctx);
(gdb) p msgb_tlli(msg)
No symbol "msgb_tlli" in current context.
(gdb) frame 5
 #5  0x0804a2f6 in gsm48_gmm_sendmsg (msg=0x80963a8, command=0, mm=0x80932d0) at gprs_gmm.c:241
241		return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command, mm);
(gdb) p msgb_tlli(msg)
$10 = 3822966132
(gdb) p mm->tlli
$11 = 3822966132
(gdb) p mm->tlli_new
$12 = 3517269223
(gdb) p mm->tlli_new
$13 = 3517269223
(gdb) p mm->llme->tlli
$14 = 3517269223
(gdb) p mm->llme->tlli_old
There is no member named tlli_old.
(gdb) p mm->llme->old_tlli
$15 = 4222716219
(gdb) p mm->llme->state
$16 = GPRS_LLMS_ASSIGNED
(gdb) q
2013-07-31 16:12:02 +02:00
Holger Hans Peter Freyther
7e0fec17ce gprs_llc: Assert that we send frames with either tlli or old_tlli
In case we have access to the context verify that the selected
msgb_tlli is either the old_tlli or the tlli in either local or
foreign format. It is wrong to use any other TLLI.
2013-07-31 14:57:21 +02:00
Holger Hans Peter Freyther
964a9b3e20 gprs_llc: Work on finding the right LLE/LLME in case of routing area update
Attempt to solve what f0901f0067 tried to
solve without breaking the case of someone with a foreign TLLI from a
different network.

Lookup with the foreign TLLI converted to a local one in case we did
not find the TLLI and only then create a LLE/LLME on the fly for the
RX path.
2013-07-31 14:57:21 +02:00
Holger Hans Peter Freyther
012a7eec29 gprs_llc: Lookup lle based on the real TLLI
During the GPRS Attach procedure we might have a foreign tlli and
in the RX create a LLME on the fly for this tlli. The GMM GPRS
Attach handling code will then assign a new TLLI and keep the
foreign tlli as the llme->old_tlli.

When the GMM is sending the identity request the msgb_tlli will
point to the foreign tlli. The GPRS LLC code will then try to find
that foreign tlli but due the conversion this will not be found.
Instead a new ad-hoc LLE/LLME will be created on the fly for
each message (this means there are duplicate LLE/LLMEs in the
list).

Make the code more strict and remove the tlli_foreign2local change
from the look-up routine. This will make the GPRS LLC code find
the right LLE/LLME and the N(U) will be handled correctly.

This partially reverts:
  f0901f0067

Addresses:
  <0012> gprs_llc.c:773 LLC RX: unknown TLLI 0xadf11820, creating LLME on the fly
  ...
  <0012> gprs_llc.c:357 LLC TX: unknown TLLI 0xedf11820, creating LLME on the fly

Reproducable:
  Use pcu_emu (gprs attach) and observe with wireshark.
2013-07-31 14:57:21 +02:00
Holger Hans Peter Freyther
598e7b3cdf gprs_sgsn: In case of a Activate PDP Context timeout we should free pdp
In case of a failure this method didn't set the pctx->lib back to
NULL. In case of a timeout the callback will be made with pdp=NULL
and this would lead to leaking the PDP context. Check for the case
of having a pctx->lib != pdp and free it.

This resolves:
<000f> gprs_sgsn.c:259 freeing PDP context that still has a libgtp handle attached to it, this shouldn't happen!
2013-07-31 14:57:21 +02:00
Holger Hans Peter Freyther
92aa6bb9dc gprs: Fix a typo in the comment 2013-07-28 20:13:01 +02:00
Holger Hans Peter Freyther
c0438e3587 tests: TestCase.assertGreater is not available on Python 2.5
The jenkins build node has Python 2.5.X installed and the
assertGreater method is not available. Use assert_ until
we can use newer versions of Python.
2013-07-27 22:23:25 +02:00
Holger Hans Peter Freyther
c63f6f1f32 expiration: Allow to disable the periodic location updating procedure
Disable the periodic LU using "no periodic location update" VTY
command. In that case set the expire_lu to 0 which will then be
translated to a NULL in the database layer. This leads to a bit of
copy and paste in the db_sync_subscriber method but I don't see
how we could easily use 'datetime(%i, 'unixepoch')' and 'NULL'
at the same time.

Change the query to find expired queries to check for NOT NULL
and the time being in the past. This means if there are still
old subscribers in the database they might not be expired. One
would need to execute a query like "UPATE Subscriber SET expire_lu
= 0 WHERE expire_lu is null". The same applies when disabling the
periodic LU. One would need to update the database by hand.

Manual tests executed/passed:

1.) periodic LU enabled:

  * use gst LUTest.st to do a LU
  * UPDATE Subscriber SET expire_lu=datetime('now');
  * observe the subscriber being expired (it was)

2.) periodic LU disabled:

  * use gst LUTest.st to do a LU
  * verify that the expire_lu is NULL in the database
2013-07-27 22:02:24 +02:00
Holger Hans Peter Freyther
e7bd863f76 expiration: Speculative fixes for the periodic expiring handling
We were expiring subscribers during active calls. This is because
the T3212 is stopped under certain conditions but we didn't stop
that timer at all.

Remember if T3212 timer was stopped due something done by NITB and
update the expiration time at the end of the radio connection, as
the phone should restart it when returning to MM Idle.

It is a bit difficult to decide when we should set the flag. E.g.
in a CM Service Request we don't know if we accept the service and
during a LU we already send MM messages before we accept or reject
the subscriber.

The easiest is to set the flag when receiving a paging response
on known subscribers and at the end of the authentication process.

Do not expire a subscriber that has an active connection that is
marked with the flag, e.g. we would still expire a subscriber that
is being paged.

Manual tests executed/passed:

 * gst LUTest.st verified that a expiration date was set
 * gst SMSTest.st (doing another LU but forcing a timeout on the
   SMS sending). Verified that the expire_lu was updated.
2013-07-27 21:39:13 +02:00
Holger Hans Peter Freyther
b97089432f expiration: Print the "expire_lu" time in show subscriber
This can help with debugging subscriber expiration issues.
2013-07-27 20:03:11 +02:00
Holger Hans Peter Freyther
a7328a5642 smpp: Move the coding/mode detection into a utils file
Make sure to not ever have issues with this code again, move the
utility code to a new file and create a basic testcase. The method
currently has 100% line and branch coverage. My initial patched
missed the smpp_utils.c file and I re-did the copying (and verifying
the branch coverage)
2013-07-27 20:03:10 +02:00
Holger Hans Peter Freyther
5ecbc93656 misc: Fix compilation warnings
bsc_api.c:417:3: warning: format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 7 has type ‘unsigned int’ [-Wformat]
bsc_api.c: In function ‘handle_ass_fail’:
bsc_api.c:458:3: warning: format ‘%lu’ expects argument of type ‘long unsigned int’, but argument 7 has type ‘unsigned int’ [-Wformat]

db.c: In function ‘db_sync_subscriber’:
db.c:785:3: warning: format ‘%i’ expects argument of type ‘int’, but argument 8 has type ‘time_t’ [-Wformat]

osmo_msc.c: In function ‘msc_release_connection’:
osmo_msc.c:145:20: warning: unused variable ‘trans’ [-Wunused-variable]

smpp_smsc.c: In function ‘link_accept_cb’:
smpp_smsc.c:891:24: warning: assignment from incompatible pointer type [enabled by default]

smpp_smsc.c:271:1: warning: ‘esme_by_system_id’ defined but not used [-Wunused-function]

smpp_openbsc.c: In function ‘smpp_openbsc_init’:
smpp_openbsc.c:545:2: warning: implicit declaration of function ‘smpp_vty_init’ [-Wimplicit-function-declaration]

osmo_bsc_ctrl.c: In function ‘verify_bts_loc’:
osmo_bsc_ctrl.c:340:19: warning: variable ‘height’ set but not used [-Wunused-but-set-variable

smpp_mirror.c: In function ‘main’:
smpp_mirror.c:297:2: warning: implicit declaration of function ‘osmo_init_logging’ [-Wimplicit-function-declaration]
2013-07-27 20:03:08 +02:00
Harald Welte
649e1ff4b3 sgsn: spelling fixes inside comments 2013-07-21 17:41:46 +08:00
Harald Welte
b4b21f59f6 SMPP: complete the VTY help/documentation
As discovered by osmotestconfig.py, a number of SMPP related VTY
commands were missing their help/documentation text.
2013-07-21 16:00:28 +08:00
Harald Welte
badb12f6a6 remove 'bind early' from osmo-bsc_mgcp example config
(discovered by osmotestconfig.py)
2013-07-21 15:52:40 +08:00
Harald Welte
3dfb549a6f sgsn: Add "auth-policy" VTY command to enable/disable ACL 2013-07-21 15:44:28 +08:00
Harald Welte
7f6da485f5 sgsn: add a minimalistic ACL
This adds a minimalistic ACL by which certain, individual roaming IMSIs
can be authorized to use the SGSN.  So you can selectively bypass the
'MCC+MNC == first 5 digits of IMSI' checking for a couple of IMSIs
2013-07-21 15:44:24 +08:00
Holger Hans Peter Freyther
cb5353d851 oml: Add a missing break switch for NM_OC_BS11
It appears to me that for NM_OC_BS11 mo was either NULL or the
one mo value from NM_OC_BS11_RACK. The break inside the nested
switch case didn't break from the outer one.

Fixes Coverity: CID 1040728
2013-07-18 12:03:31 +02:00
Holger Hans Peter Freyther
1b624ba1f6 smpp: Close the file descriptor when we can't accept the SMSC conn
When we failed to allocate the memory or failed to register the
fd we would have leaked the file descriptor. Close the fd and
avoid the leak.
2013-07-14 09:04:51 +02:00
Holger Hans Peter Freyther
c962d45669 smpp: Add the classic check for osmo_fd_register
In case the osmo_fd_register will fail we will need to free the
memory we have allocated.

Fixes: Coverity CID 1042375
2013-07-14 09:04:51 +02:00
Holger Hans Peter Freyther
921b2278df smpp: Fix possible NULL dereference of the emse->acl
The esme->acl is treated like it can be NULL in other places
of the code. Assume it can be NULL during this check as well.

Dereference after null check (FORWARD_NULL)
9. var_deref_op: Dereferencing null pointer "esme->acl".

Fixes: Coverity CID 1042374
2013-07-14 09:04:51 +02:00
Holger Hans Peter Freyther
ae9d8d3131 smpp: Checking an array for NULL will always be false
The if (submit->short_message) and if (smsc->system_id) will
always be true.

Fixes: Coverity CID 1042371, CID 1042372
2013-07-14 09:04:50 +02:00
Holger Hans Peter Freyther
c9251fa8c9 ipaccess: The proxy code checked the array but not the element
Array compared against 0 (NO_EFFECT)
array_null: Comparing an array to null is not useful: "ipbc->bsc_rsl_conn".

Fixes: Coverity CID 1040718
2013-07-14 09:04:50 +02:00
Holger Hans Peter Freyther
3aedba66bd ipaccess: Fix a resource leak in case the stat is failing
Close the file when the stat is failing.

Fixes: Coverity CID 1040711
2013-07-14 09:04:50 +02:00
Holger Hans Peter Freyther
5ccd015371 nitb: The subscr->imsi is an array will never be NULL
Array compared against 0 (NO_EFFECT)
array_null: Comparing an array to null is not useful: "subscr->imsi"

Fixes: Coverity CID 1040716
2013-07-14 09:04:50 +02:00
Harald Welte
995ff35f39 Fix license header at smpp_openbsc.c and smpp_smsc.c
As Holger pointed out, they contained a GPLv2+ disclaimer rather than
the AGPLv3+ which we use for OpenBSC.  This is not an incompaibility,
but was done unintentionally.  The code was always mean to be under
AGPLv3+.

Nevertheless, anyone using those two files in a version up to this
commit have the right to use it under GPLv2+ as well.  This is not
applicable for any versions after this commit.
2013-07-13 16:35:32 +02:00
Harald Welte
4c5babc06c smpp_openbsc: Fix parsing of 03.38 data coding scheme in MO case 2013-07-11 14:29:31 +02:00
Andreas Eversberg
641475cb81 Fix: Handle CM service request on already secured channel correctly
A CM service request must be acknowledged also, when encryption is already
enabled.

Without encryption enabled, the security status is GSM_SECURITY_NOTAVAIL,
which causes a CM service acknowledge. On initial CM service request, the
security status is GSM_SECURITY_SUCCEED, if encryption is enabled. This
will not lead to an acknowledge, because the cyphering command implies an
acknowlege. An additional CM service request requires an acknowledge, so
I added a new security status: GSM_SECURITY_ALREADY
2013-07-11 08:27:26 +02:00
Pablo Neira Ayuso
46bd4244a1 libmgcp: add enum mgcp_type and use it
This patch replaces the field 'is_transcoded' in the mgcp_endpoint
structure by the enum mgcp_type, that can be further extended with
new types.
2013-07-08 16:46:06 +02:00
Holger Hans Peter Freyther
1e61b25661 mncc: Remove what we believe to be a tautology from the MNCC code
Coverity pointed out that we use trans->subscr after a NULL check,
it is our believe that every transaction will have a subscriber.
Remove the check and add an assert before we are dispatching things.

Fixes: Coverity CID 1040740, CID 1040739
2013-07-06 11:45:38 +02:00
Holger Hans Peter Freyther
096dc3a466 nat: The con variable is not assigned at this point
Coverity pointed out that this code is logically dead. Quickly
judging the code we will forward the RSLD message anyway. Remove
the code for now and next time I work on the NAT/USSD bridge I
will have a look at the flow of the RLSD messages.

Fixes: Coverity CID 1042327
2013-07-05 08:22:03 +02:00
Holger Hans Peter Freyther
7346081ba3 nat: number could point to an address on the stack that can be reused
The number = int_number assignment will make the number point to
the stack and as the int_number goes out of scope at the end of
the if statement other code could re-use this stack for other memory.

Fixes: Coverity CID 1042325
2013-07-05 07:50:30 +02:00
Holger Hans Peter Freyther
9bec10ecd3 nat: Address coverity warning about uninitialized addr
Use memset on the addr to initialize the entire structure.

Fixes: Coverity CID 1042324
2013-07-05 07:48:04 +02:00
Holger Hans Peter Freyther
b0b8a34dd5 nat: Please coverity and initialize the saveptr to NULL
Coverity complains about the saveptr used in the strtok_r. This
is not a bug because we pass a string as part of the first call
to strtok_r but it is easier to just initialize it.

Addresses: Coverity CID 1042323
2013-07-05 07:45:08 +02:00
Holger Hans Peter Freyther
9feef48eaf nitb: Add a missing NULL check for searching the subscriber
"subscriber " SUBSCR_TYPES " ID sms pending-send

could fail with an invalid ID/IMSI for the subscriber.

Fixes: Coverity CID 1040715
2013-07-04 20:34:46 +02:00
Holger Hans Peter Freyther
e885951f27 db: Fix an issue with the memset
We want to memset the entire area of the atuple and not just the
first four/eight bytes of the data.

Fixes: Coverity CID 1040708
2013-07-04 20:24:02 +02:00
Holger Hans Peter Freyther
81cff91ec0 gsm_subscriber: Fix compiler warning of the printf string
This fixes both a GCC and a Coverity warning:

GCC:
gsm_subscriber.c: In function ‘subscr_expire_callback’:
gsm_subscriber.c:389:2: warning: format ‘%i’ expects argument of type ‘int’, but argument 8 has type ‘long long unsigned int’ [-Wformat]

Coverity:
CID 1040712
2013-07-04 20:22:27 +02:00
Holger Hans Peter Freyther
7b76934f03 nat: The second call didn't really add anything to the test.
Avoid: Coverity CID 1042323
2013-07-04 20:19:44 +02:00
Holger Hans Peter Freyther
b18c7456cb ipaccess-config: Add missing break to parsing the -L option
Fixes: Coverity CID 1040738
2013-07-04 18:51:07 +02:00
Holger Hans Peter Freyther
7d8139a42e ipaccess-config: Fix a resource leak in an error path
Fixes: Coverity CID 1040710, CID 1040711
2013-07-04 18:49:04 +02:00
Holger Hans Peter Freyther
aa63d70f39 sgsn: Fix the unimplemented/uninstalled show ggsn command
This is fixing a GCC and Coverity warning.

GCC:
sgsn_vty.c: At top level:
sgsn_vty.c:308:1: warning: ‘show_ggsn_cmd’ defined but not used [-Wunused-variable]

Coverity: CID 1040727
2013-07-04 18:45:31 +02:00
Holger Hans Peter Freyther
80e036560d sgsn_vty: Fix uninitialized variable in the gprs_apn2str method
This is fixing a GCC and Coverity warning:

GCC:
sgsn_vty.c: In function ‘vty_dump_pdp’:
sgsn_vty.c:64:5: warning: ‘i’ may be used uninitialized in this function [-Wmaybe-uninitialized]
sgsn_vty.c:49:15: note: ‘i’ was declared here

Coverity: CID 1040706
2013-07-04 18:44:16 +02:00
Holger Hans Peter Freyther
3a708afe63 sgsn: Fix logically dead code in regard to the osmo_fd_register
The code was written like checking the return value of the
osmo_fd_register but the rc variable was not assigned for the
subsequent calls.

Fixes: Coverity CID 1040741
2013-07-04 18:39:52 +02:00
Alexander Chemeris
84402c0c82 sgsn: Fix lengths of MS Network Capability and MS Radio Access Capability elements.
Original code was inconsistent about lengths and could lead to out
of bounds write. Lengths were also inconsistent with the TS 24.008.

Fixes: Coverity CID 1040714.
2013-07-04 18:34:49 +02:00
Holger Hans Peter Freyther
f0167ddfc2 hsl: Remove the support for the HSL bts from OpenBSC
The support has been implemented for an old model, we were told that
newer versions would be made incompatible with OpenBSC. Ther are
various warnings in the code and coverity has found some new ones.

Just remove the code as we don't know of anyone using this code.
2013-07-03 16:19:41 +02:00
Holger Hans Peter Freyther
a164d5291e nat: Fix compiler warning and cast uint16_t to uint8_t 2013-07-03 16:18:37 +02:00
Holger Hans Peter Freyther
1eba7de0c2 mgcp: Make sure the save pointer is initialized with NULL.
Coverity is not happy about it but it doesn't appear to be a real
issue as the data will not be NULL on the first call.

Addresses: Coverity CID 1040704
2013-07-03 10:23:35 +02:00
Holger Hans Peter Freyther
d5c270e71c ipaccess-find: Address a warning by coverity of unitialized memory
Use a memset on the sockaddr_in to make coverity happy.

Fixes: CID 1040705
2013-07-03 10:19:37 +02:00
Holger Hans Peter Freyther
8690b98e7c isdnsync: Remove a double close of the isdn device
The fd is already closed above the if statement and Coverity
detected this as a double close.

Fixes: Coverity CID 1040703
2013-07-03 10:17:37 +02:00
Holger Hans Peter Freyther
8bb0720ebb nanobts: Do not crash on an invalid TRX number
In case the specified trx number is not configured, do not crash
but return NULL from the function. The libosmo-abis library should
close the connection for us then.
2013-06-30 20:11:46 +02:00
Holger Hans Peter Freyther
eb0acb6e02 tests: Add a custom test runner to test the VTY functionality.
Begin with the NAT code. It is not clear yet if we will have one
file with all the tests or will have a sub directory with *.py files.
In the long run the base class will move to the osmo-python-tests
module.
2013-06-24 16:13:55 +02:00
Holger Hans Peter Freyther
9e22e69266 misc: Ignore compiled python code and another test case 2013-06-24 14:04:55 +02:00
Katerina Barone-Adesi
e0aee7aaa9 Introduced support for external python tests
The test scripts warn about missing documentation, untested configs,
check common errors, and stub out testing individual VTY commands.
The scripts have been moved to the another osmocom repository,
python/osmo-python-tests

The features were requested by zecke.
2013-06-24 13:22:34 +02:00
Harald Welte
cc6b2d2fa3 ctrlif: Flush/Clear write_queue when closing the control socket 2013-06-24 10:59:40 +02:00
Harald Welte
1304b35a64 bsc_vty: Print human-readable string version of NM ADM STATE 2013-06-24 10:59:33 +02:00
Harald Welte
abadd54346 GPRS LLC: Add non-standard method of sequence number recovery
In some situations (like MS reboot without prior DETACH or SGSN reboot
without prior MS detach), the LLC sequence numbers for UI mode could
be different on both sides.

The LLC spec unfortunately doesn't permit us to send something like a
FRMR in this case, but instructs us to silently discard the frame.  At
that time the remote LLC entity will re-transmit the frame with the same
seqeunce number over and over again, which we will drop again and again.

The mthod used now will keep track of the last received UI sequence
number.  If that number is retransmitted for three times in a row, then
we accept this sequence number and recover from that point on.
2013-06-21 14:06:18 +02:00
Harald Welte
22ce59826a osmo-bsc VTY: fix saving of codec-list
the codec-list parser expects only spaces between the elements of the
list, while the 'save' code is putting ", " between the elements
2013-06-19 15:42:44 +02:00
Holger Hans Peter Freyther
b0bf1da4c8 smpp: Only write the systemd-id if it is not empty
system_id is a char array, which makes the NULL check a tautology,
so we should check with strlen if the string is empty or not.

This is fixing the "write" command of VTY that would otherwise
create a config file that can not be parsed.
2013-06-12 09:35:43 +02:00
Alexander Huemer
a1c09a401d Makefile.am: Use AM_CPPFLAGS
Since automake 1.13 INCLUDES is depricates and causes a warning
2013-06-12 09:16:27 +02:00
Holger Hans Peter Freyther
846d8dca9f vty: Print the state of all GPRS OML objects in show bts
For debugging GB-proxy/IPA issues it is nice to see the state of
the OML objects.
2013-05-29 16:37:27 +02:00
Harald Welte
c75ed6d593 SMPP: Add new 'dcs_transparent' ESME setting
If an ESME has the dcs_transparent config flag, then the TP-DCS
of MO-SMS is transparently passed to SMPP and not converted to SMPP
specific data_coding values.

This is needed in cases where ESMEs actually care about the exact
TP-DCS, as the conversion from TP-DCS to SMPP data_coding is not
bijective.
2013-05-28 20:59:25 +02:00
Harald Welte
27d5e65640 SMPP: Pass on 0xFx style DCS from SMPP to GSM
There are multiple ways how the TS 03.38 TP-DCS can indicate 8bit or
7bit messages.  SMPP has it's own data coding specification, which is
different from TS 03.38.

However, some SMPP ESMEs want to be able to have fine-grained control
over the TP-DCS indicated in the TPDU header.  If such values like 0xF6
are used in SMPP, we now transparently pass them on to the GSM side.
2013-05-28 20:37:07 +02:00
Harald Welte
61e1935a5f SMPP: Respond with BIND_TRX_RESP to BIND_TRX, not BIND_TX_RESP 2013-05-26 14:40:14 +02:00
Holger Hans Peter Freyther
9f3835b988 mgcp: Initialize the tone to CHAR_MAX as this might not be a request
The RQNT message might not contain a 'S:' line with the actual tone
to play. Instead of calling the callback with the 0 as tone just leave
early.

Example:
X: 6B9519B88F0
R: D/[0-9#*](N), G/ft, fxr/t38
2013-05-21 17:04:35 +02:00
Pablo Neira Ayuso
0a244b40c9 nat: fix use after free in forward_sccp_to_bts
valgrind detected an use after free in the path of forward_sccp_to_bts.
The 'parsed' object is referenced from update_con_authorize.
2013-05-13 01:13:27 +02:00
Holger Hans Peter Freyther
2177624ca9 channels: Mark channels as broken that time out on activation/release
A channel that fails to send an ACK/NACK/REL within the four second
timeout is now marked as broken. In case the release comes in late
it will be ignored. The lchan should already been freed and for now
we don't want to trust the channel.

In the future we might want to send a "release" for a channel that
got activated ack late and just set the state to none on a channel
that is released acked late.

The late ACK and REL has been tested with two manual tests using the
fakebts. The channels remained blocked even after having received
the ACK message here. The NACK case has not been manually tested.
2013-05-02 19:36:29 +02:00
Holger Hans Peter Freyther
e152a46f6e Merge branch 'zecke/features/sysmobts'
* This branch make the type sysmobts work.
* Asssume a bsc_gsmnet variable to be defined.
* This allows to use channel configurations not supported by the
  nanoBTS.
* Manually tested with the FakeBTS and tested by users.
2013-04-29 20:47:52 +02:00
Holger Hans Peter Freyther
e48c1871af ipaccess: Remove the ipaccess_gsmnet and assume there is a bsc_gsmnet
Assume that there is a bsc_gsmnet and modify the ipaccess-config to
provide this symbol. If a bsc_gsmmnet is not available when linked
the linker will complain and fail.

E.g. give an error like this:
../../src/libbsc/libbsc.a(bts_ipaccess_nanobts.o): In function `ipaccess_sign_link_up':
src/libbsc/bts_ipaccess_nanobts.c:550: undefined reference to `bsc_gsmnet'
2013-04-29 20:44:42 +02:00
Holger Hans Peter Freyther
4b0e36ae7f sysmobts: Make the nanoBTS NM code work for the sysmobts
Use the is_ipaccess_bts method to check if this is either is
nanoBTS or sysmoBTS. The sysmobts type can now be used to bootstrap
a bts.
2013-04-29 20:44:42 +02:00
Holger Hans Peter Freyther
84b033f8c7 sysmobts: Initialize the NM signal handler only once in a mixed network
Make sure that the bts_ipa_nm_sig_cb is only installed once. In
a nanoBTS + sysmoBTS network the _start method will be called
for each mode leading to the handler being registered twice.

Make sure that there is only one handler registered by unregistering
a previously installed handler. The osmo_signal_unregister_handler
will remove 0 or 1 handlers per invocation and we only add one
handler in this file so it is always balanced.
2013-04-29 20:44:42 +02:00
Holger Hans Peter Freyther
e84dd98d26 sysmobts: Avoid a crash when trying to look-up a BTS
The nanoBTS code is trying to find a struct gsm_bts based on
the ipaccess_gsmnet and the ipaccess_unit data. The pointer is
not initialized in the case of a sysmoBTS leading to a classic
NULL pointer dereference.

Move the feature init into the _init method. This way we can
re-use the start code of the nanoBTS. This ensures that the
ipaccess_gsmnet pointer is properly initialized and that the
signal handlers are installed.
2013-04-29 20:44:42 +02:00
Holger Hans Peter Freyther
7a0010bdd4 nat: Include LAC/CI as TV values at the end of the 'status' message
Extend the status message and send LAC/CI as part of the status
message. It is using TV to allow sending more fields in the feature.
We only need to encode the data and this is why there is no tlv
description yet.
2013-04-29 20:40:44 +02:00
Holger Hans Peter Freyther
d7b22c624b smpp: Attempt to fix a memory leak of the msgb
The smpp_pdu_rx method does not free the msgb. Introduce an
annotation (currently defined to nothing) to indicate what
will happen to a msgb.
2013-04-29 14:00:59 +02:00
Holger Hans Peter Freyther
2bc90c274d nat: Use memcmp for the token on the USSD interface as well
This is similar to the token on the A-interface. There are no more
token based authentication in the NAT.
2013-04-22 10:54:32 +02:00
Holger Hans Peter Freyther
ab22335378 nat: Move the callstats to a new header file due sccp usage
The bsc_nat.h is included by common_vty.c so we may not used
sccp_types.h in the bsc_nat.h header file. Move the callstats
to a new file and include it where it is needed.
2013-04-22 09:07:39 +02:00
Holger Hans Peter Freyther
7e9b039a94 nat: Add an example for a black list 2013-04-18 15:11:49 +02:00
Holger Hans Peter Freyther
70c58ef03b ctrl: Provide a reply in case the range check failed 2013-04-17 14:34:36 +02:00
Holger Hans Peter Freyther
d38cf50d0a ctrl: Make the commands static to not pollute the namespace
We do not need to access these commands from another compilation
unit and can just make it static.
2013-04-17 14:34:26 +02:00
Holger Hans Peter Freyther
b2b291d3ef nat: Extract the LAC/CI from the Complete Layer3 Information
Find the Cell Identifier from the Complete Layer3 Information and
store it for future reference. We could begin to verify that the
LAC/CI used really belongs to the BSC.
2013-04-16 14:14:17 +02:00
Holger Hans Peter Freyther
c279e39c12 nat: Rename "struct sccp_connections" to "struct nat_sccp_connection"
The name sccp_connection is used in the osmo-sccp code, sccp_connections
was used in the NAT for tracking a sccp_connection. Rename it so it is
obvious that the struct belongs to the nat.

The rename was done with sed:
$ sed -i s,"struct sccp_connections","struct nat_sccp_connection",g \
		include/openbsc/*.h src/osmo-bsc_nat/* tests/*/*
2013-04-16 09:53:13 +02:00
Holger Hans Peter Freyther
0e5f5aeaad debian: Begin the 0.13.0 series with a new changelog entry 2013-04-16 09:23:33 +02:00
Holger Hans Peter Freyther
dbd9449a16 nat: Allow to re-write international numbers in the CC Setup messages
Prepend the international number with a '+' and then do the normal
re-writing on it. There are a couple of ways to handle this:

	\+([0-9]), \+[0-9][0-9]([0-9]), \+49([0-9])

Add a test case for the international re-write based on an already
internationalized number.
2013-04-16 09:20:06 +02:00
Holger Hans Peter Freyther
27b6184225 nat: Allow to daemonize the NAT process
Add handling for the 'D' option
2013-04-16 09:20:00 +02:00
Holger Hans Peter Freyther
dc3a78f0c4 Merge commit 'zecke/mgcp-statistics' 2013-04-16 09:18:29 +02:00
Holger Hans Peter Freyther
ac04d8d55e nat: Name the variable more properly and begin with net.1.bsc.%d
We can identify the NAT and BSC given the types of the variable,
no need to put them into the value itself.
2013-04-16 09:17:21 +02:00
Holger Hans Peter Freyther
7d7054eafa nat: Include the sccp_src_ref and sccp_dst_ref for this call
This can help with some post analysis for failed calls and helps
finding the connection in the pcap trace.
2013-04-16 09:17:21 +02:00
Holger Hans Peter Freyther
7c831ecd19 nat: Do not allow the amount of pending responses to grow infinitely
Limit the amount of pending DLCX responses to three times the amount
of available endpoints. Currently all MGCP messages are sent and handled
in sequence.
2013-04-16 09:17:21 +02:00
Holger Hans Peter Freyther
931ad6ac33 nat: Reword the log messages as this is normal operation
The bsc_mgcp_dlcx method is called from the mgcp policy callback
but also from inside the nat core when the SCCP connection is going
away.
2013-04-16 09:17:21 +02:00
Holger Hans Peter Freyther
462b7d7158 nat: We want the remote to respond to our DLCX request
We want to send a TRAP with the MGCP statistics from the NAT and
the connected BSC. The BSC endpoint can be either released because
of a DLCX from the MGCP CallAgent or the SCCP Connection release on
the A-link.

This is why we need to queue the statistics when the deleting the
endpoint on the BSC. The processing is continued once the response
arrives. This code assumes that the response of the DLCX will be sent
by the remote side. The current amount of outstanding responses can be
seen on the VTY. This assumption is based on the fact that the BSC has
already responded to the CRCX and maybe to the MDCX.

The MGCP RFC is bended to prefix the transaction identifier with "nat-"
to easily detect the response and hand it to the handler. This will
then parse the response and generate the TRAP. The current version is
v1. We assume that the transaction space is big enough and we will
not re-assign the transaction identifier too early.
2013-04-16 09:17:21 +02:00
Holger Hans Peter Freyther
c327187259 nat: Make it possible to send MGCP messages through the IPA multiplex
Instead of handling MGCP through the UDP socket, read and write messages
through the ipa connection to the MSC.
2013-04-16 09:17:21 +02:00
Holger Hans Peter Freyther
77956aa034 nat: Move all methods sending a response to the callagent to a single place
For testing it can be nice to handle MGCP messages through the IPA
protocol. Prepare the code to send the messages through other means.
2013-04-16 09:17:21 +02:00
Holger Hans Peter Freyther
6de9d0ba35 nat: Address the FIXME and send the MDCX down to the BSC 2013-04-16 09:17:21 +02:00
Holger Hans Peter Freyther
1c0c317094 debian: Fix the installation of the sgsn example data
Creating the sgsn package failed because the debian directory has
been moved and the .examples file was not updated. This was reported
by plotr.
2013-04-05 18:43:25 +02:00
Holger Hans Peter Freyther
30156e1eea sysmobts: Add the necessary data structure and init for the SAPI queue
The sysmobts is now having a SAPI queue with all pending SAPI operations
on the BTS. Add the llist_head to the lchan and make sure it is initialized
by the shared code.
2013-04-05 18:41:45 +02:00
Holger Hans Peter Freyther
d34adb2f9f nat: Fix authentication by-pass using shorter tokens
The token was compared with the configured one but only up to a
user supplied length. Compare the token sizes and then use memcmp
for the actual comparison to make sure to compare the right ammount
of characters.

There is no unit-test but there should be one.
2013-04-02 10:10:21 +02:00
Holger Hans Peter Freyther
8ae35c1606 bsc-ctrl: Fix a potential memory leak on failed verification
It was possible that the tmp was strduped but not freed, e.g. when
the number of commas was not right. It would evenutally be freed at
the time the cmd is freed thanks to the talloc hierachy.
2013-03-28 17:13:01 +01:00
Holger Hans Peter Freyther
0c908b6e72 db: Link to the VTY library for the vty_config_unlock symbol
Linking started to fail for me due the symbol coming from the
vty library and the db code not linking to it.
2013-03-21 11:12:56 +01:00
Andreas Eversberg
0c8f9ca30b Add VTY option to set GPRS network-control-order to enable MS measurements
In order to enable GPRS downlink measurements at mobile, the
network-control-order must be set to nc1.
2013-03-17 14:37:16 +01:00
Harald Welte
7159e8bea3 Fix osmo-nitb build without libsmpp 2013-03-13 15:40:14 +01:00
284 changed files with 44684 additions and 6730 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
debian/*.log

21
debian/changelog vendored
View File

@@ -1,3 +1,22 @@
openbsc (0.14.0-fw.2) trusty; urgency=low
* Added a way to always route SMS through SMPP.
-- Ivan Kluchnikov <kluchnikovi@gmail.com> Thu, 20 Aug 2015 20:17:42 +0300
openbsc (0.14.0-fw.1) trusty; urgency=low
* Added osmocom-meas-utils package.
* Others enhancements and fixes.
-- Ivan Kluchnikov <kluchnikovi@gmail.com> Mon, 27 Jul 2015 13:56:58 +0300
openbsc (0.14.0) UNRELEASED; urgency=low
* New upstream tag and additional patches.
-- Holger Hans Peter Freyther <holger@freyther.de> Sat, 14 Mar 2015 20:33:25 +0100
openbsc (0.12.0+git26-7) unstable; urgency=low
* 64bit fix for the MGCP rewriting
@@ -56,6 +75,6 @@ openbsc (0.9.13.115.eb113-1) natty; urgency=low
openbsc (0.9.4-1) unstable; urgency=low
* Initial release (Closes: #nnnn) <nnnn is the bug number of your ITP>
* Initial release
-- Harald Welte <laforge@gnumonks.org> Tue, 24 Aug 2010 13:34:24 +0200

44
debian/control vendored
View File

@@ -2,43 +2,37 @@ Source: openbsc
Section: net
Priority: optional
Maintainer: Harald Welte <laforge@gnumonks.org>
Build-Depends: debhelper (>= 7.0.0~), autotools-dev, pkg-config, libgtp-dev, libosmocore-dev, libosmo-sccp-dev, libdbi0-dev, dh-autoreconf, libosmo-abis-dev, libdbd-sqlite3
Build-Depends: debhelper (>= 7.0.0~), autotools-dev, pkg-config, libosmocore-dev, libosmo-sccp-dev, libdbi0-dev, dh-autoreconf, libosmo-abis-dev, libosmo-netif-dev, libdbd-sqlite3, libpcap-dev, libsmpp34-dev, libcdk5-dev, libsqlite3-dev
Standards-Version: 3.8.4
Homepage: http://openbsc.osmocom.org/
Vcs-Git: git://bs11-abis.gnumonks.org/openbsc.git
Vcs-Browser: http://openbsc.osmocom.org/trac/browser
Package: osmocom-bsc
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libosmocore, libosmo-sccp
Description: GSM Base Station Controller; BSC-only version of OpenBSC. Needs a real MSC!
Package: osmocom-nitb
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libosmocore, libdbd-sqlite3, libdbi1
Depends: ${shlibs:Depends}, ${misc:Depends}, libdbd-sqlite3
Description: GSM Network-in-a-Box, implements BSC, MSC, SMSC, HLR, VLR
All the GSM network components bundled together.
Package: osmocom-ipaccess-utils
Package: osmocom-meas-utils
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libosmocore
Description: Command line utilities for ip.access nanoBTS
Depends: ${shlibs:Depends}, ${misc:Depends}, libcdk5, sqlite3
Description: Measurement utilities for the OpenBSC
Measurement utilities for the OpenBSC.
Package: osmocom-bs11-utils
Package: osmocom-nitb-dbg
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libosmocore
Description: Command line utilities for Siemens BS-11 BTS
Section: debug
Priority: extra
Depends: osmocom-nitb (= ${binary:Version}), ${misc:Depends}
Description: Debug symbols for the OpenBSC NITB
Make debugging possible
Package: osmocom-sgsn
Package: osmocom-meas-utils-dbg
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libosmocore, libgtp
Description: Osmocom Serving GPRS Support Node
Section: debug
Priority: extra
Depends: osmocom-meas-utils (= ${binary:Version}), ${misc:Depends}
Description: Debug symbols for the OpenBSC measurement utilities
Make debugging possible
Package: osmocom-gbproxy
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libosmocore
Description: Osmocom GPRS Gb Interface Proxy
Package: osmocom-bsc-nat
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libosmocore
Description: Osmocom Base Station Controller Network Address Translation

5
debian/copyright vendored
View File

@@ -6,7 +6,7 @@ It was downloaded from:
git://bs11-abis.gnumonks.org/openbsc.git
Upstream Author(s):
Upstream Authors:
Harald Welte <laforge@gnumonks.org>
Dieter Spaar <spaar@mirider.augusta.de>
@@ -45,6 +45,3 @@ The Debian packaging is:
and is licensed under the GPL version 3,
see "/usr/share/common-licenses/GPL-3".
# Please also look if there are files or directories which have a
# different copyright/license attached and list them here.

153
debian/osmocom-bsc-nat.init vendored Executable file
View File

@@ -0,0 +1,153 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: osmocom-bsc-nat
# Required-Start: $network $local_fs
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Osmocom GSM network-in-a-box
# Description: A minimal implementation of the GSM Base Station Controller,
# Mobile Switching Center, Home Location regster and all other
# components to run a self-contained GSM network.
### END INIT INFO
# Author: Harald Welte <laforge@gnumonks.org>
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
NAME=osmo-bsc_nat # Introduce the short server's name here
DESC="Osmocom GSM BSC Multiplexer (NAT)" # Introduce a short description here
DAEMON=/usr/bin/osmo-bsc_nat # Introduce the server's location here
SCRIPTNAME=/etc/init.d/osmocom-bsc-nat
CONFIG_FILE=/etc/osmocom/osmocom-bsc-nat.cfg
# Exit if the package is not installed
[ -x $DAEMON ] || exit 0
# Read configuration variable file if it is present
[ -r /etc/default/osmocom-bsc-nat ] && . /etc/default/osmocom-bsc-nat
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
DAEMON_ARGS="-D -c $CONFIG_FILE"
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --exec $DAEMON --test > /dev/null \
|| return 1
start-stop-daemon --start --quiet --exec $DAEMON -- \
$DAEMON_ARGS \
|| return 2
# Add code here, if necessary, that waits for the process to be ready
# to handle requests from services started subsequently which depend
# on this one. As a last resort, sleep for some time.
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --name $NAME
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
[ "$?" = 2 ] && return 2
return "$RETVAL"
}
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet $PIDFILE --name $NAME
return 0
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
exit 3
;;
esac
:

151
debian/osmocom-gbproxy.init vendored Executable file
View File

@@ -0,0 +1,151 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: osmo-gbproxy
# Required-Start: $network $local_fs
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Osmocom GBproxy
# Description: A tool to proxy the GPRS Gb interface.
### END INIT INFO
# Author: Harald Welte <laforge@gnumonks.org>
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
NAME=osmo-gbproxy # Introduce the short server's name here
DESC="Osmocom GBProxy" # Introduce a short description here
DAEMON=/usr/bin/osmo-gbproxy # Introduce the server's location here
SCRIPTNAME=/etc/init.d/osmocom-gbproxy
CONFIG_FILE=/etc/osmocom/osmocom-gbproxy.cfg
# Exit if the package is not installed
[ -x $DAEMON ] || exit 0
# Read configuration variable file if it is present
[ -r /etc/default/osmocom-gbproxy ] && . /etc/default/osmocom-gbproxy
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
DAEMON_ARGS="-D -c $CONFIG_FILE"
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --exec $DAEMON --test > /dev/null \
|| return 1
start-stop-daemon --start --quiet --exec $DAEMON -- \
$DAEMON_ARGS \
|| return 2
# Add code here, if necessary, that waits for the process to be ready
# to handle requests from services started subsequently which depend
# on this one. As a last resort, sleep for some time.
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --name $NAME
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
[ "$?" = 2 ] && return 2
return "$RETVAL"
}
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet $PIDFILE --name $NAME
return 0
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC " "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
exit 3
;;
esac
:

4
debian/osmocom-meas-utils.install vendored Normal file
View File

@@ -0,0 +1,4 @@
/usr/bin/osmo-meas-udp2db
/usr/bin/osmo-meas-pcap2db
/usr/bin/meas_vis
/usr/bin/meas_json

View File

@@ -1 +1 @@
doc/examples/osmo-sgsn
openbsc/doc/examples/osmo-sgsn

8
debian/rules vendored
View File

@@ -17,6 +17,8 @@ DEBIAN := $(shell dpkg-parsechangelog | grep ^Version: | cut -d' ' -f2)
DEBVERS := $(shell echo '$(DEBIAN)' | cut -d- -f1)
VERSION := $(shell echo '$(DEBVERS)' | sed -e 's/[+-].*//' -e 's/~//g')
export DEB_BUILD_HARDENING=1
%:
dh --sourcedirectory=openbsc --with autoreconf $@
@@ -24,7 +26,11 @@ VERSION := $(shell echo '$(DEBVERS)' | sed -e 's/[+-].*//' -e 's/~//g')
override_dh_autoreconf:
cd openbsc && autoreconf --install --force
override_dh_strip:
dh_strip -posmocom-nitb --dbg-package=osmocom-nitb-dbg
dh_strip -posmocom-meas-utils --dbg-package=osmocom-meas-utils-dbg
override_dh_auto_configure:
echo $(VERSION) > openbsc/.tarball-version
dh_auto_configure --sourcedirectory=openbsc -- --enable-nat --enable-osmo-bsc
dh_auto_configure --sourcedirectory=openbsc -- --enable-smpp

18
openbsc/.gitignore vendored
View File

@@ -10,9 +10,16 @@ openbsc.pc
src/osmo-nitb/osmo-nitb
src/osmo-bsc_mgcp/osmo-bsc_mgcp
src/osmo-bsc/osmo-bsc
src/utils/meas_vis
src/utils/osmo-meas-pcap2db
src/utils/osmo-meas-udp2db
src/utils/smpp_mirror
*.*~
*.sw?
.libs
*.pyc
*.gcda
*.gcno
#configure
aclocal.m4
@@ -22,6 +29,7 @@ config.status
config.guess
config.sub
configure
compile
depcomp
install-sh
missing
@@ -48,7 +56,9 @@ src/gprs/osmo-gbproxy
src/osmo-bsc_nat/osmo-bsc_nat
#tests
tests/testsuite.dir
tests/bsc-nat/bsc_nat_test
tests/bsc-nat-trie/bsc_nat_trie_test
tests/channel/channel_test
tests/db/db_test
tests/debug/debug_test
@@ -58,7 +68,15 @@ tests/sccp/sccp_test
tests/sms/sms_test
tests/timer/timer_test
tests/gprs/gprs_test
tests/gbproxy/gbproxy_test
tests/abis/abis_test
tests/si/si_test
tests/smpp/smpp_test
tests/bsc/bsc_test
tests/trau/trau_test
tests/mgcp/mgcp_transcoding_test
tests/sgsn/sgsn_test
tests/subscr/subscr_test
tests/atconfig
tests/atlocal

View File

@@ -1,13 +1,13 @@
AUTOMAKE_OPTIONS = foreign dist-bzip2 1.6
INCLUDES = $(all_includes) -I$(top_srcdir)/include
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include
SUBDIRS = doc include src tests
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = openbsc.pc
BUILT_SOURCES = $(top_srcdir)/.version
EXTRA_DIST = git-version-gen
EXTRA_DIST = git-version-gen osmoappdesc.py
$(top_srcdir)/.version:
echo $(VERSION) > $@-t && mv $@-t $@
dist-hook:

View File

@@ -1,7 +1,7 @@
dnl Process this file with autoconf to produce a configure script
AC_INIT([openbsc],
m4_esyscmd([./git-version-gen .tarball-version]),
[openbsc-devel@lists.openbsc.org])
[openbsc@lists.osmocom.org])
AM_INIT_AUTOMAKE([dist-bzip2])
AC_CONFIG_TESTDIR(tests)
@@ -18,12 +18,17 @@ AC_PROG_RANLIB
dnl checks for libraries
AC_SEARCH_LIBS(crypt, crypt,
[LIBCRYPT="-lcrypt"; AC_DEFINE([VTY_CRYPT_PW], [], [Use crypt functionality of vty.])])
AC_SEARCH_LIBS([dlopen], [dl dld], [LIBRARY_DL="$LIBS";LIBS=""])
AC_SUBST(LIBRARY_DL)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.5.3.60)
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 0.6.4)
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty >= 0.3.0)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.6.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.1.0)
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 0.5.2)
PKG_CHECK_MODULES(LIBOSMOCTRL, libosmoctrl)
PKG_CHECK_MODULES(LIBOSMOGSM, libosmogsm >= 0.7.0)
PKG_CHECK_MODULES(LIBOSMOABIS, libosmoabis >= 0.2.0)
PKG_CHECK_MODULES(LIBOSMOGB, libosmogb >= 0.6.4)
PKG_CHECK_MODULES(LIBOSMONETIF, libosmo-netif >= 0.0.1)
# Enabke/disable the NAT?
AC_ARG_ENABLE([nat], [AS_HELP_STRING([--enable-nat], [Build the BSC NAT. Requires SCCP])],
@@ -36,31 +41,58 @@ AC_SUBST(osmo_ac_build_nat)
# Enable/disable the BSC?
AC_ARG_ENABLE([osmo-bsc], [AS_HELP_STRING([--enable-osmo-bsc], [Build the Osmo BSC])],
[osmo_ac_build_bsc="$enableval"])
[osmo_ac_build_bsc="$enableval"],[osmo_ac_build_bsc="no"])
if test "$osmo_ac_build_bsc" = "yes" ; then
PKG_CHECK_MODULES(LIBOSMOSCCP, libosmo-sccp >= 0.0.6)
fi
AM_CONDITIONAL(BUILD_BSC, test "x$osmo_ac_build_bsc" = "xyes")
AC_SUBST(osmo_ac_build_bsc)
# Enable/disable smpp support in the nitb?
AC_ARG_ENABLE([smpp], [AS_HELP_STRING([--enable-smpp], [Build the SMPP interface])],
[osmo_ac_build_smpp="$enableval"])
[osmo_ac_build_smpp="$enableval"],[osmo_ac_build_smpp="no"])
if test "$osmo_ac_build_smpp" = "yes" ; then
PKG_CHECK_MODULES(LIBSMPP34, libsmpp34 >= 1.10)
AC_DEFINE(BUILD_SMPP, 1, [Define if we want to build SMPP])
fi
AM_CONDITIONAL(BUILD_SMPP, test "x$osmo_ac_build_smpp" = "xyes")
AC_SUBST(osmo_ac_build_smpp)
# Enable/disable transcoding within osmo-bsc_mgcp?
AC_ARG_ENABLE([mgcp-transcoding], [AS_HELP_STRING([--enable-mgcp-transcoding], [Build the MGCP gateway with internal transcoding enabled.])],
[osmo_ac_mgcp_transcoding="$enableval"],[osmo_ac_mgcp_transcoding="no"])
AC_ARG_WITH([g729], [AS_HELP_STRING([--with-g729], [Enable G.729 encoding/decoding.])], [osmo_ac_with_g729="$withval"],[osmo_ac_with_g729="no"])
if test "$osmo_ac_mgcp_transcoding" = "yes" ; then
AC_SEARCH_LIBS(gsm_create, gsm)
if test "$osmo_ac_with_g729" = "yes" ; then
PKG_CHECK_MODULES(LIBBCG729, libbcg729 >= 0.1, [AC_DEFINE([HAVE_BCG729], [1], [Use bgc729 decoder/encoder])])
fi
AC_DEFINE(BUILD_MGCP_TRANSCODING, 1, [Define if we want to build the MGCP gateway with transcoding support])
fi
AM_CONDITIONAL(BUILD_MGCP_TRANSCODING, test "x$osmo_ac_mgcp_transcoding" = "xyes")
AC_SUBST(osmo_ac_mgcp_transcoding)
found_libgtp=yes
PKG_CHECK_MODULES(LIBGTP, libgtp, , found_libgtp=no)
AM_CONDITIONAL(HAVE_LIBGTP, test "$found_libgtp" = yes)
AC_SUBST(found_libgtp)
dnl checks for header files
AC_HEADER_STDC
AC_CHECK_HEADERS(dahdi/user.h,,AC_MSG_WARN(DAHDI input driver will not be built))
AC_CHECK_HEADERS(dbi/dbd.h,,AC_MSG_ERROR(DBI library is not installed))
found_cdk=yes
AC_CHECK_HEADERS(cdk/cdk.h,,found_cdk=no)
AM_CONDITIONAL(HAVE_LIBCDK, test "$found_cdk" = yes)
found_sqlite3=yes
PKG_CHECK_MODULES(SQLITE3, sqlite3, ,found_sqlite3=no)
AM_CONDITIONAL(HAVE_SQLITE3, test "$found_sqlite3" = yes)
AC_SUBST(found_sqlite3)
dnl Checks for typedefs, structures and compiler characteristics
@@ -114,6 +146,26 @@ AC_DEFUN([CHECK_TM_INCLUDES_TM_GMTOFF], [
CHECK_TM_INCLUDES_TM_GMTOFF
AC_ARG_ENABLE([vty_tests],
AC_HELP_STRING([--enable-vty-tests],
[Include the VTY/CTRL tests in make check (deprecated)
[default=no]]),
[enable_ext_tests="$enableval"],[enable_ext_tests="no"])
AC_ARG_ENABLE([external_tests],
AC_HELP_STRING([--enable-external-tests],
[Include the VTY/CTRL tests in make check [default=no]]),
[enable_ext_tests="$enableval"],[enable_ext_tests="no"])
if test "x$enable_ext_tests" = "xyes" ; then
AM_PATH_PYTHON
AC_CHECK_PROG(OSMOTESTEXT_CHECK,osmotestvty.py,yes)
if test "x$OSMOTESTEXT_CHECK" != "xyes" ; then
AC_MSG_ERROR([Please install osmocom-python to run the VTY/CTRL tests.])
fi
fi
AC_MSG_CHECKING([whether to enable VTY/CTRL tests])
AC_MSG_RESULT([$enable_ext_tests])
AM_CONDITIONAL(ENABLE_EXT_TESTS, test "x$enable_ext_tests" = "xyes")
dnl Generate the output
AM_CONFIG_HEADER(bscconfig.h)
@@ -124,10 +176,10 @@ AC_OUTPUT(
src/Makefile
src/libtrau/Makefile
src/libbsc/Makefile
src/libctrl/Makefile
src/libmsc/Makefile
src/libmgcp/Makefile
src/libcommon/Makefile
src/libfilter/Makefile
src/osmo-nitb/Makefile
src/osmo-bsc/Makefile
src/osmo-bsc_nat/Makefile
@@ -140,11 +192,17 @@ AC_OUTPUT(
tests/gsm0408/Makefile
tests/db/Makefile
tests/channel/Makefile
tests/bsc/Makefile
tests/bsc-nat/Makefile
tests/bsc-nat-trie/Makefile
tests/mgcp/Makefile
tests/gprs/Makefile
tests/si/Makefile
tests/gbproxy/Makefile
tests/abis/Makefile
tests/smpp/Makefile
tests/trau/Makefile
tests/sgsn/Makefile
tests/subscr/Makefile
doc/Makefile
doc/examples/Makefile
Makefile)

View File

@@ -1,57 +0,0 @@
#!/usr/bin/env python
"""
Start the process and dump the documentation to the doc dir. This is
copied from the BTS directory and a fix might need to be applied there
too.
"""
import socket, subprocess, time,os
def dump_doc(end, port, filename):
sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sck.setblocking(1)
sck.connect(("localhost", port))
sck.recv(4096)
# Now send the command
sck.send("show online-help\r")
xml = ""
while True:
data = sck.recv(4096)
xml = "%s%s" % (xml, data)
if data.endswith(end):
break
# Now write everything until the end to the file
out = open(filename, 'w')
out.write(xml[18:len(end)*-1])
out.close()
apps = [
# The same could be done with an empty config file but this way
# the example files are properly tested.
(4242, "src/osmo-nitb/osmo-nitb", "doc/examples/osmo-nitb/nanobts/openbsc.cfg", "OpenBSC", "nitb"),
(4242, "src/osmo-bsc/osmo-bsc", "doc/examples/osmo-bsc/osmo-bsc.cfg", "OsmoBSC", "bsc"),
(4243, "src/osmo-bsc_mgcp/osmo-bsc_mgcp", "doc/examples/osmo-bsc_mgcp/mgcp.cfg", "OpenBSC MGCP", "mgcp"),
(4244, "src/osmo-bsc_nat/osmo-bsc_nat", "doc/examples/osmo-bsc_nat/osmo-bsc_nat.cfg", "OsmoBSCNAT", "nat"),
(4245, "src/gprs/osmo-sgsn", "doc/examples/osmo-sgsn/osmo-sgsn.cfg", "OsmoSGSN", "sgsn"),
(4246, "src/gprs/osmo-gbproxy", "doc/examples/osmo-gbproxy/osmo-gbproxy.cfg", "OsmoGbProxy", "gbproxy"),
]
# Dump the config of all our apps
for app in apps:
print "Starting app for %s" % app[4]
cmd = [app[1], "-c", app[2]]
proc = subprocess.Popen(cmd, stdin=None, stdout=None)
time.sleep(1)
try:
dump_doc('\r\n%s> ' % app[3], app[0], 'doc/%s_vty_reference.xml' % app[4])
finally:
# Clean-up
proc.kill()
proc.wait()

View File

@@ -0,0 +1,420 @@
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -smp disable
-module(gen_rtp_header).
% -mode(compile).
-define(VERSION, "0.1").
-export([main/1]).
-record(rtp_packet,
{
version = 2,
padding = 0,
marker = 0,
payload_type = 0,
seqno = 0,
timestamp = 0,
ssrc = 0,
csrcs = [],
extension = <<>>,
payload = <<>>,
realtime
}).
main(Args) ->
DefaultOpts = [{format, state},
{ssrc, 16#11223344},
{rate, 8000},
{pt, 98}],
{PosArgs, Opts} = getopts_checked(Args, DefaultOpts),
log(debug, fun (Dev) ->
io:format(Dev, "Initial options:~n", []),
dump_opts(Dev, Opts),
io:format(Dev, "~s: ~p~n", ["Args", PosArgs])
end, [], Opts),
main(PosArgs, Opts).
main([First | RemArgs], Opts) ->
try
F = list_to_integer(First),
Format = proplists:get_value(format, Opts, state),
PayloadData = proplists:get_value(payload, Opts, undef),
InFile = proplists:get_value(file, Opts, undef),
Payload = case {PayloadData, InFile} of
{undef, undef} ->
% use default value
#rtp_packet{}#rtp_packet.payload;
{P, undef} -> P;
{_, File} ->
log(info, "Loading file '~s'~n", [File], Opts),
{ok, InDev} = file:open(File, [read]),
DS = [ Pl#rtp_packet.payload || {_T, Pl} <- read_packets(InDev, Opts)],
file:close(InDev),
log(debug, "File '~s' closed, ~w packets read.~n", [File, length(DS)], Opts),
DS
end,
Dev = standard_io,
write_packet_pre(Dev, Format),
do_groups(Dev, Payload, F, RemArgs, Opts),
write_packet_post(Dev, Format),
0
catch
_:_ ->
log(debug, "~p~n", [hd(erlang:get_stacktrace())], Opts),
usage(),
halt(1)
end
;
main(_, _Opts) ->
usage(),
halt(1).
%%% group (count + offset) handling %%%
do_groups(_Dev, _Pl, _F, [], _Opts) ->
ok;
do_groups(Dev, Pl, F, [L], Opts) ->
do_groups(Dev, Pl, F, [L, 0], Opts);
do_groups(Dev, Pl, First, [L, O | Args], Opts) ->
Ssrc = proplists:get_value(ssrc, Opts, #rtp_packet.ssrc),
PT = proplists:get_value(pt, Opts, #rtp_packet.payload_type),
Len = list_to_num(L),
Offs = list_to_num(O),
log(info, "Starting group: Ssrc=~.16B, PT=~B, First=~B, Len=~B, Offs=~B~n",
[Ssrc, PT, First, Len, Offs], Opts),
Pkg = #rtp_packet{ssrc = Ssrc, payload_type = PT},
Pl2 = write_packets(Dev, Pl, Pkg, First, Len, Offs, Opts),
{Args2, Opts2} = getopts_checked(Args, Opts),
log(debug, fun (Io) ->
io:format(Io, "Changed options:~n", []),
dump_opts(Io, Opts2 -- Opts)
end, [], Opts),
do_groups(Dev, Pl2, First+Len, Args2, Opts2).
%%% error handling helpers %%%
getopts_checked(Args, Opts) ->
try
getopts(Args, Opts)
catch
C:R ->
log(error, "~s~n",
[explain_error(C, R, erlang:get_stacktrace(), Opts)], Opts),
usage(),
halt(1)
end.
explain_error(error, badarg, [{erlang,list_to_integer,[S,B]} | _ ], _Opts) ->
io_lib:format("Invalid number '~s' (base ~B)", [S, B]);
explain_error(error, badarg, [{erlang,list_to_integer,[S]} | _ ], _Opts) ->
io_lib:format("Invalid decimal number '~s'", [S]);
explain_error(C, R, [Hd | _ ], _Opts) ->
io_lib:format("~p, ~p:~p", [Hd, C, R]);
explain_error(_, _, [], _Opts) ->
"".
%%% usage and options %%%
myname() ->
filename:basename(escript:script_name()).
usage(Text) ->
io:format(standard_error, "~s: ~s~n", [myname(), Text]),
usage().
usage() ->
io:format(standard_error,
"Usage: ~s [Options] Start Count1 Offs1 [[Options] Count2 Offs2 ...]~n",
[myname()]).
show_version() ->
io:format(standard_io,
"~s ~s~n", [myname(), ?VERSION]).
show_help() ->
io:format(standard_io,
"Usage: ~s [Options] Start Count1 Offs1 [[Options] Count2 Offs2 ...]~n~n" ++
"Options:~n" ++
" -h, --help this text~n" ++
" --version show version info~n" ++
" -i, --file=FILE reads payload from file (state format by default)~n" ++
" -f, --frame-size=N read payload as binary frames of size N instead~n" ++
" -p, --payload=HEX set constant payload~n" ++
" --verbose=N set verbosity~n" ++
" -v increase verbosity~n" ++
" --format=state use state format for output (default)~n" ++
" -C, --format=c use simple C lines for output~n" ++
" --format=carray use a C array for output~n" ++
" -s, --ssrc=SSRC set the SSRC~n" ++
" -t, --type=N set the payload type~n" ++
" -r, --rate=N set the RTP rate [8000]~n" ++
" -D, --duration=N set the packet duration in RTP time units [160]~n" ++
" -d, --delay=FLOAT add offset to playout timestamp~n" ++
"~n" ++
"Arguments:~n" ++
" Start initial packet (sequence) number~n" ++
" Count number of packets~n" ++
" Offs timestamp offset (in RTP units)~n" ++
"", [myname()]).
getopts([ "--file=" ++ File | R], Opts) ->
getopts(R, [{file, File} | Opts]);
getopts([ "-i" ++ T | R], Opts) ->
getopts_alias_arg("--file", T, R, Opts);
getopts([ "--frame-size=" ++ N | R], Opts) ->
Size = list_to_integer(N),
getopts(R, [{frame_size, Size}, {in_format, bin} | Opts]);
getopts([ "-f" ++ T | R], Opts) ->
getopts_alias_arg("--frame-size", T, R, Opts);
getopts([ "--duration=" ++ N | R], Opts) ->
Duration = list_to_integer(N),
getopts(R, [{duration, Duration} | Opts]);
getopts([ "-D" ++ T | R], Opts) ->
getopts_alias_arg("--duration", T, R, Opts);
getopts([ "--rate=" ++ N | R], Opts) ->
Rate = list_to_integer(N),
getopts(R, [{rate, Rate} | Opts]);
getopts([ "-r" ++ T | R], Opts) ->
getopts_alias_arg("--rate", T, R, Opts);
getopts([ "--version" | _], _Opts) ->
show_version(),
halt(0);
getopts([ "--help" | _], _Opts) ->
show_help(),
halt(0);
getopts([ "-h" ++ T | R], Opts) ->
getopts_alias_no_arg("--help", T, R, Opts);
getopts([ "--verbose=" ++ V | R], Opts) ->
Verbose = list_to_integer(V),
getopts(R, [{verbose, Verbose} | Opts]);
getopts([ "-v" ++ T | R], Opts) ->
Verbose = proplists:get_value(verbose, Opts, 0),
getopts_short_no_arg(T, R, [ {verbose, Verbose+1} | Opts]);
getopts([ "--format=state" | R], Opts) ->
getopts(R, [{format, state} | Opts]);
getopts([ "--format=c" | R], Opts) ->
getopts(R, [{format, c} | Opts]);
getopts([ "-C" ++ T | R], Opts) ->
getopts_alias_no_arg("--format=c", T, R, Opts);
getopts([ "--format=carray" | R], Opts) ->
getopts(R, [{format, carray} | Opts]);
getopts([ "--payload=" ++ Hex | R], Opts) ->
getopts(R, [{payload, hex_to_bin(Hex)} | Opts]);
getopts([ "--ssrc=" ++ Num | R], Opts) ->
getopts(R, [{ssrc, list_to_num(Num)} | Opts]);
getopts([ "-s" ++ T | R], Opts) ->
getopts_alias_arg("--ssrc", T, R, Opts);
getopts([ "--type=" ++ Num | R], Opts) ->
getopts(R, [{pt, list_to_num(Num)} | Opts]);
getopts([ "-t" ++ T | R], Opts) ->
getopts_alias_arg("--type", T, R, Opts);
getopts([ "--delay=" ++ Num | R], Opts) ->
getopts(R, [{delay, list_to_float(Num)} | Opts]);
getopts([ "-d" ++ T | R], Opts) ->
getopts_alias_arg("--delay", T, R, Opts);
% parsing helpers
getopts([ "--" | R], Opts) ->
{R, normalize_opts(Opts)};
getopts([ O = "--" ++ _ | _], _Opts) ->
usage("Invalid option: " ++ O),
halt(1);
getopts([ [ $-, C | _] | _], _Opts) when C < $0; C > $9 ->
usage("Invalid option: -" ++ [C]),
halt(1);
getopts(R, Opts) ->
{R, normalize_opts(Opts)}.
getopts_short_no_arg([], R, Opts) -> getopts(R, Opts);
getopts_short_no_arg(T, R, Opts) -> getopts([ "-" ++ T | R], Opts).
getopts_alias_no_arg(A, [], R, Opts) -> getopts([A | R], Opts);
getopts_alias_no_arg(A, T, R, Opts) -> getopts([A, "-" ++ T | R], Opts).
getopts_alias_arg(A, [], [T | R], Opts) -> getopts([A ++ "=" ++ T | R], Opts);
getopts_alias_arg(A, T, R, Opts) -> getopts([A ++ "=" ++ T | R], Opts).
normalize_opts(Opts) ->
[ proplists:lookup(E, Opts) || E <- proplists:get_keys(Opts) ].
%%% conversions %%%
bin_to_hex(Bin) -> [hd(integer_to_list(N,16)) || <<N:4>> <= Bin].
hex_to_bin(Hex) -> << <<(list_to_integer([Nib],16)):4>> || Nib <- Hex>>.
list_to_num("-" ++ Str) -> -list_to_num(Str);
list_to_num("0x" ++ Str) -> list_to_integer(Str, 16);
list_to_num("0b" ++ Str) -> list_to_integer(Str, 2);
list_to_num(Str = [ $0 | _ ]) -> list_to_integer(Str, 8);
list_to_num(Str) -> list_to_integer(Str, 10).
%%% dumping data %%%
dump_opts(Dev, Opts) ->
dump_opts2(Dev, Opts, proplists:get_keys(Opts)).
dump_opts2(Dev, Opts, [OptName | R]) ->
io:format(Dev, " ~-10s: ~p~n",
[OptName, proplists:get_value(OptName, Opts)]),
dump_opts2(Dev, Opts, R);
dump_opts2(_Dev, _Opts, []) -> ok.
%%% logging %%%
log(L, Fmt, Args, Opts) when is_list(Opts) ->
log(L, Fmt, Args, proplists:get_value(verbose, Opts, 0), Opts).
log(debug, Fmt, Args, V, Opts) when V > 2 -> log2("DEBUG", Fmt, Args, Opts);
log(info, Fmt, Args, V, Opts) when V > 1 -> log2("INFO", Fmt, Args, Opts);
log(notice, Fmt, Args, V, Opts) when V > 0 -> log2("NOTICE", Fmt, Args, Opts);
log(warn, Fmt, Args, _V, Opts) -> log2("WARNING", Fmt, Args, Opts);
log(error, Fmt, Args, _V, Opts) -> log2("ERROR", Fmt, Args, Opts);
log(Lvl, Fmt, Args, V, Opts) when V >= Lvl -> log2("", Fmt, Args, Opts);
log(_, _, _, _i, _) -> ok.
log2(Type, Fmt, Args, _Opts) when is_list(Fmt) ->
io:format(standard_error, "~s: " ++ Fmt, [Type | Args]);
log2("", Fmt, Args, _Opts) when is_list(Fmt) ->
io:format(standard_error, Fmt, Args);
log2(_Type, Fun, _Args, _Opts) when is_function(Fun, 1) ->
Fun(standard_error).
%%% RTP packets %%%
make_rtp_packet(P = #rtp_packet{version = 2}) ->
<< (P#rtp_packet.version):2,
0:1, % P
0:1, % X
0:4, % CC
(P#rtp_packet.marker):1,
(P#rtp_packet.payload_type):7,
(P#rtp_packet.seqno):16,
(P#rtp_packet.timestamp):32,
(P#rtp_packet.ssrc):32,
(P#rtp_packet.payload)/bytes
>>.
parse_rtp_packet(
<< 2:2, % Version 2
0:1, % P (not supported yet)
0:1, % X (not supported yet)
0:4, % CC (not supported yet)
M:1,
PT:7,
SeqNo: 16,
TS:32,
Ssrc:32,
Payload/bytes >>) ->
#rtp_packet{
version = 0,
marker = M,
payload_type = PT,
seqno = SeqNo,
timestamp = TS,
ssrc = Ssrc,
payload = Payload}.
%%% payload generation %%%
next_payload(F) when is_function(F) ->
{F(), F};
next_payload({F, D}) when is_function(F) ->
{P, D2} = F(D),
{P, {F, D2}};
next_payload([P | R]) ->
{P, R};
next_payload([]) ->
undef;
next_payload(Bin = <<_/bytes>>) ->
{Bin, Bin}.
%%% real writing work %%%
write_packets(_Dev, DS, _P, _F, 0, _O, _Opts) ->
DS;
write_packets(Dev, DataSource, P = #rtp_packet{}, F, L, O, Opts) ->
Format = proplists:get_value(format, Opts, state),
Ptime = proplists:get_value(duration, Opts, 160),
Delay = proplists:get_value(delay, Opts, 0),
Rate = proplists:get_value(rate, Opts, 8000),
case next_payload(DataSource) of
{Payload, DataSource2} ->
write_packet(Dev, Ptime * F / Rate + Delay,
P#rtp_packet{seqno = F, timestamp = F*Ptime+O,
payload = Payload},
Format),
write_packets(Dev, DataSource2, P, F+1, L-1, O, Opts);
Other -> Other
end.
write_packet(Dev, Time, P = #rtp_packet{}, Format) ->
Bin = make_rtp_packet(P),
write_packet_line(Dev, Time, P, Bin, Format).
write_packet_pre(Dev, carray) ->
io:format(Dev,
"struct {float t; int len; char *data;} packets[] = {~n", []);
write_packet_pre(_Dev, _) -> ok.
write_packet_post(Dev, carray) ->
io:format(Dev, "};~n", []);
write_packet_post(_Dev, _) -> ok.
write_packet_line(Dev, Time, _P, Bin, state) ->
io:format(Dev, "~f ~s~n", [Time, bin_to_hex(Bin)]);
write_packet_line(Dev, Time, #rtp_packet{seqno = N, timestamp = TS}, Bin, c) ->
ByteList = [ [ $0, $x | integer_to_list(Byte, 16) ] || <<Byte:8>> <= Bin ],
ByteStr = string:join(ByteList, ", "),
io:format(Dev, "/* time=~f, SeqNo=~B, TS=~B */ {~s}~n", [Time, N, TS, ByteStr]);
write_packet_line(Dev, Time, #rtp_packet{seqno = N, timestamp = TS}, Bin, carray) ->
io:format(Dev, " /* RTP: SeqNo=~B, TS=~B */~n", [N, TS]),
io:format(Dev, " {~f, ~B, \"", [Time, size(Bin)]),
[ io:format(Dev, "\\x~2.16.0B", [Byte]) || <<Byte:8>> <= Bin ],
io:format(Dev, "\"},~n", []).
%%% real reading work %%%
read_packets(Dev, Opts) ->
Format = proplists:get_value(in_format, Opts, state),
read_packets(Dev, Opts, Format).
read_packets(Dev, Opts, Format) ->
case read_packet(Dev, Opts, Format) of
eof -> [];
Tuple -> [Tuple | read_packets(Dev, Opts, Format)]
end.
read_packet(Dev, Opts, bin) ->
Size = proplists:get_value(frame_size, Opts),
case file:read(Dev, Size) of
{ok, Data} -> {0, #rtp_packet{payload = iolist_to_binary(Data)}};
eof -> eof
end;
read_packet(Dev, _Opts, Format) ->
case read_packet_line(Dev, Format) of
{Time, Bin} -> {Time, parse_rtp_packet(Bin)};
eof -> eof
end.
read_packet_line(Dev, state) ->
case io:fread(Dev, "", "~f ~s") of
{ok, [Time, Hex]} -> {Time, hex_to_bin(Hex)};
eof -> eof
end.

View File

@@ -7,11 +7,15 @@ FileStream fileIn: 'rtp_replay_shared.st'.
Eval [
| replay |
| replay file host dport |
file := Smalltalk arguments at: 1 ifAbsent: [ 'rtpstream.state' ].
host := Smalltalk arguments at: 2 ifAbsent: [ '127.0.0.1' ].
dport := (Smalltalk arguments at: 3 ifAbsent: [ '4000' ]) asInteger.
sport := (Smalltalk arguments at: 4 ifAbsent: [ '0' ]) asInteger.
replay := RTPReplay on: 'rtp_ssrc6976010.240.240.1_to_10.240.240.50.state'.
replay := RTPReplay on: file fromPort: sport.
Transcript nextPutAll: 'Going to stream now'; nl.
replay streamAudio: '127.0.0.1' port: 4000.
replay streamAudio: host port: dport.
]

View File

@@ -42,8 +42,18 @@ Object subclass: RTPReplay [
file: aFile; yourself
]
RTPReplay class >> on: aFile fromPort: aPort [
^ self new
initialize: aPort;
file: aFile; yourself
]
initialize [
socket := Sockets.DatagramSocket new.
self initialize: 0.
]
initialize: aPort [
socket := Sockets.DatagramSocket local: '0.0.0.0' port: aPort.
]
file: aFile [
@@ -59,7 +69,7 @@ Object subclass: RTPReplay [
last_time := nil.
last_image := nil.
file := FileStream open: filename.
file := FileStream open: filename mode: #read.
"Send the payload"
dest := Sockets.SocketAddress byName: aHost.

View File

@@ -5,5 +5,7 @@ Description=OpenBSC MGCP
Type=simple
Restart=always
ExecStart=/usr/bin/osmo-bsc_mgcp -s -c /etc/osmocom/osmo-bsc-mgcp.cfg
Restart=always
RestartSec=2
[Install]
WantedBy=multi-user.target

View File

@@ -1,10 +1,12 @@
[Unit]
Description=OpenBSC BSC
Requires=osmo-bsc-mgcp.service
Wants=osmo-bsc-mgcp.service
[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/osmo-bsc -c /etc/osmocom/osmo-bsc.cfg -s
Restart=always
RestartSec=2
[Install]
WantedBy=multi-user.target

View File

@@ -5,5 +5,7 @@ Description=OpenBSC Network In the Box (NITB)
Type=simple
Restart=always
ExecStart=/usr/bin/osmo-nitb -s -C -c /etc/osmocom/osmo-nitb.cfg -l /var/lib/osmocom/hlr.sqlite3
Restart=always
RestartSec=2
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,11 @@
[Unit]
Description=OpenBSC SGSN
[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/osmo-sgsn -c /etc/osmocom/osmo-sgsn.cfg
RestartSec=2
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,16 @@
OBJS = testconv_main.o
CC = gcc
CFLAGS = -O0 -ggdb -Wall
LDFLAGS =
CPPFLAGS = -I../.. -I../../include $(shell pkg-config --cflags libosmocore) $(shell pkg-config --cflags libbcg729)
LIBS = ../../src/libmgcp/libmgcp.a ../../src/libcommon/libcommon.a $(shell pkg-config --libs libosmocore) $(shell pkg-config --libs libbcg729) -lgsm -lrt
testconv: $(OBJS)
$(CC) -o $@ $^ $(LDFLAGS) $(LIBS)
testconv_main.o: testconv_main.c
$(OBJS):
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<

View File

@@ -0,0 +1,133 @@
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/application.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/mgcp.h>
#include <openbsc/mgcp_internal.h>
#include "bscconfig.h"
#ifndef BUILD_MGCP_TRANSCODING
#error "Requires MGCP transcoding enabled (see --enable-mgcp-transcoding)"
#endif
#include "openbsc/mgcp_transcode.h"
static int audio_name_to_type(const char *name)
{
if (!strcasecmp(name, "gsm"))
return 3;
#ifdef HAVE_BCG729
else if (!strcasecmp(name, "g729"))
return 18;
#endif
else if (!strcasecmp(name, "pcma"))
return 8;
else if (!strcasecmp(name, "l16"))
return 11;
return -1;
}
int mgcp_get_trans_frame_size(void *state_, int nsamples, int dst);
int main(int argc, char **argv)
{
char buf[4096] = {0x80, 0};
int cc, rc;
struct mgcp_rtp_end *dst_end;
struct mgcp_rtp_end *src_end;
struct mgcp_trunk_config tcfg = {{0}};
struct mgcp_endpoint endp = {0};
struct mgcp_process_rtp_state *state;
int in_size;
int in_samples = 160;
int out_samples = 0;
uint32_t ts = 0;
uint16_t seq = 0;
osmo_init_logging(&log_info);
tcfg.endpoints = &endp;
tcfg.number_endpoints = 1;
endp.tcfg = &tcfg;
mgcp_initialize_endp(&endp);
dst_end = &endp.bts_end;
src_end = &endp.net_end;
if (argc <= 2)
errx(1, "Usage: {gsm|g729|pcma|l16} {gsm|g729|pcma|l16} [SPP]");
if ((src_end->codec.payload_type = audio_name_to_type(argv[1])) == -1)
errx(1, "invalid input format '%s'", argv[1]);
if ((dst_end->codec.payload_type = audio_name_to_type(argv[2])) == -1)
errx(1, "invalid output format '%s'", argv[2]);
if (argc > 3)
out_samples = atoi(argv[3]);
if (out_samples) {
dst_end->codec.frame_duration_den = dst_end->codec.rate;
dst_end->codec.frame_duration_num = out_samples;
dst_end->frames_per_packet = 1;
}
rc = mgcp_transcoding_setup(&endp, dst_end, src_end);
if (rc < 0)
errx(1, "setup failed: %s", strerror(-rc));
state = dst_end->rtp_process_data;
OSMO_ASSERT(state != NULL);
in_size = mgcp_transcoding_get_frame_size(state, in_samples, 0);
OSMO_ASSERT(sizeof(buf) >= in_size + 12);
buf[1] = src_end->codec.payload_type;
*(uint16_t*)(buf+2) = htons(1);
*(uint32_t*)(buf+4) = htonl(0);
*(uint32_t*)(buf+8) = htonl(0xaabbccdd);
while ((cc = read(0, buf + 12, in_size))) {
int cont;
int len;
if (cc != in_size)
err(1, "read");
*(uint16_t*)(buf+2) = htonl(seq);
*(uint32_t*)(buf+4) = htonl(ts);
seq += 1;
ts += in_samples;
cc += 12; /* include RTP header */
len = cc;
do {
cont = mgcp_transcoding_process_rtp(&endp, dst_end,
buf, &len, sizeof(buf));
if (cont == -EAGAIN) {
fprintf(stderr, "Got EAGAIN\n");
break;
}
if (cont < 0)
errx(1, "processing failed: %s", strerror(-cont));
len -= 12; /* ignore RTP header */
if (write(1, buf + 12, len) != len)
err(1, "write");
len = cont;
} while (len > 0);
}
return 0;
}

View File

@@ -98,3 +98,8 @@ msc
timeout-ping 20
timeout-pong 5
dest 192.168.100.11 6666 0
access-list-name msc-list
no access-list-name
bsc
no access-list-name
access-list-name bsc-list

View File

@@ -11,8 +11,8 @@ mgcp
bts ip 172.16.252.43
bind ip 127.0.0.1
bind port 2427
bind early 1
rtp base 4000
rtp force-ptime 20
sdp audio payload number 98
sdp audio payload name AMR/8000
number endpoints 31

View File

@@ -0,0 +1 @@
678012512671923:6:6:

View File

@@ -1,3 +1,72 @@
nat
!
! OsmoBSCNAT (0.12.0.266-2daa9) configuration saved from vty
!!
!
log stderr
logging filter all 1
logging color 1
logging timestamp 0
logging level all everything
logging level rll notice
logging level cc notice
logging level mm notice
logging level rr notice
logging level rsl notice
logging level nm info
logging level mncc notice
logging level pag notice
logging level meas notice
logging level sccp notice
logging level msc notice
logging level mgcp notice
logging level ho notice
logging level db notice
logging level ref notice
logging level gprs everything
logging level ns info
logging level bssgp everything
logging level llc everything
logging level sndcp everything
logging level nat notice
logging level ctrl notice
logging level smpp everything
logging level lglobal notice
logging level llapd notice
logging level linp notice
logging level lmux notice
logging level lmi notice
logging level lmib notice
logging level lsms notice
!
line vty
no login
!
mgcp
call agent ip 127.0.0.1
bind ip 0.0.0.0
bind port 2427
rtp bts-base 4000
rtp net-base 16000
rtp ip-dscp 0
no rtcp-omit
sdp audio-payload number 126
sdp audio-payload name AMR/8000
loop 0
number endpoints 1
call-agent ip 127.0.0.1
rtp transcoder-base 0
transcoder-remote-base 4000
nat
msc ip 127.0.0.1
msc port 5000
timeout auth 2
timeout ping 20
timeout pong 5
ip-dscp 0
access-list bla imsi-allow ^11$
bsc 0
token bla
location_area_code 1234
description bsc
max-endpoints 32
paging forbidden 0

View File

@@ -1,90 +0,0 @@
!
! OpenBSC (0.9.11.261-32c0) configuration saved from vty
!!
password foo
!
line vty
no login
!
e1_input
e1_line 0 driver hsl
network
network country code 262
mobile network code 42
short name OpenBSC
long name OpenBSC
auth policy closed
location updating reject cause 13
encryption a5 0
neci 1
paging any use tch 0
rrlp mode none
mm info 0
handover 0
handover window rxlev averaging 10
handover window rxqual averaging 1
handover window rxlev neighbor averaging 10
handover power budget interval 6
handover power budget hysteresis 3
handover maximum distance 9999
timer t3101 10
timer t3103 0
timer t3105 0
timer t3107 0
timer t3109 4
timer t3111 0
timer t3113 60
timer t3115 0
timer t3117 0
timer t3119 0
timer t3122 0
timer t3141 0
dtx-used 1
subscriber-keep-in-ram 0
bts 0
type hsl_femto
band DCS1800
cell_identity 0
location_area_code 1
training_sequence_code 0
base_station_id_code 0
ms max power 15
cell reselection hysteresis 4
rxlev access min 0
channel allocator ascending
rach tx integer 9
rach max transmission 1
hsl serial-number 8303701
neighbor-list mode automatic
oml hsl line 0
gprs mode none
trx 0
rf_locked 0
arfcn 871
nominal power 23
max_power_red 20
rsl e1 tei 0
timeslot 0
phys_chan_config CCCH+SDCCH4
hopping enabled 0
timeslot 1
phys_chan_config TCH/F
hopping enabled 0
timeslot 2
phys_chan_config TCH/F
hopping enabled 0
timeslot 3
phys_chan_config TCH/F
hopping enabled 0
timeslot 4
phys_chan_config TCH/F
hopping enabled 0
timeslot 5
phys_chan_config TCH/F
hopping enabled 0
timeslot 6
phys_chan_config TCH/F
hopping enabled 0
timeslot 7
phys_chan_config TCH/F
hopping enabled 0

View File

@@ -6,8 +6,8 @@ line vty
no login
!
sgsn
gtp local-ip 10.23.23.23
ggsn 0 remote-ip 192.168.0.101
gtp local-ip 127.0.0.1
ggsn 0 remote-ip 127.0.0.1
ggsn 0 gtp-version 1
!
ns
@@ -18,7 +18,7 @@ ns
timer tns-test 30
timer tns-alive 3
timer tns-alive-retries 10
encapsulation udp local-ip 192.168.0.101
encapsulation udp local-ip 127.0.0.1
encapsulation udp local-port 23000
encapsulation framerelay-gre enabled 0
!

View File

@@ -0,0 +1,444 @@
GPRS Subscriber Update Protocol
1. General
This document describes the remote protocol that is used by the SGSN to update
and manage the local subscriber list. The protocol and the messages are
designed after the corresponding MAP messages (see GSM 09.02) with the
following differences:
- The encoding uses TLV structures instead of ASN.1 encodings
- Segmentation is not used
See the specification of the Gr interface (GSM 03.60).
2. Connection
The protocol expects that a reliable, ordered, packet boundaries preserving
connection is used (e.g. IPA over TCP). The remote peer is either a service
that understands the protocol natively or a wrapper service that maps the
messages to/from real MAP messages that can be used to directly communicate
with an HLR.
2.1. Using IPA
By default, the following identifiers should be used:
- IPA protocol: 0xee (OSMO)
- IPA OSMO protocol extension: 0x05
2. Procedures
2.1. Authentication management
The SGSN sends a SEND_AUTHENTICATION_INFO_REQ message containing the MS's IMSI
to the peer. On errors, especially if authentication info is not availabe for
that IMSI, the peer returns a SEND_AUTHENTICATION_INFO_ERR message. Otherwise
the peer returns a SEND_AUTHENTICATION_INFO_RES message. If this message
contains at least one authentication tuple, the SGSN replaces all tuples that
are assigned to the subscriber. If the message doesn't contain any tuple the
SGSN may reject the Attach Request. (see GSM 09.02, 25.5.6)
2.2. Location Updating
The SGSN sends a UPDATE_LOCATION_REQ to the peer. If the request is denied by
the network, the peer returns an UPDATE_LOCATION_ERR message to the SGSN.
Otherwise the peer returns an UPDATE_LOCATION_RES message containing all
information fields that shall be inserted into the subscriber record. If
the 'PDP info complete' information element is set in the message, the SGSN
clears existing PDP information fields in the subscriber record first.
(see GSM 09.02, 19.1.1.8)
[...]
3. Message Format
3.1. General
Every message is based on the following message format
IEI Info Element Type Pres. Format Length
Message type 4.2.1 M V 1
01 IMSI 4.2.9 M TLV 2-10
If a numeric range is indicated in the 'presence' column, multiple information
elements with the same tag may be used in sequence. The information elements
shall be sent in the given order. Nevertheless after the generic part the
receiver shall be able to received them in any order. Unknown IE shall be
ignored.
3.2.1. Send Authentication Info Request
SGSN -> Network peer
IEI Info Element Type Pres. Format Length
Message type 4.2.1 M V 1
01 IMSI 4.2.9 M TLV 2-10
3.2.2. Send Authentication Info Error
Network peer -> SGSN
IEI Info Element Type Pres. Format Length
Message type 4.2.1 M V 1
01 IMSI 4.2.9 M TLV 2-10
02 Cause GMM cause, M TLV 3
04.08: 10.5.5.14
3.2.3. Send Authentication Info Response
Network peer -> SGSN
IEI Info Element Type Pres. Format Length
Message type 4.2.1 M V 1
01 IMSI 4.2.9 M TLV 2-10
03 Auth tuple 4.2.5 0-5 TLV 36
3.2.4. Update Location Request
SGSN -> Network peer
IEI Info Element Type Pres. Format Length
Message type 4.2.1 M V 1
01 IMSI 4.2.9 M TLV 2-10
3.2.5. Update Location Error
Network peer -> SGSN
IEI Info Element Type Pres. Format Length
Message type 4.2.1 M V 1
01 IMSI 4.2.9 M TLV 2-10
02 Cause GMM cause, M TLV 3
04.08: 10.5.5.14
3.2.6. Update Location Result
Network peer -> SGSN
IEI Info Element Type Pres. Format Length
Message type 4.2.1 M V 1
01 IMSI 4.2.9 M TLV 2-10
08 MSISDN 4.2.10 O TLV 0-9
04 PDP info complete 4.2.8 O TLV 2
05 PDP info 4.2.3 1-10 TLV
If the PDP info complete IE is present, the old PDP info list shall be cleared.
3.2.7. Location Cancellation Request
Network peer -> SGSN
IEI Info Element Type Pres. Format Length
Message type 4.2.1 M V 1
01 IMSI 4.2.9 M TLV 2-10
06 Cancellation type 4.2.6 M TLV 3
3.2.8. Location Cancellation Result
SGSN -> Network peer
IEI Info Element Type Pres. Format Length
Message type 4.2.1 M V 1
01 IMSI 4.2.9 M TLV 2-10
3.2.9. Purge MS Request
SGSN -> Network peer
IEI Info Element Type Pres. Format Length
Message type 4.2.1 M V 1
01 IMSI 4.2.9 M TLV 2-10
3.2.10. Purge MS Error
Network peer -> SGSN
IEI Info Element Type Pres. Format Length
Message type 4.2.1 M V 1
01 IMSI 4.2.9 M TLV 2-10
02 Cause GMM cause, M TLV 3
04.08: 10.5.5.14
3.2.11. Purge MS Result
Network peer -> SGSN
IEI Info Element Type Pres. Format Length
Message type 4.2.1 M V 1
01 IMSI 4.2.9 M TLV 2-10
07 Freeze P-TMSI 4.2.8 O TLV 2
3.2.12. Insert Subscriber Data Request
Network peer -> SGSN
IEI Info Element Type Pres. Format Length
Message type 4.2.1 M V 1
01 IMSI 4.2.9 M TLV 2-10
04 PDP info complete 4.2.8 O TLV 2
05 PDP info 4.2.3 0-10 TLV
If the PDP info complete IE is present, the old PDP info list shall be cleared.
3.2.13. Insert Subscriber Data Error
SGSN -> Network peer
IEI Info Element Type Pres. Format Length
Message type 4.2.1 M V 1
01 IMSI 4.2.9 M TLV 2-10
02 Cause GMM cause, M TLV 3
04.08: 10.5.5.14
3.2.14. Insert Subscriber Data Result
SGSN -> Network peer
IEI Info Element Type Pres. Format Length
Message type 4.2.1 M V 1
01 IMSI 4.2.9 M TLV 2-10
3.2.15. Delete Subscriber Data Request
Network peer -> SGSN
IEI Info Element Type Pres. Format Length
Message type 4.2.1 M V 1
01 IMSI 4.2.9 M TLV 2-10
10 PDP context id 4.2.3 0-10 TLV
(no conditional IE)
3.2.16. Delete Subscriber Data Error
SGSN -> Network peer
IEI Info Element Type Pres. Format Length
Message type 4.2.1 M V 1
01 IMSI 4.2.9 M TLV 2-10
02 Cause GMM cause, M TLV 3
04.08: 10.5.5.14
3.2.17. Delete Subscriber Data Result
Network peer -> SGSN
IEI Info Element Type Pres. Format Length
Message type 4.2.1 M V 1
01 IMSI 4.2.9 M TLV 2-10
4. Information Elements
4.1. General
[...]
4.2.1. Message Type
+---------------------------------------------------+
| 8 7 6 5 4 3 2 1 |
| |
| 0 0 0 0 0 1 0 0 - Update Location Request |
| 0 0 0 0 0 1 0 1 - Update Location Error |
| 0 0 0 0 0 1 1 0 - Update Location Result |
| |
| 0 0 0 0 1 0 0 0 - Send Auth Info Request |
| 0 0 0 0 1 0 0 1 - Send Auth Info Error |
| 0 0 0 0 1 0 1 0 - Send Auth Info Result |
| |
| 0 0 0 0 1 1 0 0 - Purge MS Request |
| 0 0 0 0 1 1 0 1 - Purge MS Error |
| 0 0 0 0 1 1 1 0 - Purge MS Result |
| |
| 0 0 0 1 0 0 0 0 - Insert Subscr. Data Request |
| 0 0 0 1 0 0 0 1 - Insert Subscr. Data Error |
| 0 0 0 1 0 0 1 0 - Insert Subscr. Data Result |
| |
| 0 0 0 1 0 1 0 0 - Delete Subscr. Data Request |
| 0 0 0 1 0 1 0 1 - Delete Subscr. Data Error |
| 0 0 0 1 0 1 1 0 - Delete Subscr. Data Result |
| |
| 0 0 0 1 1 1 0 0 - Location Cancellation Request |
| 0 0 0 1 1 1 0 1 - Location Cancellation Error |
| 0 0 0 1 1 1 1 0 - Location Cancellation Result |
| |
+---------------------------------------------------+
4.2.2. IP Address
The value part is encoded like in the Packet data protocol address IE defined
in GSM 04.08, 10.5.6.4. PDP type organization must be set to 'IETF allocated
address'.
4.2.3. PDP Info
This is a container for information elements describing a single PDP.
IEI Info Element Type Pres. Format Length
PDP Info IEI M V 1
Length of PDP Info IE length, no ext M V 1
10 PDP context id big endian int, 1-N C TLV 3
11 PDP type 4.2.4 C TLV 4
12 Access point name 04.08, 10.5.6.1 C TLV 3-102
13 Quality of Service 4.2.11 O TLV 1-20
The conditional IE are mandantory unless mentioned otherwise.
4.2.4. PDP Type
The PDP type value consists of 2 octets that are encoded like octet 4-5 of the
End User Address defined in GSM 09.60, 7.9.18.
8 7 6 5 4 3 2 1
+-----------------------------------------------------+
| | PDP type IEI | octet 1
+-----------------------------------------------------+
| Length of PDP type IE contents (2) | octet 2
+-----------------------------------------------------+
| Spare | PDP type org. | octet 3
+-----------------------------------------------------+
| PDP type number | octet 4
+-----------------------------------------------------+
The spare bits are left undefined. While 09.60 defines them as '1 1 1 1', there
are MAP traces where these bits are set to '0 0 0 0'. So the receiver shall
ignore these bits.
Examples:
IPv4: PDP type org: 1 (IETF), PDP type number: 0x21
IPv6: PDP type org: 1 (IETF), PDP type number: 0x57
4.2.5. Auth tuple
This is a container for information elements describing a single authentication
tuple.
IEI Info Element Type Pres. Format Length
Auth. Tuple IEI M V 1
Length of Ath Tuple IE length, no ext M V 1
20 RAND octet string (16) M TLV 18
21 SRES octet string (4) M TLV 6
22 Kc octet string (8) M TLV 10
4.2.6. Cancellation Type
8 7 6 5 4 3 2 1
+-----------------------------------------------------+
| | Cancellation type IEI | octet 1
+-----------------------------------------------------+
| Length of Cancellation Type IE contents (1) | octet 2
+-----------------------------------------------------+
| Cancellation type number | octet 4
+-----------------------------------------------------+
Where the cancellation type number is:
+---------------------------------------------------+
| 8 7 6 5 4 3 2 1 |
| |
| 0 0 0 0 0 0 0 0 - Update Procedure |
| 0 0 0 0 0 0 0 1 - Subscription Withdraw |
+---------------------------------------------------+
4.2.7. IE Identifier (informational)
These are the standard values for the IEI. See the message definitions for the
IEI that shall be used for the encoding.
+---------------------------------------------------------+
| IEI Info Element Type |
| |
| 0x01 IMSI Mobile identity, 04.08: 10.5.1.4 |
| 0x02 Cause GMM cause, 04.08: 10.5.5.14 |
| 0x03 Auth tuple 4.2.5 |
| 0x04 PDP info compl 4.2.8 |
| 0x05 PDP info 4.2.3 |
| 0x06 Cancel type 4.2.6 |
| 0x07 Freeze P-TMSI 4.2.8 |
| 0x08 MSISDN ISDN-AddressString/octet, 4.2.10 |
| 0x10 PDP context id big endian int |
| 0x11 PDP type 4.2.4 |
| 0x12 APN 04.08, 10.5.6.1 |
| 0x13 QoS 4.2.11 |
| 0x20 RAND octet string |
| 0x21 SRES octet string |
| 0x22 Kc octet string |
+---------------------------------------------------------+
4.2.8 Empty field
This is used for flags, if and only if this IE is present, the flag is set.
The semantics depend on the IEI and the context.
8 7 6 5 4 3 2 1
+-----------------------------------------------------+
| | IEI | octet 1
+-----------------------------------------------------+
| Length of IE contents (0) | octet 2
+-----------------------------------------------------+
4.2.9. IMSI
The IMSI is encoded like in octet 4-N of the Called Party BCD Number defined in GSM 04.08, 10.5.4.7.
8 7 6 5 4 3 2 1
+-----------------------------------------------------+
| | IMSI IEI | octet 1
+-----------------------------------------------------+
| Length of IMSI IE contents | octet 2
+-----------------------------------------------------+
| Number digit 2 | Number digit 1 | octet 3
+-----------------------------------------------------+
| Number digit 4 | Number digit 3 | octet 4
+-----------------------------------------------------+
: : :
+-----------------------------------------------------+
| see note 1) | octet 2+(N+1)div2
+-----------------------------------------------------+
Note 1) Either '1 1 1 1 | Number digit N' (N odd) or
'Number digit N | Number digit N-1' (N even),
where N is the number of digits.
4.2.10. ISDN-AddressString / MSISDN / Called Party BCD Number
The MSISDN is encoded as an ISDN-AddressString in GSM 09.02 and Called Party
BCD Number in GSM 04.08. It will be stored by the SGSN and then passed as is
to the GGSN during the activation of the primary PDP Context.
8 7 6 5 4 3 2 1
+-----------------------------------------------------+
| | IEI | octet 1
+-----------------------------------------------------+
| Length of IE contents | octet 2
+-----------------------------------------------------+
| ext | Type of num | Numbering plan | octet 2
+-----------------------------------------------------+
| Number digit 2 | Number digit 1 | octet 3
+-----------------------------------------------------+
| Number digit 4 | Number digit 3 | octet 4
+-----------------------------------------------------+
: : :
+-----------------------------------------------------+
4.2.11 Quality of Service Subscribed Service
This encodes the subscribed QoS of a subscriber. It will be used by the
SGSN during the PDP Context activation. If the length of the QoS data
is 3 (three) octets it is assumed that these are octets 3-5 of the TS
3GPP TS 24.008 Quality of Service Octets. If it is more than three then
then it is assumed that the first octet is the Allocation/Retention
Priority and the reset are encoded as octets 3-N of 24.008.
8 7 6 5 4 3 2 1
+-----------------------------------------------------+
| | IEI | octet 1
+-----------------------------------------------------+
| Length of IE contents | octet 2
+-----------------------------------------------------+
: : :
+-----------------------------------------------------+

View File

@@ -1,19 +1,22 @@
noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \
gsm_subscriber.h gsm_04_11.h debug.h signal.h \
misdn.h chan_alloc.h paging.h \
misdn.h chan_alloc.h paging.h ctrl.h \
trau_mux.h rs232.h openbscdefines.h rtp_proxy.h \
bsc_rll.h mncc.h transaction.h ussd.h gsm_04_80.h \
silent_call.h mgcp.h meas_rep.h rest_octets.h \
system_information.h handover.h mgcp_internal.h \
vty.h socket.h e1_config.h trau_upqueue.h token_auth.h \
handover_decision.h rrlp.h control_if.h \
handover_decision.h rrlp.h \
crc24.h gprs_llc.h gprs_gmm.h \
gb_proxy.h gprs_sgsn.h gsm_04_08_gprs.h sgsn.h \
auth.h osmo_msc.h bsc_msc.h bsc_nat.h \
osmo_bsc_rf.h osmo_bsc.h network_listen.h bsc_nat_sccp.h \
osmo_msc_data.h osmo_bsc_grace.h sms_queue.h abis_om2000.h \
bss.h gsm_data_shared.h control_cmd.h ipaccess.h mncc_int.h \
arfcn_range_encode.h
bss.h gsm_data_shared.h ipaccess.h mncc_int.h \
arfcn_range_encode.h nat_rewrite_trie.h bsc_nat_callstats.h \
osmux.h mgcp_transcode.h gprs_utils.h \
gprs_gb_parse.h smpp.h meas_feed.h gprs_gsup_messages.h \
gprs_gsup_client.h bsc_msg_filter.h
openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h
openbscdir = $(includedir)/openbsc

View File

@@ -183,4 +183,7 @@ int abis_nm_parse_sw_config(const uint8_t *data, const size_t len,
struct abis_nm_sw_descr *res, const int res_len);
int abis_nm_select_newest_sw(const struct abis_nm_sw_descr *sw, const size_t len);
/* Helper functions for updating attributes */
int abis_nm_update_max_power_red(struct gsm_bts_trx *trx);
#endif /* _NM_H */

View File

@@ -43,7 +43,7 @@ int rsl_chan_activate(struct gsm_bts_trx *trx, uint8_t chan_nr,
uint8_t bs_power, uint8_t ms_power,
uint8_t ta);
int rsl_chan_activate_lchan(struct gsm_lchan *lchan, uint8_t act_type,
uint8_t ta, uint8_t ho_ref);
uint8_t ho_ref);
int rsl_chan_mode_modify_req(struct gsm_lchan *ts);
int rsl_encryption_cmd(struct msgb *msg);
int rsl_paging_cmd(struct gsm_bts *bts, uint8_t paging_group, uint8_t len,
@@ -71,6 +71,7 @@ int rsl_release_request(struct gsm_lchan *lchan, uint8_t link_id,
enum rsl_rel_mode release_mode);
int rsl_lchan_set_state(struct gsm_lchan *lchan, int);
int rsl_lchan_mark_broken(struct gsm_lchan *lchan, const char *broken);
/* to be provided by external code */
int rsl_deact_sacch(struct gsm_lchan *lchan);
@@ -87,7 +88,8 @@ int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int dbm);
/* SMSCB functionality */
int rsl_sms_cb_command(struct gsm_bts *bts, uint8_t chan_number,
uint8_t cb_command, const uint8_t *data, int len);
struct rsl_ie_cb_cmd_type cb_command,
const uint8_t *data, int len);
/* some Nokia specific stuff */
int rsl_nokia_si_begin(struct gsm_bts_trx *trx);

View File

@@ -16,7 +16,7 @@ enum {
int range_enc_determine_range(const int *arfcns, int size, int *f0_out);
int range_enc_arfcns(const int rng, const int *arfcns, int sze, int *out, int idx);
int range_enc_find_index(const int rng, const int *arfcns, int size);
int range_enc_filter_arfcns(const int rng, int *arfcns, const int sze, const int f0, int *f0_included);
int range_enc_filter_arfcns(int *arfcns, const int sze, const int f0, int *f0_included);
int range_enc_range128(uint8_t *chan_list, int f0, int *w);
int range_enc_range256(uint8_t *chan_list, int f0, int *w);

View File

@@ -40,7 +40,7 @@ struct bsc_api {
* not implemented AMR5.9 will be used.
*/
void (*mr_config)(struct gsm_subscriber_connection *conn,
struct gsm48_multi_rate_conf *conf);
uint8_t *mr_ms_lv, uint8_t *mr_bts_lv);
};
int bsc_api_init(struct gsm_network *network, struct bsc_api *api);
@@ -52,4 +52,6 @@ int gsm0808_page(struct gsm_bts *bts, unsigned int page_group,
unsigned int mi_len, uint8_t *mi, int chan_type);
int gsm0808_clear(struct gsm_subscriber_connection *conn);
struct llist_head *bsc_api_sub_connections(struct gsm_network *net);
#endif

View File

@@ -25,6 +25,8 @@
#include <osmocom/core/write_queue.h>
#include <osmocom/core/timer.h>
#include <netinet/in.h>
struct bsc_msc_dest {
struct llist_head list;
@@ -42,10 +44,14 @@ struct bsc_msc_connection {
struct llist_head *dests;
const char *name;
void (*connection_loss) (struct bsc_msc_connection *);
void (*connected) (struct bsc_msc_connection *);
struct osmo_timer_list reconnect_timer;
struct osmo_timer_list timeout_timer;
struct msgb *pending_msg;
};
struct bsc_msc_connection *bsc_msc_create(void *ctx, struct llist_head *dest);

View File

@@ -0,0 +1,107 @@
#pragma once
#include <osmocom/core/msgb.h>
#include <osmocom/core/msgfile.h>
#include <osmocom/core/linuxrbtree.h>
#include <osmocom/core/linuxlist.h>
#include <regex.h>
struct vty;
struct gsm48_hdr;
struct bsc_filter_reject_cause {
int lu_reject_cause;
int cm_reject_cause;
};
struct bsc_filter_barr_entry {
struct rb_node node;
char *imsi;
int cm_reject_cause;
int lu_reject_cause;
};
enum bsc_filter_acc_ctr {
ACC_LIST_LOCAL_FILTER,
ACC_LIST_GLOBAL_FILTER,
};
struct bsc_msg_acc_lst {
struct llist_head list;
/* counter */
struct rate_ctr_group *stats;
/* the name of the list */
const char *name;
struct llist_head fltr_list;
};
struct bsc_msg_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;
/* reject reasons for the access lists */
int cm_reject_cause;
int lu_reject_cause;
};
enum {
FLT_CON_TYPE_NONE,
FLT_CON_TYPE_LU,
FLT_CON_TYPE_CM_SERV_REQ,
FLT_CON_TYPE_PAG_RESP,
FLT_CON_TYPE_SSA,
FLT_CON_TYPE_LOCAL_REJECT,
FLT_CON_TYPE_OTHER,
};
struct bsc_filter_state {
char *imsi;
int imsi_checked;
int con_type;
};
struct bsc_filter_request {
void *ctx;
struct rb_root *black_list;
struct llist_head *access_lists;
const char *local_lst_name;
const char *global_lst_name;
int bsc_nr;
};
int bsc_filter_barr_adapt(void *ctx, struct rb_root *rbtree, const struct osmo_config_list *);
int bsc_filter_barr_find(struct rb_root *root, const char *imsi, int *cm, int *lu);
/**
* Content filtering.
*/
int bsc_msg_filter_initial(struct gsm48_hdr *hdr, size_t size,
struct bsc_filter_request *req,
int *con_type, char **imsi,
struct bsc_filter_reject_cause *cause);
int bsc_msg_filter_data(struct gsm48_hdr *hdr, size_t size,
struct bsc_filter_request *req,
struct bsc_filter_state *state,
struct bsc_filter_reject_cause *cause);
/* IMSI allow/deny handling */
struct bsc_msg_acc_lst *bsc_msg_acc_lst_find(struct llist_head *lst, const char *name);
struct bsc_msg_acc_lst *bsc_msg_acc_lst_get(void *ctx, struct llist_head *lst, const char *name);
void bsc_msg_acc_lst_delete(struct bsc_msg_acc_lst *lst);
struct bsc_msg_acc_lst_entry *bsc_msg_acc_lst_entry_create(struct bsc_msg_acc_lst *);
int bsc_msg_acc_lst_check_allow(struct bsc_msg_acc_lst *lst, const char *imsi);
void bsc_msg_lst_vty_init(void *ctx, struct llist_head *lst, int node);
void bsc_msg_acc_lst_write(struct vty *vty, struct bsc_msg_acc_lst *lst);

View File

@@ -22,6 +22,7 @@
#define BSC_NAT_H
#include "mgcp.h"
#include "bsc_msg_filter.h"
#include <osmocom/core/select.h>
@@ -41,20 +42,11 @@
#define PAGIN_GROUP_UNASSIGNED -1
struct sccp_source_reference;
struct sccp_connections;
struct nat_sccp_connection;
struct bsc_nat_parsed;
struct bsc_nat;
struct bsc_nat_ussd_con;
enum {
NAT_CON_TYPE_NONE,
NAT_CON_TYPE_LU,
NAT_CON_TYPE_CM_SERV_REQ,
NAT_CON_TYPE_PAG_RESP,
NAT_CON_TYPE_SSA,
NAT_CON_TYPE_LOCAL_REJECT,
NAT_CON_TYPE_OTHER,
};
struct nat_rewrite_rule;
/*
* Is this terminated to the MSC, to the local machine (release
@@ -96,6 +88,9 @@ struct bsc_connection {
/* the fd we use to communicate */
struct osmo_wqueue write_queue;
/* incoming message buffer */
struct msgb *pending_msg;
/* the BSS associated */
struct bsc_config *cfg;
@@ -111,6 +106,9 @@ struct bsc_connection {
int number_multiplexes;
int max_endpoints;
int last_endpoint;
int next_transaction;
uint32_t pending_dlcx_count;
struct llist_head pending_dlcx;
/* track the pending commands for this BSC */
struct llist_head cmd_pending;
@@ -169,6 +167,9 @@ struct bsc_config {
struct bsc_config_stats stats;
struct llist_head lac_list;
/* Osmux is enabled/disabled per BSC */
int osmux;
};
struct bsc_lac_entry {
@@ -219,32 +220,6 @@ struct bsc_nat_statistics {
} ussd;
};
enum bsc_nat_acc_ctr {
ACC_LIST_BSC_FILTER,
ACC_LIST_NAT_FILTER,
};
struct bsc_nat_acc_lst {
struct llist_head list;
/* counter */
struct rate_ctr_group *stats;
/* 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
*/
@@ -270,6 +245,8 @@ struct bsc_nat {
struct mgcp_config *mgcp_cfg;
uint8_t mgcp_msg[4096];
int mgcp_length;
int mgcp_ipa;
int sdp_ensure_amr_mode_set;
/* msc things */
struct llist_head dests;
@@ -294,6 +271,8 @@ struct bsc_nat {
/* number rewriting */
char *num_rewr_name;
struct llist_head num_rewr;
char *num_rewr_post_name;
struct llist_head num_rewr_post;
char *smsc_rewr_name;
struct llist_head smsc_rewr;
@@ -304,6 +283,10 @@ struct bsc_nat {
char *sms_num_rewr_name;
struct llist_head sms_num_rewr;
/* more rewriting */
char *num_rewr_trie_name;
struct nat_rewrite *num_rewr_trie;
/* USSD messages we want to match */
char *ussd_lst_name;
char *ussd_query;
@@ -328,12 +311,9 @@ struct bsc_nat_ussd_con {
struct bsc_nat *nat;
int authorized;
struct osmo_timer_list auth_timeout;
};
struct msgb *pending_msg;
struct bsc_nat_reject_cause {
int lu_reject_cause;
int cm_reject_cause;
struct osmo_timer_list auth_timeout;
};
/* create and init the structures */
@@ -348,7 +328,7 @@ struct bsc_nat *bsc_nat_alloc(void);
struct bsc_connection *bsc_connection_alloc(struct bsc_nat *nat);
void bsc_nat_set_msc_ip(struct bsc_nat *bsc, const char *ip);
void sccp_connection_destroy(struct sccp_connections *);
void sccp_connection_destroy(struct nat_sccp_connection *);
void bsc_close_connection(struct bsc_connection *);
const char *bsc_con_type_to_string(int type);
@@ -365,39 +345,30 @@ int bsc_nat_filter_ipa(int direction, struct msgb *msg, struct bsc_nat_parsed *p
int bsc_nat_vty_init(struct bsc_nat *nat);
int bsc_nat_find_paging(struct msgb *msg, const uint8_t **,int *len);
/**
* Content filtering.
*/
int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg,
struct bsc_nat_parsed *, int *con_type, char **imsi,
struct bsc_nat_reject_cause *cause);
int bsc_nat_filter_dt(struct bsc_connection *bsc, struct msgb *msg,
struct sccp_connections *con, struct bsc_nat_parsed *parsed,
struct bsc_nat_reject_cause *cause);
/**
* SCCP patching and handling
*/
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);
struct nat_sccp_connection *create_sccp_src_ref(struct bsc_connection *bsc, struct bsc_nat_parsed *parsed);
int update_sccp_src_ref(struct nat_sccp_connection *sccp, struct bsc_nat_parsed *parsed);
void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed);
struct sccp_connections *patch_sccp_src_ref_to_bsc(struct msgb *, struct bsc_nat_parsed *, struct bsc_nat *);
struct sccp_connections *patch_sccp_src_ref_to_msc(struct msgb *, struct bsc_nat_parsed *, struct bsc_connection *);
struct sccp_connections *bsc_nat_find_con_by_bsc(struct bsc_nat *, struct sccp_source_reference *);
struct nat_sccp_connection *patch_sccp_src_ref_to_bsc(struct msgb *, struct bsc_nat_parsed *, struct bsc_nat *);
struct nat_sccp_connection *patch_sccp_src_ref_to_msc(struct msgb *, struct bsc_nat_parsed *, struct bsc_connection *);
struct nat_sccp_connection *bsc_nat_find_con_by_bsc(struct bsc_nat *, struct sccp_source_reference *);
/**
* MGCP/Audio handling
*/
int bsc_mgcp_nr_multiplexes(int max_endpoints);
int bsc_write_mgcp(struct bsc_connection *bsc, const uint8_t *data, unsigned int length);
int bsc_mgcp_assign_patch(struct sccp_connections *, struct msgb *msg);
void bsc_mgcp_init(struct sccp_connections *);
void bsc_mgcp_dlcx(struct sccp_connections *);
int bsc_mgcp_assign_patch(struct nat_sccp_connection *, struct msgb *msg);
void bsc_mgcp_init(struct nat_sccp_connection *);
void bsc_mgcp_dlcx(struct nat_sccp_connection *);
void bsc_mgcp_free_endpoints(struct bsc_nat *nat);
int bsc_mgcp_nat_init(struct bsc_nat *nat);
struct sccp_connections *bsc_mgcp_find_con(struct bsc_nat *, int endpoint_number);
struct msgb *bsc_mgcp_rewrite(char *input, int length, int endp, const char *ip, int port);
struct nat_sccp_connection *bsc_mgcp_find_con(struct bsc_nat *, int endpoint_number);
struct msgb *bsc_mgcp_rewrite(char *input, int length, int endp, const char *ip,
int port, int osmux, int *payload_type, int mode_set);
void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg);
void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc);
@@ -410,24 +381,16 @@ int bsc_do_write(struct osmo_wqueue *queue, struct msgb *msg, int id);
int bsc_write_msg(struct osmo_wqueue *queue, struct msgb *msg);
int bsc_write_cb(struct osmo_fd *bfd, struct msgb *msg);
/* IMSI allow/deny handling */
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 *);
int bsc_nat_lst_check_allow(struct bsc_nat_acc_lst *lst, const char *imsi);
int bsc_nat_msc_is_connected(struct bsc_nat *nat);
int bsc_conn_type_to_ctr(struct sccp_connections *conn);
int bsc_conn_type_to_ctr(struct nat_sccp_connection *conn);
struct gsm48_hdr *bsc_unpack_dtap(struct bsc_nat_parsed *parsed, struct msgb *msg, uint32_t *len);
/** USSD filtering */
int bsc_ussd_init(struct bsc_nat *nat);
int bsc_check_ussd(struct sccp_connections *con, struct bsc_nat_parsed *parsed, struct msgb *msg);
int bsc_close_ussd_connections(struct bsc_nat *nat);
int bsc_ussd_check(struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed, struct msgb *msg);
int bsc_ussd_close_connections(struct bsc_nat *nat);
struct msgb *bsc_nat_rewrite_msg(struct bsc_nat *nat, struct msgb *msg, struct bsc_nat_parsed *, const char *imsi);
@@ -448,23 +411,36 @@ struct bsc_nat_num_rewr_entry {
regex_t num_reg;
char *replace;
uint8_t is_prefix_lookup;
};
void bsc_nat_num_rewr_entry_adapt(void *ctx, struct llist_head *head, const struct osmo_config_list *);
struct bsc_nat_barr_entry {
struct rb_node node;
char *imsi;
int cm_reject_cause;
int lu_reject_cause;
};
int bsc_nat_barr_adapt(void *ctx, struct rb_root *rbtree, const struct osmo_config_list *);
int bsc_nat_barr_find(struct rb_root *root, const char *imsi, int *cm, int *lu);
void bsc_nat_send_mgcp_to_msc(struct bsc_nat *bsc_nat, struct msgb *msg);
void bsc_nat_handle_mgcp(struct bsc_nat *bsc, struct msgb *msg);
struct ctrl_handle *bsc_nat_controlif_setup(struct bsc_nat *nat, int port);
void bsc_nat_ctrl_del_pending(struct bsc_cmd_list *pending);
int bsc_nat_handle_ctrlif_msg(struct bsc_connection *bsc, struct msgb *msg);
int bsc_nat_extract_lac(struct bsc_connection *bsc, struct nat_sccp_connection *con,
struct bsc_nat_parsed *parsed, struct msgb *msg);
int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg,
struct bsc_nat_parsed *, int *con_type, char **imsi,
struct bsc_filter_reject_cause *cause);
int bsc_nat_filter_dt(struct bsc_connection *bsc, struct msgb *msg,
struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed,
struct bsc_filter_reject_cause *cause);
/**
* CTRL interface helper
*/
void bsc_nat_inform_reject(struct bsc_connection *bsc, const char *imsi);
/*
* Use for testing
*/
void bsc_nat_free(struct bsc_nat *nat);
#endif

View File

@@ -0,0 +1,55 @@
/*
* (C) 2010-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010-2012 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef BSC_NAT_CALLSTATS_H
#define BSC_NAT_CALLSTATS_H
#include <osmocom/core/linuxlist.h>
#include <osmocom/sccp/sccp_types.h>
struct bsc_nat_call_stats {
struct llist_head entry;
struct sccp_source_reference remote_ref;
struct sccp_source_reference src_ref; /* as seen by the MSC */
/* mgcp options */
uint32_t ci;
int bts_rtp_port;
int net_rtp_port;
struct in_addr bts_addr;
struct in_addr net_addr;
/* as witnessed by the NAT */
uint32_t net_ps;
uint32_t net_os;
uint32_t bts_pr;
uint32_t bts_or;
uint32_t bts_expected;
uint32_t bts_jitter;
int bts_loss;
uint32_t trans_id;
int msc_endpoint;
};
#endif

View File

@@ -22,6 +22,8 @@
#ifndef BSC_NAT_SCCP_H
#define BSC_NAT_SCCP_H
#include "bsc_msg_filter.h"
#include <osmocom/sccp/sccp_types.h>
/*
@@ -41,6 +43,9 @@ struct bsc_nat_parsed {
/* destination local reference */
struct sccp_source_reference *dest_local_ref;
/* original value */
struct sccp_source_reference original_dest_ref;
/* called ssn number */
int called_ssn;
@@ -62,7 +67,7 @@ struct bsc_nat_parsed {
* be updated on new SCCP connections, connection confirm and reject,
* and on the loss of the BSC connection.
*/
struct sccp_connections {
struct nat_sccp_connection {
struct llist_head list_entry;
struct bsc_connection *bsc;
@@ -74,11 +79,13 @@ struct sccp_connections {
int has_remote_ref;
/* status */
int con_type;
int con_local;
int authorized;
int imsi_checked;
char *imsi;
struct bsc_filter_state filter_state;
uint16_t lac;
uint16_t ci;
/* remember which Transactions we run over the bypass */
char ussd_ti[8];

View File

@@ -13,7 +13,6 @@ extern int bts_init(void);
extern int bts_model_bs11_init(void);
extern int bts_model_rbs2k_init(void);
extern int bts_model_nanobts_init(void);
extern int bts_model_hslfemto_init(void);
extern int bts_model_nokia_site_init(void);
extern int bts_model_sysmobts_init(void);
#endif

View File

@@ -24,17 +24,6 @@
struct gsm_subscriber_connection;
/* Special allocator for C0 of BTS */
struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts,
enum gsm_phys_chan_config pchan);
/* Regular physical channel allocator */
struct gsm_bts_trx_ts *ts_alloc(struct gsm_bts *bts,
enum gsm_phys_chan_config pchan);
/* Regular physical channel (TS) */
void ts_free(struct gsm_bts_trx_ts *ts);
/* Find an allocated channel for a specified subscriber */
struct gsm_subscriber_connection *connection_for_subscr(struct gsm_subscriber *subscr);
@@ -54,7 +43,7 @@ struct load_counter {
};
struct pchan_load {
struct load_counter pchan[GSM_PCHAN_UNKNOWN];
struct load_counter pchan[_GSM_PCHAN_MAX];
};
void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts);

View File

@@ -1,162 +0,0 @@
#ifndef _CONTROL_CMD_H
#define _CONTROL_CMD_H
#include <osmocom/core/msgb.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/vty/vector.h>
#include <openbsc/vty.h>
#define CTRL_CMD_ERROR -1
#define CTRL_CMD_HANDLED 0
#define CTRL_CMD_REPLY 1
struct ctrl_handle;
enum ctrl_node_type {
CTRL_NODE_ROOT, /* Root elements */
CTRL_NODE_BTS, /* BTS specific (net.btsN.) */
CTRL_NODE_TRX, /* TRX specific (net.btsN.trxM.) */
CTRL_NODE_TS, /* TS specific (net.btsN.trxM.tsI.) */
_LAST_CTRL_NODE
};
enum ctrl_type {
CTRL_TYPE_UNKNOWN,
CTRL_TYPE_GET,
CTRL_TYPE_SET,
CTRL_TYPE_GET_REPLY,
CTRL_TYPE_SET_REPLY,
CTRL_TYPE_TRAP,
CTRL_TYPE_ERROR
};
struct ctrl_connection {
struct llist_head list_entry;
/* The queue for sending data back */
struct osmo_wqueue write_queue;
/* Callback if the connection was closed */
void (*closed_cb)(struct ctrl_connection *conn);
/* Pending commands for this connection */
struct llist_head cmds;
};
struct ctrl_cmd {
struct ctrl_connection *ccon;
enum ctrl_type type;
char *id;
void *node;
char *variable;
char *value;
char *reply;
};
struct ctrl_cmd_struct {
int nr_commands;
char **command;
};
struct ctrl_cmd_element {
const char *name;
const char *param;
struct ctrl_cmd_struct strcmd;
int (*set)(struct ctrl_cmd *cmd, void *data);
int (*get)(struct ctrl_cmd *cmd, void *data);
int (*verify)(struct ctrl_cmd *cmd, const char *value, void *data);
};
struct ctrl_cmd_map {
char *cmd;
enum ctrl_type type;
};
int ctrl_cmd_exec(vector vline, struct ctrl_cmd *command, vector node, void *data);
int ctrl_cmd_install(enum ctrl_node_type node, struct ctrl_cmd_element *cmd);
int ctrl_cmd_handle(struct ctrl_cmd *cmd, void *data);
int ctrl_cmd_send(struct osmo_wqueue *queue, struct ctrl_cmd *cmd);
int ctrl_cmd_send_to_all(struct ctrl_handle *ctrl, struct ctrl_cmd *cmd);
struct ctrl_cmd *ctrl_cmd_parse(void *ctx, struct msgb *msg);
struct msgb *ctrl_cmd_make(struct ctrl_cmd *cmd);
struct ctrl_cmd *ctrl_cmd_cpy(void *ctx, struct ctrl_cmd *cmd);
struct ctrl_cmd *ctrl_cmd_create(void *ctx, enum ctrl_type);
struct ctrl_cmd *ctrl_cmd_trap(struct ctrl_cmd *cmd);
#define CTRL_CMD_DEFINE_RANGE(cmdname, cmdstr, dtype, element, min, max) \
static int get_##cmdname(struct ctrl_cmd *cmd, void *_data) \
{ \
dtype *node = cmd->node; \
cmd->reply = talloc_asprintf(cmd, "%i", node->element); \
if (!cmd->reply) { \
cmd->reply = "OOM"; \
return CTRL_CMD_ERROR; \
} \
return CTRL_CMD_REPLY; \
} \
static int set_##cmdname(struct ctrl_cmd *cmd, void *_data) \
{ \
dtype *node = cmd->node; \
int tmp = atoi(cmd->value); \
node->element = tmp; \
return get_##cmdname(cmd, _data); \
} \
static int verify_##cmdname(struct ctrl_cmd *cmd, const char *value, void *_data) \
{ \
int tmp = atoi(value); \
if ((tmp >= min)&&(tmp <= max)) { \
return 0; \
} \
return -1; \
} \
struct ctrl_cmd_element cmd_##cmdname = { \
.name = cmdstr, \
.param = NULL, \
.get = &get_##cmdname, \
.set = &set_##cmdname, \
.verify = &verify_##cmdname, \
}
#define CTRL_CMD_DEFINE_STRING(cmdname, cmdstr, dtype, element) \
static int get_##cmdname(struct ctrl_cmd *cmd, void *_data) \
{ \
dtype *data = cmd->node; \
cmd->reply = talloc_asprintf(cmd, "%s", data->element); \
if (!cmd->reply) { \
cmd->reply = "OOM"; \
return CTRL_CMD_ERROR; \
} \
return CTRL_CMD_REPLY; \
} \
static int set_##cmdname(struct ctrl_cmd *cmd, void *_data) \
{ \
dtype *data = cmd->node; \
bsc_replace_string(cmd->node, &data->element, cmd->value); \
return get_##cmdname(cmd, _data); \
} \
struct ctrl_cmd_element cmd_##cmdname = { \
.name = cmdstr, \
.param = NULL, \
.get = &get_##cmdname, \
.set = &set_##cmdname, \
.verify = NULL, \
}
#define CTRL_CMD_DEFINE(cmdname, cmdstr) \
static int get_##cmdname(struct ctrl_cmd *cmd, void *data); \
static int set_##cmdname(struct ctrl_cmd *cmd, void *data); \
static int verify_##cmdname(struct ctrl_cmd *cmd, const char *value, void *data); \
struct ctrl_cmd_element cmd_##cmdname = { \
.name = cmdstr, \
.param = NULL, \
.get = &get_##cmdname, \
.set = &set_##cmdname, \
.verify = &verify_##cmdname, \
}
struct gsm_network;
#endif /* _CONTROL_CMD_H */

View File

@@ -1,21 +0,0 @@
#ifndef _CONTROL_IF_H
#define _CONTROL_IF_H
#include <osmocom/core/write_queue.h>
#include <openbsc/control_cmd.h>
#include <openbsc/gsm_data.h>
struct ctrl_handle {
struct osmo_fd listen_fd;
struct gsm_network *gsmnet;
/* List of control connections */
struct llist_head ccon_list;
};
int ctrl_cmd_send(struct osmo_wqueue *queue, struct ctrl_cmd *cmd);
int ctrl_cmd_handle(struct ctrl_cmd *cmd, void *data);
struct ctrl_handle *controlif_setup(struct gsm_network *gsmnet, uint16_t port);
#endif /* _CONTROL_IF_H */

View File

@@ -0,0 +1,3 @@
#pragma once
struct ctrl_handle *bsc_controlif_setup(struct gsm_network *net, uint16_t port);

View File

@@ -35,19 +35,19 @@ int db_prepare(void);
int db_fini(void);
/* subscriber management */
struct gsm_subscriber *db_create_subscriber(struct gsm_network *net,
char *imsi);
struct gsm_subscriber *db_get_subscriber(struct gsm_network *net,
enum gsm_subscriber_field field,
struct gsm_subscriber *db_create_subscriber(const char *imsi, uint64_t prefix);
struct gsm_subscriber *db_get_subscriber(enum gsm_subscriber_field field,
const char *subscr);
int db_sync_subscriber(struct gsm_subscriber *subscriber);
int db_subscriber_expire(void *priv, void (*callback)(void *priv, long long unsigned int id));
int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber);
int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber);
int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber, uint64_t prefix);
int db_subscriber_alloc_token(struct gsm_subscriber *subscriber, uint32_t* token);
int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char *imei);
int db_subscriber_delete(struct gsm_subscriber *subscriber);
int db_sync_equipment(struct gsm_equipment *equip);
int db_subscriber_update(struct gsm_subscriber *subscriber);
int db_subscriber_list_active(void (*list_cb)(struct gsm_subscriber*,void*), void*);
/* auth info */
int db_get_authinfo_for_subscr(struct gsm_auth_info *ainfo,
@@ -65,7 +65,7 @@ struct gsm_sms *db_sms_get(struct gsm_network *net, unsigned long long id);
struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, unsigned long long min_id);
struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net, unsigned long long min_subscr_id, unsigned int failed);
struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr);
int db_sms_mark_sent(struct gsm_sms *sms);
int db_sms_mark_delivered(struct gsm_sms *sms);
int db_sms_inc_deliver_attempts(struct gsm_sms *sms);
/* APDU blob storage */

View File

@@ -32,6 +32,7 @@ enum {
DNAT,
DCTRL,
DSMPP,
DFILTER,
Debug_LastEntry,
};
@@ -53,8 +54,9 @@ enum {
/* we don't need a header dependency for this... */
struct gprs_nsvc;
struct bssgp_bvc_ctx;
struct gsm_subscriber;
void log_set_imsi_filter(struct log_target *target, const char *imsi);
void log_set_imsi_filter(struct log_target *target, struct gsm_subscriber *subscr);
void log_set_nsvc_filter(struct log_target *target,
struct gprs_nsvc *nsvc);
void log_set_bvc_filter(struct log_target *target,

View File

@@ -7,16 +7,166 @@
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/vty/command.h>
#include <sys/types.h>
#include <regex.h>
#define GBPROXY_INIT_VU_GEN_TX 256
struct rate_ctr_group;
struct gprs_gb_parse_context;
struct tlv_parsed;
enum gbproxy_global_ctr {
GBPROX_GLOB_CTR_INV_BVCI,
GBPROX_GLOB_CTR_INV_LAI,
GBPROX_GLOB_CTR_INV_RAI,
GBPROX_GLOB_CTR_INV_NSEI,
GBPROX_GLOB_CTR_PROTO_ERR_BSS,
GBPROX_GLOB_CTR_PROTO_ERR_SGSN,
GBPROX_GLOB_CTR_NOT_SUPPORTED_BSS,
GBPROX_GLOB_CTR_NOT_SUPPORTED_SGSN,
GBPROX_GLOB_CTR_RESTART_RESET_SGSN,
GBPROX_GLOB_CTR_TX_ERR_SGSN,
GBPROX_GLOB_CTR_OTHER_ERR,
GBPROX_GLOB_CTR_PATCH_PEER_ERR,
};
enum gbproxy_peer_ctr {
GBPROX_PEER_CTR_BLOCKED,
GBPROX_PEER_CTR_UNBLOCKED,
GBPROX_PEER_CTR_DROPPED,
GBPROX_PEER_CTR_INV_NSEI,
GBPROX_PEER_CTR_TX_ERR,
GBPROX_PEER_CTR_RAID_PATCHED_BSS,
GBPROX_PEER_CTR_RAID_PATCHED_SGSN,
GBPROX_PEER_CTR_APN_PATCHED,
GBPROX_PEER_CTR_TLLI_PATCHED_BSS,
GBPROX_PEER_CTR_TLLI_PATCHED_SGSN,
GBPROX_PEER_CTR_PTMSI_PATCHED_BSS,
GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN,
GBPROX_PEER_CTR_PATCH_CRYPT_ERR,
GBPROX_PEER_CTR_PATCH_ERR,
GBPROX_PEER_CTR_ATTACH_REQS,
GBPROX_PEER_CTR_ATTACH_REJS,
GBPROX_PEER_CTR_TLLI_UNKNOWN,
GBPROX_PEER_CTR_TLLI_CACHE_SIZE,
};
enum gbproxy_keep_mode {
GBPROX_KEEP_NEVER,
GBPROX_KEEP_REATTACH,
GBPROX_KEEP_IDENTIFIED,
GBPROX_KEEP_ALWAYS,
};
enum gbproxy_match_id {
GBPROX_MATCH_PATCHING,
GBPROX_MATCH_ROUTING,
GBPROX_MATCH_LAST
};
struct gbproxy_match {
int enable;
char *re_str;
regex_t re_comp;
};
struct gbproxy_config {
/* parsed from config file */
uint16_t nsip_sgsn_nsei;
/* misc */
struct gprs_ns_inst *nsi;
/* Linked list of all Gb peers (except SGSN) */
struct llist_head bts_peers;
/* Counter */
struct rate_ctr_group *ctrg;
/* force mcc/mnc */
int core_mnc;
int core_mcc;
uint8_t* core_apn;
size_t core_apn_size;
int tlli_max_age;
int tlli_max_len;
/* Experimental config */
int patch_ptmsi;
int acquire_imsi;
int route_to_sgsn2;
uint16_t nsip_sgsn2_nsei;
enum gbproxy_keep_mode keep_link_infos;
/* IMSI checking/matching */
struct gbproxy_match matches[GBPROX_MATCH_LAST];
/* Used to generate identifiers */
unsigned bss_ptmsi_state;
unsigned sgsn_tlli_state;
};
struct gbproxy_patch_state {
int local_mnc;
int local_mcc;
/* List of TLLIs for which patching is enabled */
struct llist_head logical_links;
int logical_link_count;
};
struct gbproxy_peer {
struct llist_head list;
/* point back to the config */
struct gbproxy_config *cfg;
/* NSEI of the peer entity */
uint16_t nsei;
/* BVCI used for Point-to-Point to this peer */
uint16_t bvci;
int blocked;
/* Routeing Area that this peer is part of (raw 04.08 encoding) */
uint8_t ra[6];
/* Counter */
struct rate_ctr_group *ctrg;
struct gbproxy_patch_state patch_state;
};
struct gbproxy_tlli_state {
uint32_t current;
uint32_t assigned;
int bss_validated;
int net_validated;
uint32_t ptmsi;
};
struct gbproxy_link_info {
struct llist_head list;
struct gbproxy_tlli_state tlli;
struct gbproxy_tlli_state sgsn_tlli;
uint32_t sgsn_nsei;
time_t timestamp;
uint8_t *imsi;
size_t imsi_len;
int imsi_acq_pending;
struct llist_head stored_msgs;
unsigned vu_gen_tx_bss;
int is_deregistered;
int is_matching[GBPROX_MATCH_LAST];
};
extern struct gbproxy_config gbcfg;
extern struct cmd_element show_gbproxy_cmd;
/* gb_proxy_vty .c */
@@ -25,9 +175,10 @@ int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg);
/* gb_proxy.c */
int gbproxy_init_config(struct gbproxy_config *cfg);
/* Main input function for Gb proxy */
int gbprox_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci);
int gbprox_rcvmsg(struct gbproxy_config *cfg, struct msgb *msg, uint16_t nsei, uint16_t ns_bvci, uint16_t nsvci);
int gbprox_signal(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data);
@@ -35,4 +186,91 @@ int gbprox_signal(unsigned int subsys, unsigned int signal,
/* Reset all persistent NS-VC's */
int gbprox_reset_persistent_nsvcs(struct gprs_ns_inst *nsi);
void gbprox_reset(struct gbproxy_config *cfg);
/* TLLI info handling */
void gbproxy_delete_link_infos(struct gbproxy_peer *peer);
struct gbproxy_link_info *gbproxy_update_link_state_ul(
struct gbproxy_peer *peer, time_t now,
struct gprs_gb_parse_context *parse_ctx);
struct gbproxy_link_info *gbproxy_update_link_state_dl(
struct gbproxy_peer *peer, time_t now,
struct gprs_gb_parse_context *parse_ctx);
void gbproxy_update_link_state_after(
struct gbproxy_peer *peer, struct gbproxy_link_info *link_info,
time_t now, struct gprs_gb_parse_context *parse_ctx);
int gbproxy_remove_stale_link_infos(struct gbproxy_peer *peer, time_t now);
void gbproxy_delete_link_info(struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info);
void gbproxy_link_info_discard_messages(struct gbproxy_link_info *link_info);
void gbproxy_attach_link_info(struct gbproxy_peer *peer, time_t now,
struct gbproxy_link_info *link_info);
void gbproxy_update_link_info(struct gbproxy_link_info *link_info,
const uint8_t *imsi, size_t imsi_len);
void gbproxy_detach_link_info(struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info);
struct gbproxy_link_info *gbproxy_link_info_alloc( struct gbproxy_peer *peer);
struct gbproxy_link_info *gbproxy_link_info_by_tlli(
struct gbproxy_peer *peer, uint32_t tlli);
struct gbproxy_link_info *gbproxy_link_info_by_imsi(
struct gbproxy_peer *peer, const uint8_t *imsi, size_t imsi_len);
struct gbproxy_link_info *gbproxy_link_info_by_any_sgsn_tlli(
struct gbproxy_peer *peer, uint32_t tlli);
struct gbproxy_link_info *gbproxy_link_info_by_sgsn_tlli(
struct gbproxy_peer *peer,
uint32_t tlli, uint32_t sgsn_nsei);
struct gbproxy_link_info *gbproxy_link_info_by_ptmsi(
struct gbproxy_peer *peer,
uint32_t ptmsi);
int gbproxy_imsi_matches(
struct gbproxy_config *cfg,
enum gbproxy_match_id match_id,
struct gbproxy_link_info *link_info);
uint32_t gbproxy_map_tlli(
uint32_t other_tlli, struct gbproxy_link_info *link_info, int to_bss);
/* needed by gb_proxy_tlli.h */
uint32_t gbproxy_make_bss_ptmsi(struct gbproxy_peer *peer, uint32_t sgsn_ptmsi);
uint32_t gbproxy_make_sgsn_tlli(
struct gbproxy_peer *peer, struct gbproxy_link_info *link_info,
uint32_t bss_tlli);
void gbproxy_reset_link(struct gbproxy_link_info *link_info);
int gbproxy_check_imsi(
struct gbproxy_match *match, const uint8_t *imsi, size_t imsi_len);
/* Message patching */
void gbproxy_patch_bssgp(
struct msgb *msg, uint8_t *bssgp, size_t bssgp_len,
struct gbproxy_peer *peer, struct gbproxy_link_info *link_info,
int *len_change, struct gprs_gb_parse_context *parse_ctx);
int gbproxy_patch_llc(
struct msgb *msg, uint8_t *llc, size_t llc_len,
struct gbproxy_peer *peer, struct gbproxy_link_info *link_info,
int *len_change, struct gprs_gb_parse_context *parse_ctx);
int gbproxy_set_patch_filter(
struct gbproxy_match *match, const char *filter, const char **err_msg);
void gbproxy_clear_patch_filter(struct gbproxy_match *match);
/* Peer handling */
struct gbproxy_peer *gbproxy_peer_by_bvci(
struct gbproxy_config *cfg, uint16_t bvci);
struct gbproxy_peer *gbproxy_peer_by_nsei(
struct gbproxy_config *cfg, uint16_t nsei);
struct gbproxy_peer *gbproxy_peer_by_rai(
struct gbproxy_config *cfg, const uint8_t *ra);
struct gbproxy_peer *gbproxy_peer_by_lai(
struct gbproxy_config *cfg, const uint8_t *la);
struct gbproxy_peer *gbproxy_peer_by_lac(
struct gbproxy_config *cfg, const uint8_t *la);
struct gbproxy_peer *gbproxy_peer_by_bssgp_tlv(
struct gbproxy_config *cfg, struct tlv_parsed *tp);
struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci);
void gbproxy_peer_free(struct gbproxy_peer *peer);
int gbproxy_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci);
#endif

View File

@@ -0,0 +1,59 @@
#pragma once
#include <openbsc/gprs_llc.h>
#include <sys/types.h>
struct gprs_gb_parse_context {
/* Pointer to protocol specific parts */
struct gsm48_hdr *g48_hdr;
struct bssgp_normal_hdr *bgp_hdr;
struct bssgp_ud_hdr *bud_hdr;
uint8_t *bssgp_data;
size_t bssgp_data_len;
uint8_t *llc;
size_t llc_len;
/* Extracted information */
struct gprs_llc_hdr_parsed llc_hdr_parsed;
struct tlv_parsed bssgp_tp;
int to_bss;
uint8_t *tlli_enc;
uint8_t *old_tlli_enc;
uint8_t *imsi;
size_t imsi_len;
uint8_t *apn_ie;
size_t apn_ie_len;
uint8_t *ptmsi_enc;
uint8_t *new_ptmsi_enc;
uint8_t *raid_enc;
uint8_t *old_raid_enc;
uint8_t *bssgp_raid_enc;
uint8_t *bssgp_ptmsi_enc;
/* General info */
const char *llc_msg_name;
int invalidate_tlli;
int await_reattach;
int need_decryption;
uint32_t tlli;
int pdu_type;
int old_raid_is_foreign;
int peer_nsei;
};
int gprs_gb_parse_dtap(uint8_t *data, size_t data_len,
struct gprs_gb_parse_context *parse_ctx);
int gprs_gb_parse_llc(uint8_t *llc, size_t llc_len,
struct gprs_gb_parse_context *parse_ctx);
int gprs_gb_parse_bssgp(uint8_t *bssgp, size_t bssgp_len,
struct gprs_gb_parse_context *parse_ctx);
const char *gprs_gb_message_name(const struct gprs_gb_parse_context *parse_ctx,
const char *default_msg_name);
void gprs_gb_log_parse_context(int log_level,
struct gprs_gb_parse_context *parse_ctx,
const char *default_msg_name);

View File

@@ -11,9 +11,17 @@ int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp);
int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp);
int gsm0408_gprs_rcvmsg(struct msgb *msg, struct gprs_llc_llme *llme);
int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx);
int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg);
void gsm0408_gprs_access_granted(struct sgsn_mm_ctx *mmctx);
void gsm0408_gprs_access_denied(struct sgsn_mm_ctx *mmctx, int gmm_cause);
void gsm0408_gprs_access_cancelled(struct sgsn_mm_ctx *mmctx, int gmm_cause);
void gsm0408_gprs_authenticate(struct sgsn_mm_ctx *mmctx);
int gprs_gmm_rx_suspend(struct gprs_ra_id *raid, uint32_t tlli);
int gprs_gmm_rx_resume(struct gprs_ra_id *raid, uint32_t tlli,
uint8_t suspend_ref);
time_t gprs_max_time_to_idle(void);
#endif /* _GPRS_GMM_H */

View File

@@ -0,0 +1,54 @@
/* GPRS Subscriber Update Protocol client */
/* (C) 2014 by Sysmocom s.f.m.c. GmbH
* All Rights Reserved
*
* Author: Jacob Erlbeck
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <osmocom/core/timer.h>
#define GPRS_GSUP_RECONNECT_INTERVAL 10
#define GPRS_GSUP_PING_INTERVAL 20
struct msgb;
struct ipa_client_conn;
struct gprs_gsup_client;
/* Expects message in msg->l2h */
typedef int (*gprs_gsup_read_cb_t)(struct gprs_gsup_client *gsupc, struct msgb *msg);
struct gprs_gsup_client {
struct ipa_client_conn *link;
gprs_gsup_read_cb_t read_cb;
void *data;
struct osmo_timer_list ping_timer;
struct osmo_timer_list connect_timer;
int is_connected;
int got_ipa_pong;
};
struct gprs_gsup_client *gprs_gsup_client_create(const char *ip_addr,
unsigned int tcp_port,
gprs_gsup_read_cb_t read_cb);
void gprs_gsup_client_destroy(struct gprs_gsup_client *gsupc);
int gprs_gsup_client_send(struct gprs_gsup_client *gsupc, struct msgb *msg);
struct msgb *gprs_gsup_msgb_alloc(void);

View File

@@ -0,0 +1,116 @@
/* GPRS Subscriber Update Protocol message encoder/decoder */
/* (C) 2014 by Sysmocom s.f.m.c. GmbH
* All Rights Reserved
*
* Author: Jacob Erlbeck
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <stdint.h>
#include <openbsc/gsm_04_08_gprs.h>
#include <openbsc/gsm_data.h>
/* Needed for GSM_IMSI_LENGTH: */
#include <openbsc/gsm_subscriber.h>
#define GPRS_GSUP_MAX_NUM_PDP_INFO 10 /* GSM 09.02 limits this to 50 */
#define GPRS_GSUP_MAX_NUM_AUTH_INFO 5
#define GPRS_GSUP_MAX_MSISDN_LEN 9
#define GPRS_GSUP_PDP_TYPE_SIZE 2
enum gprs_gsup_iei {
GPRS_GSUP_IMSI_IE = 0x01,
GPRS_GSUP_CAUSE_IE = 0x02,
GPRS_GSUP_AUTH_TUPLE_IE = 0x03,
GPRS_GSUP_PDP_INFO_COMPL_IE = 0x04,
GPRS_GSUP_PDP_INFO_IE = 0x05,
GPRS_GSUP_CANCEL_TYPE_IE = 0x06,
GPRS_GSUP_FREEZE_PTMSI_IE = 0x07,
GPRS_GSUP_MSISDN_IE = 0x08,
GPRS_GSUP_PDP_CONTEXT_ID_IE = 0x10,
GPRS_GSUP_PDP_TYPE_IE = 0x11,
GPRS_GSUP_ACCESS_POINT_NAME_IE = 0x12,
GPRS_GSUP_PDP_QOS_IE = 0x13,
GPRS_GSUP_RAND_IE = 0x20,
GPRS_GSUP_SRES_IE = 0x21,
GPRS_GSUP_KC_IE = 0x22
};
enum gprs_gsup_message_type {
GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST = 0b00000100,
GPRS_GSUP_MSGT_UPDATE_LOCATION_ERROR = 0b00000101,
GPRS_GSUP_MSGT_UPDATE_LOCATION_RESULT = 0b00000110,
GPRS_GSUP_MSGT_SEND_AUTH_INFO_REQUEST = 0b00001000,
GPRS_GSUP_MSGT_SEND_AUTH_INFO_ERROR = 0b00001001,
GPRS_GSUP_MSGT_SEND_AUTH_INFO_RESULT = 0b00001010,
GPRS_GSUP_MSGT_PURGE_MS_REQUEST = 0b00001100,
GPRS_GSUP_MSGT_PURGE_MS_ERROR = 0b00001101,
GPRS_GSUP_MSGT_PURGE_MS_RESULT = 0b00001110,
GPRS_GSUP_MSGT_INSERT_DATA_REQUEST = 0b00010000,
GPRS_GSUP_MSGT_INSERT_DATA_ERROR = 0b00010001,
GPRS_GSUP_MSGT_INSERT_DATA_RESULT = 0b00010010,
GPRS_GSUP_MSGT_DELETE_DATA_REQUEST = 0b00010100,
GPRS_GSUP_MSGT_DELETE_DATA_ERROR = 0b00010101,
GPRS_GSUP_MSGT_DELETE_DATA_RESULT = 0b00010110,
GPRS_GSUP_MSGT_LOCATION_CANCEL_REQUEST = 0b00011100,
GPRS_GSUP_MSGT_LOCATION_CANCEL_ERROR = 0b00011101,
GPRS_GSUP_MSGT_LOCATION_CANCEL_RESULT = 0b00011110,
};
#define GPRS_GSUP_IS_MSGT_REQUEST(msgt) (((msgt) & 0b00000011) == 0b00)
#define GPRS_GSUP_IS_MSGT_ERROR(msgt) (((msgt) & 0b00000011) == 0b01)
#define GPRS_GSUP_TO_MSGT_ERROR(msgt) (((msgt) & 0b11111100) | 0b01)
enum gprs_gsup_cancel_type {
GPRS_GSUP_CANCEL_TYPE_UPDATE = 1, /* on wire: 0 */
GPRS_GSUP_CANCEL_TYPE_WITHDRAW = 2, /* on wire: 1 */
};
struct gprs_gsup_pdp_info {
unsigned int context_id;
int have_info;
uint16_t pdp_type;
const uint8_t *apn_enc;
size_t apn_enc_len;
const uint8_t *qos_enc;
size_t qos_enc_len;
};
struct gprs_gsup_message {
enum gprs_gsup_message_type message_type;
char imsi[GSM_IMSI_LENGTH];
enum gsm48_gmm_cause cause;
enum gprs_gsup_cancel_type cancel_type;
int pdp_info_compl;
int freeze_ptmsi;
struct gsm_auth_tuple auth_tuples[GPRS_GSUP_MAX_NUM_AUTH_INFO];
size_t num_auth_tuples;
struct gprs_gsup_pdp_info pdp_infos[GPRS_GSUP_MAX_NUM_PDP_INFO];
size_t num_pdp_infos;
const uint8_t *msisdn_enc;
size_t msisdn_enc_len;
};
int gprs_gsup_decode(const uint8_t *data, size_t data_len,
struct gprs_gsup_message *gsup_msg);
void gprs_gsup_encode(struct msgb *msg, const struct gprs_gsup_message *gsup_msg);

View File

@@ -126,6 +126,10 @@ struct gprs_llc_lle {
uint16_t vu_send;
uint16_t vu_recv;
/* non-standard LLC state */
uint16_t vu_recv_last;
uint16_t vu_recv_duplicates;
/* Overflow Counter for ABM */
uint32_t oc_i_send;
uint32_t oc_i_recv;
@@ -157,10 +161,48 @@ struct gprs_llc_llme {
uint16_t bvci;
uint16_t nsei;
struct gprs_llc_lle lle[NUM_SAPIS];
/* Internal management */
uint32_t age_timestamp;
};
#define GPRS_LLME_RESET_AGE (0)
extern struct llist_head gprs_llc_llmes;
/* LLC low level types */
enum gprs_llc_cmd {
GPRS_LLC_NULL,
GPRS_LLC_RR,
GPRS_LLC_ACK,
GPRS_LLC_RNR,
GPRS_LLC_SACK,
GPRS_LLC_DM,
GPRS_LLC_DISC,
GPRS_LLC_UA,
GPRS_LLC_SABM,
GPRS_LLC_FRMR,
GPRS_LLC_XID,
GPRS_LLC_UI,
};
struct gprs_llc_hdr_parsed {
uint8_t sapi;
uint8_t is_cmd:1,
ack_req:1,
is_encrypted:1;
uint32_t seq_rx;
uint32_t seq_tx;
uint32_t fcs;
uint32_t fcs_calc;
uint8_t *data;
uint16_t data_len;
uint16_t crc_length;
enum gprs_llc_cmd cmd;
};
/* BSSGP-UL-UNITDATA.ind */
int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv);
@@ -170,6 +212,7 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
/* Chapter 7.2.1.2 LLGMM-RESET.req */
int gprs_llgmm_reset(struct gprs_llc_llme *llme);
int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi);
/* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */
int gprs_llgmm_assign(struct gprs_llc_llme *llme,
@@ -195,4 +238,18 @@ static inline int gprs_llc_is_retransmit(uint16_t nu, uint16_t vur)
return 0 < delta && delta < 32;
}
/* LLC low level functions */
/* parse a GPRS LLC header, also check for invalid frames */
int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
uint8_t *llc_hdr, int len);
void gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph);
int gprs_llc_fcs(uint8_t *data, unsigned int len);
/* LLME handling routines */
struct llist_head *gprs_llme_list(void);
struct gprs_llc_lle *gprs_lle_get_or_create(const uint32_t tlli, uint8_t sapi);
#endif

View File

@@ -10,11 +10,18 @@
#include <osmocom/crypt/gprs_cipher.h>
#include <openbsc/gsm_data.h>
#define GSM_IMSI_LENGTH 17
#define GSM_IMEI_LENGTH 17
#define GSM_EXTENSION_LENGTH 15
#define GSM_APN_LENGTH 102
struct gprs_llc_lle;
struct ctrl_handle;
struct gsm_subscriber;
enum gsm48_gsm_cause;
/* TS 04.08 4.1.3.3 GMM mobility management states on the network side */
enum gprs_mm_state {
@@ -47,11 +54,20 @@ enum gprs_pdp_ctx {
};
enum gprs_t3350_mode {
GMM_T3350_MODE_NONE,
GMM_T3350_MODE_ATT,
GMM_T3350_MODE_RAU,
GMM_T3350_MODE_PTMSI_REALL,
};
/* Authorization/ACL handling */
enum sgsn_auth_state {
SGSN_AUTH_UNKNOWN,
SGSN_AUTH_AUTHENTICATE,
SGSN_AUTH_ACCEPTED,
SGSN_AUTH_REJECTED
};
#define MS_RADIO_ACCESS_CAPA
/* According to TS 03.60, Table 5: SGSN MM and PDP Contexts */
@@ -74,18 +90,19 @@ struct sgsn_mm_ctx {
uint32_t sac_age;/* Iu: Service Area Code age */
/* VLR number */
uint32_t new_sgsn_addr;
/* Authentication Triplets */
/* Authentication Triplet */
struct gsm_auth_tuple auth_triplet;
/* Kc */
/* Iu: CK, IK, KSI */
/* CKSN */
enum gprs_ciph_algo ciph_algo;
struct {
uint8_t buf[52]; /* 10.5.5.12a */
uint8_t len;
uint8_t buf[50]; /* GSM 04.08 10.5.5.12a, extended in TS 24.008 */
} ms_radio_access_capa;
struct {
uint8_t buf[4]; /* 10.5.5.12 */
uint8_t len;
uint8_t buf[8]; /* GSM 04.08 10.5.5.12, extended in TS 24.008 */
} ms_network_capa;
uint16_t drx_parms;
int mnrg; /* MS reported to HLR? */
@@ -110,8 +127,22 @@ struct sgsn_mm_ctx {
enum gprs_t3350_mode t3350_mode;
uint8_t t3370_id_type;
uint8_t pending_req; /* the request's message type */
/* TODO: There isn't much semantic difference between t3350_mode
* (refers to the timer) and pending_req (refers to the procedure),
* where mm->T == 3350 => mm->t3350_mode == f(mm->pending_req). Check
* whether one of them can be dropped. */
enum sgsn_auth_state auth_state;
int is_authenticated;
struct gsm_subscriber *subscr;
};
#define LOGMMCTXP(level, mm, fmt, args...) \
LOGP(DMM, level, "MM(%s/%08x) " fmt, (mm) ? (mm)->imsi : "---", \
(mm) ? (mm)->p_tmsi : GSM_RESERVED_TMSI, ## args)
/* look-up a SGSN MM context based on TLLI + RAI */
struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli,
const struct gprs_ra_id *raid);
@@ -122,7 +153,11 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi);
struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli,
const struct gprs_ra_id *raid);
void sgsn_mm_ctx_free(struct sgsn_mm_ctx *mm);
void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx);
struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
struct tlv_parsed *tp,
enum gsm48_gsm_cause *gsm_cause);
enum pdp_ctx_state {
PDP_STATE_NONE,
@@ -175,6 +210,9 @@ struct sgsn_pdp_ctx {
unsigned int num_T_exp; /* number of consecutive T expirations */
};
#define LOGPDPCTXP(level, pdp, fmt, args...) \
LOGP(DGPRS, level, "PDP(%s/%u) " \
fmt, (pdp)->mm ? (pdp)->mm->imsi : "---", (pdp)->ti, ## args)
/* look up PDP context by MM context and NSAPI */
struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm,
@@ -185,6 +223,7 @@ struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_tid(const struct sgsn_mm_ctx *mm,
struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
uint8_t nsapi);
void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp);
void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp);
@@ -197,6 +236,7 @@ struct sgsn_ggsn_ctx {
struct gsn_t *gsn;
};
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id);
void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc);
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id);
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct in_addr *addr);
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id);
@@ -205,18 +245,122 @@ struct apn_ctx {
struct llist_head list;
struct sgsn_ggsn_ctx *ggsn;
char *name;
char *imsi_prefix;
char *description;
};
struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix);
void sgsn_apn_ctx_free(struct apn_ctx *actx);
struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix);
struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi_prefix);
extern struct llist_head sgsn_mm_ctxts;
extern struct llist_head sgsn_ggsn_ctxts;
extern struct llist_head sgsn_apn_ctxts;
extern struct llist_head sgsn_pdp_ctxts;
uint32_t sgsn_alloc_ptmsi(void);
void sgsn_inst_init(void);
/* High-level function to be called in case a GGSN has disappeared or
* ottherwise lost state (recovery procedure) */
int drop_all_pdp_for_ggsn(struct sgsn_ggsn_ctx *ggsn);
char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len);
/* Force re-attachment based on msgb meta data */
int sgsn_force_reattach_oldmsg(struct msgb *oldmsg);
/*
* ctrl interface related work
*/
struct gsm_network;
struct ctrl_handle *sgsn_controlif_setup(struct gsm_network *, uint16_t port);
int sgsn_ctrl_cmds_install(void);
/*
* Authorization/ACL handling
*/
struct imsi_acl_entry {
struct llist_head list;
char imsi[16+1];
};
/* see GSM 09.02, 17.7.1, PDP-Context and GPRSSubscriptionData */
/* see GSM 09.02, B.1, gprsSubscriptionData */
struct sgsn_subscriber_pdp_data {
struct llist_head list;
unsigned int context_id;
uint16_t pdp_type;
char apn_str[GSM_APN_LENGTH];
uint8_t qos_subscribed[20];
size_t qos_subscribed_len;
};
struct sgsn_subscriber_data {
struct sgsn_mm_ctx *mm;
struct gsm_auth_tuple auth_triplets[5];
int auth_triplets_updated;
struct llist_head pdp_list;
int error_cause;
uint8_t msisdn[9];
size_t msisdn_len;
};
#define SGSN_ERROR_CAUSE_NONE (-1)
#define LOGGSUBSCRP(level, subscr, fmt, args...) \
LOGP(DGPRS, level, "SUBSCR(%s) " fmt, \
(subscr) ? (subscr)->imsi : "---", \
## args)
struct sgsn_config;
struct sgsn_instance;
extern const struct value_string *sgsn_auth_state_names;
void sgsn_auth_init(void);
struct imsi_acl_entry *sgsn_acl_lookup(const char *imsi, struct sgsn_config *cfg);
int sgsn_acl_add(const char *imsi, struct sgsn_config *cfg);
int sgsn_acl_del(const char *imsi, struct sgsn_config *cfg);
/* Request authorization */
int sgsn_auth_request(struct sgsn_mm_ctx *mm);
enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mm);
void sgsn_auth_update(struct sgsn_mm_ctx *mm);
struct gsm_auth_tuple *sgsn_auth_get_tuple(struct sgsn_mm_ctx *mmctx,
unsigned key_seq);
/*
* GPRS subscriber data
*/
#define GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING (1 << 16)
#define GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING (1 << 17)
#define GPRS_SUBSCRIBER_CANCELLED (1 << 18)
#define GPRS_SUBSCRIBER_ENABLE_PURGE (1 << 19)
#define GPRS_SUBSCRIBER_UPDATE_PENDING_MASK ( \
GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING | \
GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING \
)
int gprs_subscr_init(struct sgsn_instance *sgi);
int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx);
int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx);
void gprs_subscr_cleanup(struct gsm_subscriber *subscr);
struct gsm_subscriber *gprs_subscr_get_or_create(const char *imsi);
struct gsm_subscriber *gprs_subscr_get_or_create_by_mmctx( struct sgsn_mm_ctx *mmctx);
struct gsm_subscriber *gprs_subscr_get_by_imsi(const char *imsi);
void gprs_subscr_cancel(struct gsm_subscriber *subscr);
void gprs_subscr_update(struct gsm_subscriber *subscr);
void gprs_subscr_update_auth_info(struct gsm_subscriber *subscr);
int gprs_subscr_rx_gsup_message(struct msgb *msg);
/* Called on subscriber data updates */
void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx);
int gprs_sndcp_vty_init(void);
struct sgsn_instance;
int sgsn_gtp_init(struct sgsn_instance *sgi);
#endif /* _GPRS_SGSN_H */

View File

@@ -0,0 +1,54 @@
/* GPRS utility functions */
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2010-2014 by On-Waves
* (C) 2013 by Holger Hans Peter Freyther
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <stdint.h>
#include <sys/types.h>
struct msgb;
struct msgb *gprs_msgb_copy(const struct msgb *msg, const char *name);
int gprs_msgb_resize_area(struct msgb *msg, uint8_t *area,
size_t old_size, size_t new_size);
char *gprs_apn_to_str(char *out_str, const uint8_t *apn_enc, size_t rest_chars);
int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str);
/* GSM 04.08, 10.5.7.3 GPRS Timer */
int gprs_tmr_to_secs(uint8_t tmr);
uint8_t gprs_secs_to_tmr_floor(int secs);
int gprs_is_mi_tmsi(const uint8_t *value, size_t value_len);
int gprs_is_mi_imsi(const uint8_t *value, size_t value_len);
int gprs_parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi);
void gprs_parse_tmsi(const uint8_t *value, uint32_t *tmsi);
int gprs_shift_v_fixed(uint8_t **data, size_t *data_len,
size_t len, uint8_t **value);
int gprs_match_tv_fixed(uint8_t **data, size_t *data_len,
uint8_t tag, size_t len, uint8_t **value);
int gprs_shift_tlv(uint8_t **data, size_t *data_len,
uint8_t *tag, uint8_t **value, size_t *value_len);
int gprs_match_tlv(uint8_t **data, size_t *data_len,
uint8_t tag, uint8_t **value, size_t *value_len);
int gprs_shift_lv(uint8_t **data, size_t *data_len,
uint8_t **value, size_t *value_len);

View File

@@ -6,6 +6,7 @@
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <openbsc/meas_rep.h>
#include <openbsc/mncc.h>
struct msgb;
struct gsm_bts;
@@ -13,6 +14,7 @@ struct gsm_subscriber;
struct gsm_network;
struct gsm_trans;
struct gsm_subscriber_connection;
struct amr_multirate_conf;
#define GSM48_ALLOC_SIZE 2048
#define GSM48_ALLOC_HEADROOM 256
@@ -23,6 +25,20 @@ static inline struct msgb *gsm48_msgb_alloc(void)
"GSM 04.08");
}
static inline int get_radio_link_timeout(struct gsm48_cell_options *cell_options)
{
return (cell_options->radio_link_timeout + 1) << 2;
}
static inline void set_radio_link_timeout(struct gsm48_cell_options *cell_options, int value)
{
if (value < 4)
value = 4;
if (value > 64)
value = 64;
cell_options->radio_link_timeout = (value >> 2) - 1;
}
/* config options controlling the behaviour of the lower leves */
void gsm0408_allow_everyone(int allow);
void gsm0408_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause);
@@ -39,6 +55,9 @@ void gsm_net_update_ctype(struct gsm_network *net);
int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn);
int gsm48_tx_mm_auth_req(struct gsm_subscriber_connection *conn, uint8_t *rand, int key_seq);
int gsm48_tx_mm_auth_rej(struct gsm_subscriber_connection *conn);
int gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn);
int gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn,
enum gsm48_reject_value value);
int gsm48_send_rr_release(struct gsm_lchan *lchan);
int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv);
int gsm48_send_rr_app_info(struct gsm_subscriber_connection *conn, uint8_t apdu_id,
@@ -72,4 +91,8 @@ void gsm48_lchan2chan_desc(struct gsm48_chan_desc *cd,
void release_security_operation(struct gsm_subscriber_connection *conn);
void allocate_security_operation(struct gsm_subscriber_connection *conn);
int tch_frame_down(struct gsm_network *net, uint32_t callref, struct gsm_data_frame *data);
int gsm48_multirate_config(uint8_t *lv, struct amr_multirate_conf *mr, int ms);
#endif

View File

@@ -47,6 +47,8 @@
#define GPRS_ATT_T_ATT_WHILE_IMSI 2
#define GPRS_ATT_T_COMBINED 3
extern const struct value_string *gprs_att_t_strs;
/* Chapter 10.5.5.5 / Table 10.5.138 */
#define GPRS_DET_T_MO_GPRS 1
#define GPRS_DET_T_MO_IMSI 2
@@ -56,12 +58,17 @@
#define GPRS_DET_T_MT_REATT_NOTREQ 2
#define GPRS_DET_T_MT_IMSI 3
extern const struct value_string *gprs_det_t_mo_strs;
extern const struct value_string *gprs_det_t_mt_strs;
/* Chapter 10.5.5.18 / Table 105.150 */
#define GPRS_UPD_T_RA 0
#define GPRS_UPD_T_RA_LA 1
#define GPRS_UPD_T_RA_LA_IMSI_ATT 2
#define GPRS_UPD_T_PERIODIC 3
extern const struct value_string *gprs_upd_t_strs;
enum gsm48_gprs_ie_mm {
GSM48_IE_GMM_CIPH_CKSN = 0x08, /* 10.5.1.2 */
GSM48_IE_GMM_TIMER_READY = 0x17, /* 10.5.7.3 */
@@ -70,6 +77,7 @@ enum gsm48_gprs_ie_mm {
GSM48_IE_GMM_AUTH_RAND = 0x21, /* 10.5.3.1 */
GSM48_IE_GMM_AUTH_SRES = 0x22, /* 10.5.3.2 */
GSM48_IE_GMM_IMEISV = 0x23, /* 10.5.1.4 */
GSM48_IE_GMM_CAUSE = 0x25, /* 10.5.5.14 */
GSM48_IE_GMM_DRX_PARAM = 0x27, /* 10.5.5.6 */
GSM48_IE_GMM_MS_NET_CAPA = 0x31, /* 10.5.5.12 */
GSM48_IE_GMM_PDP_CTX_STATUS = 0x32, /* 10.5.7.1 */
@@ -92,6 +100,7 @@ enum gsm48_gprs_ie_sm {
* but which we use to simplify internal APIs */
OSMO_IE_GSM_REQ_QOS = 0xfd,
OSMO_IE_GSM_REQ_PDP_ADDR = 0xfe,
OSMO_IE_GSM_SUB_QOS = 0xff,
};
/* Chapter 9.4.15 / Table 9.4.15 */
@@ -108,9 +117,12 @@ enum gsm48_gprs_tmr_unit {
GPRS_TMR_2SECONDS = 0 << 5,
GPRS_TMR_MINUTE = 1 << 5,
GPRS_TMR_6MINUTE = 2 << 5,
GPRS_TMR_DEACTIVATED = 3 << 5,
GPRS_TMR_DEACTIVATED = 7 << 5,
};
#define GPRS_TMR_UNIT_MASK (7 << 5)
#define GPRS_TMR_FACT_MASK ((1 << 5)-1)
/* Chapter 9.4.2 / Table 9.4.2 */
struct gsm48_attach_ack {
uint8_t att_result:4, /* 10.5.5.7 */
@@ -170,6 +182,8 @@ enum gsm48_gmm_cause {
GMM_CAUSE_PROTO_ERR_UNSPEC = 0x6f,
};
extern const struct value_string *gsm48_gmm_cause_names;
/* Chapter 10.4.6.6 / Table 10.5.157 */
enum gsm48_gsm_cause {
GSM_CAUSE_INSUFF_RSRC = 0x1a,
@@ -198,6 +212,8 @@ enum gsm48_gsm_cause {
GSM_CAUSE_PROTO_ERR_UNSPEC = 0x6f,
};
extern const struct value_string *gsm48_gsm_cause_names;
/* Section 6.1.2.2: Session management states on the network side */
enum gsm48_pdp_state {
PDP_S_INACTIVE,

View File

@@ -37,4 +37,6 @@ int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
int gsm411_send_sms(struct gsm_subscriber_connection *conn,
struct gsm_sms *sms);
void gsm411_sapi_n_reject(struct gsm_subscriber_connection *conn);
uint8_t sms_next_rp_msg_ref(struct gsm_subscriber_connection *conn);
#endif

View File

@@ -8,9 +8,13 @@
#include <openbsc/rest_octets.h>
/** annotations for msgb ownership */
#define __uses
#define OBSC_NM_W_ACK_CB(__msgb) (__msgb)->cb[3]
struct mncc_sock_state;
struct gsm_subscriber_group;
#define OBSC_LINKID_CB(__msgb) (__msgb)->cb[3]
@@ -18,6 +22,7 @@ enum gsm_security_event {
GSM_SECURITY_NOAVAIL,
GSM_SECURITY_AUTH_FAILED,
GSM_SECURITY_SUCCEEDED,
GSM_SECURITY_ALREADY,
};
struct msgb;
@@ -100,6 +105,11 @@ struct gsm_subscriber_connection {
/* To whom we are allocated at the moment */
struct gsm_subscriber *subscr;
/* LU expiration handling */
uint8_t expire_timer_stopped;
/* SMS helpers for libmsc */
uint8_t next_rp_ref;
/*
* Operations that have a state and might be pending
*/
@@ -109,7 +119,6 @@ struct gsm_subscriber_connection {
/* Are we part of a special "silent" call */
int silent_call;
int put_channel;
/* bsc structures */
struct osmo_bsc_sccp_con *sccp_con;
@@ -268,8 +277,10 @@ struct gsm_network {
struct osmo_bsc_data *bsc_data;
/* subscriber related features */
int keep_subscr;
int create_subscriber;
struct gsm_subscriber_group *subscr_group;
struct gsm_sms_queue *sms_queue;
uint64_t exten_prefix;
/* control interface */
struct ctrl_handle *ctrl;
@@ -295,7 +306,6 @@ struct gsm_sms_addr {
struct gsm_sms {
unsigned long long id;
struct gsm_subscriber *sender;
struct gsm_subscriber *receiver;
struct gsm_sms_addr src, dst;
enum gsm_sms_source_id source;
@@ -324,8 +334,6 @@ struct gsm_network *gsm_network_init(uint16_t country_code, uint16_t network_cod
int (*mncc_recv)(struct gsm_network *, struct msgb *));
int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type);
struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num);
/* Get reference to a neighbor cell on a given BCCH ARFCN */
struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts,
uint16_t arfcn, uint8_t bsic);
@@ -351,6 +359,17 @@ static inline int is_ipaccess_bts(struct gsm_bts *bts)
return 0;
}
static inline int is_sysmobts_v2(struct gsm_bts *bts)
{
switch (bts->type) {
case GSM_BTS_TYPE_OSMO_SYSMO:
return 1;
default:
break;
}
return 0;
}
static inline int is_siemens_bts(struct gsm_bts *bts)
{
switch (bts->type) {
@@ -363,14 +382,41 @@ static inline int is_siemens_bts(struct gsm_bts *bts)
return 0;
}
static inline int is_nokia_bts(struct gsm_bts *bts)
{
switch (bts->type) {
case GSM_BTS_TYPE_NOKIA_SITE:
return 1;
default:
break;
}
return 0;
}
static inline int is_e1_bts(struct gsm_bts *bts)
{
switch (bts->type) {
case GSM_BTS_TYPE_BS11:
case GSM_BTS_TYPE_RBS2000:
case GSM_BTS_TYPE_NOKIA_SITE:
return 1;
default:
break;
}
return 0;
}
enum gsm_auth_policy gsm_auth_policy_parse(const char *arg);
const char *gsm_auth_policy_name(enum gsm_auth_policy policy);
enum rrlp_mode rrlp_mode_parse(const char *arg);
const char *rrlp_mode_name(enum rrlp_mode mode);
enum bts_gprs_mode bts_gprs_mode_parse(const char *arg);
enum bts_gprs_mode bts_gprs_mode_parse(const char *arg, int *valid);
const char *bts_gprs_mode_name(enum bts_gprs_mode mode);
int bts_gprs_mode_is_compat(struct gsm_bts *bts, enum bts_gprs_mode mode);
int gsm48_ra_id_by_bts(uint8_t *buf, struct gsm_bts *bts);
void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts);
@@ -385,12 +431,15 @@ void subscr_con_free(struct gsm_subscriber_connection *conn);
struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net,
enum gsm_bts_type type,
uint8_t tsc, uint8_t bsic);
void set_ts_e1link(struct gsm_bts_trx_ts *ts, uint8_t e1_nr,
uint8_t e1_ts, uint8_t e1_ts_ss);
void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked);
int gsm_bts_has_feature(struct gsm_bts *bts, enum gsm_bts_features feat);
struct gsm_bts_trx *gsm_bts_trx_by_nr(struct gsm_bts *bts, int nr);
int gsm_bts_trx_set_system_infos(struct gsm_bts_trx *trx);
int gsm_bts_set_system_infos(struct gsm_bts *bts);
/* generic E1 line operations for all ISDN-based BTS. */
extern struct e1inp_line_ops bts_isdn_e1inp_line_ops;
@@ -398,4 +447,14 @@ extern struct e1inp_line_ops bts_isdn_e1inp_line_ops;
extern const struct value_string bts_type_names[_NUM_GSM_BTS_TYPE+1];
extern const struct value_string bts_type_descs[_NUM_GSM_BTS_TYPE+1];
/* control interface handling */
int bsc_base_ctrl_cmds_install(void);
int msc_ctrl_cmds_install(void);
/* dependency handling */
void bts_depend_mark(struct gsm_bts *bts, int dep);
void bts_depend_clear(struct gsm_bts *bts, int dep);
int bts_depend_check(struct gsm_bts *bts);
int bts_depend_is_depedency(struct gsm_bts *base, struct gsm_bts *other);
#endif /* _GSM_DATA_H */

View File

@@ -13,6 +13,7 @@
#include <osmocom/gsm/tlv.h>
#include <osmocom/gsm/rxlev_stat.h>
#include <osmocom/gsm/sysinfo.h>
#include <osmocom/gsm/meas_rep.h>
#include <osmocom/gsm/protocol/gsm_08_58.h>
#include <osmocom/gsm/protocol/gsm_12_21.h>
@@ -57,9 +58,6 @@ enum gsm_chreq_reason_t {
#define HARDCODED_BTS1_TS 6
#define HARDCODED_BTS2_TS 11
/* reserved according to GSM 03.03 § 2.4 */
#define GSM_RESERVED_TMSI 0xFFFFFFFF
enum gsm_hooks {
GSM_HOOK_NM_SWLOAD,
GSM_HOOK_RR_PAGING,
@@ -95,6 +93,7 @@ struct gsm_nm_state {
struct gsm_abis_mo {
uint8_t obj_class;
uint8_t procedure_pending;
struct abis_om_obj_inst obj_inst;
const char *name;
struct gsm_nm_state nm_state;
@@ -112,6 +111,7 @@ struct gsm_abis_mo {
#define LCHAN_SAPI_UNUSED 0
#define LCHAN_SAPI_MS 1
#define LCHAN_SAPI_NET 2
#define LCHAN_SAPI_REL 3
/* state of a logical channel */
enum gsm_lchan_state {
@@ -142,10 +142,18 @@ struct bts_ul_meas {
uint8_t inv_rssi;
};
struct bts_codec_conf {
uint8_t hr;
uint8_t efr;
uint8_t amr;
};
struct amr_mode {
uint8_t mode;
uint8_t threshold;
uint8_t hysteresis;
uint8_t threshold_ms;
uint8_t hysteresis_ms;
uint8_t threshold_bts;
uint8_t hysteresis_bts;
};
struct amr_multirate_conf {
uint8_t gsm48_ie[2];
@@ -189,6 +197,7 @@ struct gsm_lchan {
enum lchan_csd_mode csd_mode;
/* State */
enum gsm_lchan_state state;
const char *broken_reason;
/* Power levels for MS and BTS */
uint8_t bs_power;
uint8_t ms_power;
@@ -200,7 +209,8 @@ struct gsm_lchan {
} encr;
/* AMR bits */
struct gsm48_multi_rate_conf mr_conf;
uint8_t mr_ms_lv[7];
uint8_t mr_bts_lv[7];
/* Established data link layer services */
uint8_t sapis[8];
@@ -230,6 +240,7 @@ struct gsm_lchan {
struct osmo_timer_list T3111;
struct osmo_timer_list error_timer;
struct osmo_timer_list act_timer;
struct osmo_timer_list rel_work;
uint8_t error_cause;
/* table of neighbor cell measurements */
@@ -246,6 +257,7 @@ struct gsm_lchan {
#else
/* Number of different GsmL1_Sapi_t used in osmo_bts_sysmo is 23.
* Currently we don't share these headers so this is a magic number. */
struct llist_head sapi_cmds;
uint8_t sapis_dl[23];
uint8_t sapis_ul[23];
struct lapdm_channel lapdm_ch;
@@ -268,12 +280,7 @@ struct gsm_lchan {
struct bts_ul_meas uplink[MAX_NUM_UL_MEAS];
/* last L1 header from the MS */
uint8_t l1_info[2];
struct {
uint8_t rxlev_full;
uint8_t rxlev_sub;
uint8_t rxqual_full;
uint8_t rxqual_sub;
} res;
struct gsm_meas_rep_unidir ul_res;
} meas;
struct {
struct amr_multirate_conf amr_mr;
@@ -281,9 +288,11 @@ struct gsm_lchan {
uint8_t buf[16];
uint8_t len;
} last_sid;
uint8_t last_cmr;
} tch;
/* BTS-side ciphering state (rx only, bi-directional, ...) */
uint8_t ciph_state;
uint8_t ciph_ns;
uint8_t loopback;
struct {
uint8_t active;
@@ -295,6 +304,14 @@ struct gsm_lchan {
} ho;
/* S counter for link loss */
int s;
/* Kind of the release/activation. E.g. RSL or PCU */
int rel_act_kind;
/* power handling */
struct {
uint8_t current;
uint8_t fixed;
} ms_power_ctrl;
#endif
};
@@ -345,11 +362,8 @@ struct gsm_bts_trx {
/* how do we talk RSL with this TRX? */
struct gsm_e1_subslot rsl_e1_link;
uint8_t rsl_tei;
#ifdef ROLE_BSC
struct e1inp_sign_link *rsl_link;
#else
struct ipabis_link *rsl_link;
#endif
/* Some BTS (specifically Ericsson RBS) have a per-TRX OML Link */
struct e1inp_sign_link *oml_link;
@@ -363,9 +377,14 @@ struct gsm_bts_trx {
int nominal_power; /* in dBm */
unsigned int max_power_red; /* in actual dB */
#ifndef ROLE_BSC
struct trx_power_params power_params;
int ms_power_control;
struct {
void *l1h;
} role_bts;
#endif
union {
struct {
@@ -392,7 +411,6 @@ enum gsm_bts_type {
GSM_BTS_TYPE_BS11,
GSM_BTS_TYPE_NANOBTS,
GSM_BTS_TYPE_RBS2000,
GSM_BTS_TYPE_HSL_FEMTO,
GSM_BTS_TYPE_NOKIA_SITE,
GSM_BTS_TYPE_OSMO_SYSMO,
_NUM_GSM_BTS_TYPE
@@ -428,6 +446,7 @@ enum gsm_bts_features {
BTS_FEAT_EGPRS,
BTS_FEAT_ECSD,
BTS_FEAT_HOPPING,
BTS_FEAT_MULTI_TSC,
};
/*
@@ -594,6 +613,7 @@ struct gsm_bts {
int hr;
int mn;
int override;
int dst;
} tz;
/* ip.accesss Unit ID's have Site/BTS/TRX layout */
@@ -629,13 +649,12 @@ struct gsm_bts {
struct gsm_abis_mo mo;
} tf;
} rbs2000;
struct {
unsigned long serno;
} hsl;
struct {
uint8_t bts_type;
unsigned int configured:1,
skip_reset:1,
no_loc_rel_cnf:1,
bts_reset_timer_cnf,
did_reset:1,
wait_reset:1;
struct osmo_timer_list reset_timer;
@@ -658,6 +677,7 @@ struct gsm_bts {
} cell;
struct gsm_bts_gprs_nsvc nsvc[2];
uint8_t rac;
uint8_t net_ctrl_ord;
} gprs;
/* RACH NM values */
@@ -668,6 +688,10 @@ struct gsm_bts {
int num_trx;
struct llist_head trx_list;
/* SI related items */
int force_combined_si;
int bcch_change_mark;
#ifdef ROLE_BSC
/* Abis NM queue */
struct llist_head abis_queue;
@@ -705,20 +729,32 @@ struct gsm_bts {
/* exclude the BTS from the global RF Lock handling */
int excl_from_rf_lock;
/* supported codecs beside FR */
struct bts_codec_conf codec;
/* BTS dependencies bit field */
uint32_t depends_on[256/(8*4)];
/* full and half rate multirate config */
struct amr_multirate_conf mr_full;
struct amr_multirate_conf mr_half;
#endif /* ROLE_BSC */
void *role;
};
struct gsm_bts *gsm_bts_alloc(void *talloc_ctx);
struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts);
struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num);
struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts);
struct gsm_bts_trx *gsm_bts_trx_num(const struct gsm_bts *bts, int num);
const struct value_string gsm_pchant_names[10];
const struct value_string gsm_pchant_descs[10];
const struct value_string gsm_lchant_names[6];
const struct value_string gsm_pchant_names[12];
const struct value_string gsm_pchant_descs[12];
const struct value_string gsm_lchant_names[8];
const char *gsm_pchan_name(enum gsm_phys_chan_config c);
enum gsm_phys_chan_config gsm_pchan_parse(const char *name);
const char *gsm_lchant_name(enum gsm_chan_t c);
@@ -748,12 +784,22 @@ void gsm_bts_mo_reset(struct gsm_bts *bts);
uint8_t gsm_ts2chan_nr(const struct gsm_bts_trx_ts *ts, uint8_t lchan_nr);
uint8_t gsm_lchan2chan_nr(const struct gsm_lchan *lchan);
/* return the gsm_lchan for the CBCH (if it exists at all) */
struct gsm_lchan *gsm_bts_get_cbch(struct gsm_bts *bts);
/*
* help with parsing regexps
*/
int gsm_parse_reg(void *ctx, regex_t *reg, char **str,
int argc, const char **argv) __attribute__ ((warn_unused_result));
static inline uint8_t gsm_ts_tsc(const struct gsm_bts_trx_ts *ts)
{
if (ts->tsc != -1)
return ts->tsc;
else
return ts->trx->bts->tsc;
}
#endif

View File

@@ -13,9 +13,22 @@
#define GSM_MAX_EXTEN 49999
#define GSM_SUBSCRIBER_FIRST_CONTACT 0x00000001
/* gprs_sgsn.h defines additional flags including and above bit 16 (0x10000) */
#define tmsi_from_string(str) strtoul(str, NULL, 10)
#define GSM_SUBSCRIBER_NO_EXPIRATION 0x0
struct vty;
struct sgsn_mm_ctx;
struct sgsn_subscriber_data;
struct subscr_request;
struct gsm_subscriber_group {
struct gsm_network *net;
int keep_subscr;
};
struct gsm_equipment {
long long unsigned int id;
@@ -30,7 +43,7 @@ struct gsm_equipment {
};
struct gsm_subscriber {
struct gsm_network *net;
struct gsm_subscriber_group *group;
long long unsigned int id;
char imsi[GSM_IMSI_LENGTH];
uint32_t tmsi;
@@ -40,6 +53,9 @@ struct gsm_subscriber {
int authorized;
time_t expire_lu;
/* Don't delete subscribers even if group->keep_subscr is not set */
int keep_in_ram;
/* Temporary field which is not stored in the DB/HLR */
uint32_t flags;
@@ -52,8 +68,11 @@ struct gsm_subscriber {
struct llist_head entry;
/* pending requests */
int in_callback;
int is_paging;
struct llist_head requests;
/* GPRS/SGSN related fields */
struct sgsn_subscriber_data *sgsn_data;
};
enum gsm_subscriber_field {
@@ -71,35 +90,37 @@ enum gsm_subscriber_update_reason {
struct gsm_subscriber *subscr_get(struct gsm_subscriber *subscr);
struct gsm_subscriber *subscr_put(struct gsm_subscriber *subscr);
struct gsm_subscriber *subscr_get_by_tmsi(struct gsm_network *net,
struct gsm_subscriber *subscr_create_subscriber(struct gsm_subscriber_group *sgrp,
const char *imsi);
struct gsm_subscriber *subscr_get_by_tmsi(struct gsm_subscriber_group *sgrp,
uint32_t tmsi);
struct gsm_subscriber *subscr_get_by_imsi(struct gsm_network *net,
struct gsm_subscriber *subscr_get_by_imsi(struct gsm_subscriber_group *sgrp,
const char *imsi);
struct gsm_subscriber *subscr_get_by_extension(struct gsm_network *net,
struct gsm_subscriber *subscr_get_by_extension(struct gsm_subscriber_group *sgrp,
const char *ext);
struct gsm_subscriber *subscr_get_by_id(struct gsm_network *net,
struct gsm_subscriber *subscr_get_by_id(struct gsm_subscriber_group *sgrp,
unsigned long long id);
struct gsm_subscriber *subscr_get_or_create(struct gsm_network *net,
struct gsm_subscriber *subscr_get_or_create(struct gsm_subscriber_group *sgrp,
const char *imsi);
int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason);
void subscr_put_channel(struct gsm_subscriber *subscr);
void subscr_get_channel(struct gsm_subscriber *subscr,
int type, gsm_cbfn *cbfn, void *param);
struct gsm_subscriber *subscr_active_by_tmsi(struct gsm_network *net,
struct gsm_subscriber *subscr_active_by_tmsi(struct gsm_subscriber_group *sgrp,
uint32_t tmsi);
struct gsm_subscriber *subscr_active_by_imsi(struct gsm_network *net,
struct gsm_subscriber *subscr_active_by_imsi(struct gsm_subscriber_group *sgrp,
const char *imsi);
int subscr_pending_requests(struct gsm_subscriber *subscr);
int subscr_pending_clear(struct gsm_subscriber *subscr);
int subscr_pending_dump(struct gsm_subscriber *subscr, struct vty *vty);
int subscr_pending_kick(struct gsm_subscriber *subscr);
char *subscr_name(struct gsm_subscriber *subscr);
int subscr_purge_inactive(struct gsm_network *net);
int subscr_purge_inactive(struct gsm_subscriber_group *sgrp);
void subscr_update_from_db(struct gsm_subscriber *subscr);
void subscr_expire(struct gsm_network *net);
void subscr_expire(struct gsm_subscriber_group *sgrp);
int subscr_update_expire_lu(struct gsm_subscriber *subscr, struct gsm_bts *bts);
/*
* Paging handling with authentication
*/
struct subscr_request *subscr_request_channel(struct gsm_subscriber *subscr,
int type, gsm_cbfn *cbfn, void *param);
void subscr_remove_request(struct subscr_request *req);
/* internal */
struct gsm_subscriber *subscr_alloc(void);

View File

@@ -11,7 +11,8 @@ struct ipac_msgt_sccp_state {
uint8_t dst_ref[3];
uint8_t trans_id;
uint8_t invoke_id;
char imsi[GSM_IMSI_LENGTH];
char imsi[GSM_IMSI_LENGTH];
uint8_t data[0];
} __attribute__((packed));
/*
@@ -26,22 +27,8 @@ struct ipac_ext_lac_cmd {
uint8_t data[0];
} __attribute__((packed));
/*
* methods for parsing and sending a message
*/
int ipaccess_rcvmsg_base(struct msgb *msg, struct osmo_fd *bfd);
void ipaccess_prepend_header(struct msgb *msg, int proto);
void ipaccess_prepend_header_ext(struct msgb *msg, int proto);
int ipaccess_send_pong(int fd);
int ipaccess_send_id_ack(int fd);
int ipaccess_send_id_req(int fd);
const char *ipaccess_idtag_name(uint8_t tag);
int ipaccess_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len);
int ipaccess_parse_unitid(const char *str, uint16_t *site_id, uint16_t *bts_id, uint16_t *trx_id);
int ipaccess_drop_oml(struct gsm_bts *bts);
int ipaccess_drop_rsl(struct gsm_bts_trx *trx);
void ipaccess_drop_oml(struct gsm_bts *bts);
void ipaccess_drop_rsl(struct gsm_bts_trx *trx);
struct sdp_header_item {
struct sdp_header_entry header_entry;

View File

@@ -0,0 +1,29 @@
#ifndef _OPENBSC_MEAS_FEED_H
#define _OPENBSC_MEAS_FEED_H
#include <stdint.h>
#include <openbsc/meas_rep.h>
struct meas_feed_hdr {
uint8_t msg_type;
uint8_t reserved;
uint16_t version;
};
struct meas_feed_meas {
struct meas_feed_hdr hdr;
char imsi[15+1];
char name[31+1];
char scenario[31+1];
struct gsm_meas_rep mr;
};
enum meas_feed_msgtype {
MEAS_FEED_MEAS = 0,
};
#define MEAS_FEED_VERSION 0
#endif

View File

@@ -3,6 +3,8 @@
#include <stdint.h>
#include <osmocom/gsm/meas_rep.h>
#define MRC_F_PROCESSED 0x0001
/* extracted from a L3 measurement report IE */
@@ -14,18 +16,6 @@ struct gsm_meas_rep_cell {
unsigned int flags;
};
/* RX Level and RX Quality */
struct gsm_rx_lev_qual {
uint8_t rx_lev;
uint8_t rx_qual;
};
/* unidirectional measumrement report */
struct gsm_meas_rep_unidir {
struct gsm_rx_lev_qual full;
struct gsm_rx_lev_qual sub;
};
#define MEAS_REP_F_UL_DTX 0x01
#define MEAS_REP_F_DL_VALID 0x02
#define MEAS_REP_F_BA1 0x04
@@ -60,17 +50,6 @@ struct gsm_meas_rep {
struct gsm_meas_rep_cell cell[6];
};
enum meas_rep_field {
MEAS_REP_DL_RXLEV_FULL,
MEAS_REP_DL_RXLEV_SUB,
MEAS_REP_DL_RXQUAL_FULL,
MEAS_REP_DL_RXQUAL_SUB,
MEAS_REP_UL_RXLEV_FULL,
MEAS_REP_UL_RXLEV_SUB,
MEAS_REP_UL_RXQUAL_FULL,
MEAS_REP_UL_RXQUAL_SUB,
};
/* obtain an average over the last 'num' fields in the meas reps */
int get_meas_rep_avg(const struct gsm_lchan *lchan,
enum meas_rep_field field, unsigned int num);

View File

@@ -25,6 +25,7 @@
#include <osmocom/core/msgb.h>
#include <osmocom/core/write_queue.h>
#include <osmocom/core/timer.h>
#include "debug.h"
@@ -64,6 +65,7 @@ static inline int rtp_calculate_port(int multiplex, int base)
struct mgcp_endpoint;
struct mgcp_config;
struct mgcp_trunk_config;
struct mgcp_rtp_end;
#define MGCP_ENDP_CRCX 1
#define MGCP_ENDP_DLCX 2
@@ -85,6 +87,24 @@ typedef int (*mgcp_policy)(struct mgcp_trunk_config *cfg, int endpoint, int stat
typedef int (*mgcp_reset)(struct mgcp_trunk_config *cfg);
typedef int (*mgcp_rqnt)(struct mgcp_endpoint *endp, char tone);
/**
* Return:
* < 0 in case no audio was processed
* >= 0 in case audio was processed. The remaining payload
* length will be returned.
*/
typedef int (*mgcp_processing)(struct mgcp_endpoint *endp,
struct mgcp_rtp_end *dst_end,
char *data, int *len, int buf_size);
typedef int (*mgcp_processing_setup)(struct mgcp_endpoint *endp,
struct mgcp_rtp_end *dst_end,
struct mgcp_rtp_end *src_end);
typedef void (*mgcp_get_format)(struct mgcp_endpoint *endp,
int *payload_type,
const char**subtype_name,
const char**fmtp_extra);
#define PORT_ALLOC_STATIC 0
#define PORT_ALLOC_DYNAMIC 1
@@ -103,6 +123,8 @@ struct mgcp_port_range {
int last_port;
};
#define MGCP_KEEPALIVE_ONCE (-1)
struct mgcp_trunk_config {
struct llist_head entry;
@@ -114,17 +136,34 @@ struct mgcp_trunk_config {
char *audio_fmtp_extra;
char *audio_name;
int audio_payload;
int audio_send_ptime;
int audio_send_name;
int audio_loop;
int no_audio_transcoding;
int omit_rtcp;
int keepalive_interval;
/* RTP patching */
int force_constant_ssrc; /* 0: don't, 1: once */
int force_aligned_timing;
/* spec handling */
int force_realloc;
/* timer */
struct osmo_timer_list keepalive_timer;
unsigned int number_endpoints;
struct mgcp_endpoint *endpoints;
};
enum mgcp_role {
MGCP_BSC = 0,
MGCP_BSC_NAT,
};
struct mgcp_config {
int source_port;
char *local_ip;
@@ -139,6 +178,12 @@ struct mgcp_config {
struct in_addr transcoder_in;
int transcoder_remote_base;
/* RTP processing */
mgcp_processing rtp_processing_cb;
mgcp_processing_setup setup_rtp_processing_cb;
mgcp_get_format get_net_downlink_format_cb;
struct osmo_wqueue gw_fd;
struct mgcp_port_range bts_ports;
@@ -146,6 +191,8 @@ struct mgcp_config {
struct mgcp_port_range transcoder_ports;
int endp_dscp;
int bts_force_ptime;
mgcp_change change_cb;
mgcp_policy policy_cb;
mgcp_reset reset_cb;
@@ -162,16 +209,36 @@ struct mgcp_config {
/* only used for start with a static configuration */
int last_net_port;
int last_bts_port;
enum mgcp_role role;
/* osmux translator: 0 means disabled, 1 means enabled */
int osmux;
/* The BSC-NAT may ask for enabling osmux on demand. This tells us if
* the osmux socket is already initialized.
*/
int osmux_init;
/* osmux batch factor: from 1 to 4 maximum */
int osmux_batch;
/* osmux batch size (in bytes) */
int osmux_batch_size;
/* osmux port */
uint16_t osmux_port;
};
/* config management */
struct mgcp_config *mgcp_config_alloc(void);
int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg);
int mgcp_parse_config(const char *config_file, struct mgcp_config *cfg,
enum mgcp_role role);
int mgcp_vty_init(void);
int mgcp_endpoints_allocate(struct mgcp_trunk_config *cfg);
void mgcp_free_endp(struct mgcp_endpoint *endp);
void mgcp_release_endp(struct mgcp_endpoint *endp);
void mgcp_initialize_endp(struct mgcp_endpoint *endp);
int mgcp_reset_transcoder(struct mgcp_config *cfg);
void mgcp_format_stats(struct mgcp_endpoint *endp, char *stats, size_t size);
int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os, uint32_t *pr, uint32_t *_or, int *loss, uint32_t *jitter);
void mgcp_trunk_set_keepalive(struct mgcp_trunk_config *tcfg, int interval);
/*
* format helper functions
@@ -199,4 +266,8 @@ int mgcp_send_reset_ep(struct mgcp_endpoint *endp, int endpoint);
int mgcp_send_reset_all(struct mgcp_config *cfg);
int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port);
int mgcp_send(struct mgcp_endpoint *endp, int dest, int is_rtp, struct sockaddr_in *addr, char *buf, int rc);
int mgcp_udp_send(int fd, struct in_addr *addr, int port, char *buf, int len);
#endif

View File

@@ -20,8 +20,7 @@
*
*/
#ifndef OPENBSC_MGCP_DATA_H
#define OPENBSC_MGCP_DATA_H
#pragma once
#include <osmocom/core/select.h>
@@ -32,7 +31,7 @@ enum mgcp_connection_mode {
MGCP_CONN_RECV_ONLY = 1,
MGCP_CONN_SEND_ONLY = 2,
MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
MGCP_CONN_LOOPBACK = 4,
MGCP_CONN_LOOPBACK = 4 | MGCP_CONN_RECV_SEND,
};
enum mgcp_trunk_type {
@@ -40,36 +39,75 @@ enum mgcp_trunk_type {
MGCP_TRUNK_E1,
};
struct mgcp_rtp_stream_state {
uint32_t ssrc;
uint16_t last_seq;
uint32_t last_timestamp;
uint32_t err_ts_counter;
int32_t last_tsdelta;
uint32_t last_arrival_time;
};
struct mgcp_rtp_state {
int initialized;
int patch;
int patch_ssrc;
uint32_t orig_ssrc;
uint32_t ssrc;
uint16_t base_seq;
uint16_t max_seq;
int seq_offset;
int cycles;
uint32_t last_timestamp;
int32_t timestamp_offset;
uint32_t jitter;
int32_t transit;
uint32_t packet_duration;
struct mgcp_rtp_stream_state in_stream;
struct mgcp_rtp_stream_state out_stream;
/* jitter and packet loss calculation */
int stats_initialized;
uint16_t stats_base_seq;
uint16_t stats_max_seq;
uint32_t stats_ssrc;
uint32_t stats_jitter;
int32_t stats_transit;
int stats_cycles;
};
struct mgcp_rtp_codec {
uint32_t rate;
int channels;
uint32_t frame_duration_num;
uint32_t frame_duration_den;
int payload_type;
char *audio_name;
char *subtype_name;
};
struct mgcp_rtp_end {
/* statistics */
unsigned int packets;
unsigned int octets;
unsigned int dropped_packets;
struct in_addr addr;
/* in network byte order */
int rtp_port, rtcp_port;
/* audio codec information */
struct mgcp_rtp_codec codec;
struct mgcp_rtp_codec alt_codec; /* TODO/XXX: make it generic */
/* per endpoint data */
int payload_type;
int frames_per_packet;
uint32_t packet_duration_ms;
char *fmtp_extra;
int output_enabled;
int force_output_ptime;
/* RTP patching */
int force_constant_ssrc; /* -1: always, 0: don't, 1: once */
int force_aligned_timing;
void *rtp_process_data;
/*
* Each end has a socket...
@@ -96,11 +134,27 @@ struct mgcp_rtp_tap {
struct sockaddr_in forward;
};
struct mgcp_lco {
char *string;
char *codec;
int pkt_period_min; /* time in ms */
int pkt_period_max; /* time in ms */
};
enum mgcp_type {
MGCP_RTP_DEFAULT = 0,
MGCP_RTP_TRANSCODED,
MGCP_OSMUX_BSC,
MGCP_OSMUX_BSC_NAT,
};
#include <openbsc/osmux.h>
struct mgcp_endpoint {
int allocated;
uint32_t ci;
char *callid;
char *local_options;
struct mgcp_lco local_options;
int conn_mode;
int orig_mode;
@@ -119,24 +173,37 @@ struct mgcp_endpoint {
*/
struct mgcp_rtp_end trans_bts;
struct mgcp_rtp_end trans_net;
int is_transcoded;
enum mgcp_type type;
/* sequence bits */
struct mgcp_rtp_state net_state;
struct mgcp_rtp_state bts_state;
/* SSRC/seq/ts patching for loop */
int allow_patch;
/* fields for re-transmission */
char *last_trans;
char *last_response;
/* tap for the endpoint */
struct mgcp_rtp_tap taps[MGCP_TAP_COUNT];
struct {
/* Osmux state: disabled, activating, active */
enum osmux_state state;
/* Allocated Osmux circuit ID for this endpoint */
uint8_t cid;
/* handle to batch messages */
struct osmux_in_handle *in;
/* handle to unbatch messages */
struct osmux_out_handle out;
/* statistics */
struct {
uint32_t chunks;
uint32_t octets;
} stats;
} osmux;
};
#define ENDPOINT_NUMBER(endp) abs(endp - endp->tcfg->endpoints)
#define ENDPOINT_NUMBER(endp) abs((int)(endp - endp->tcfg->endpoints))
struct mgcp_msg_ptr {
unsigned int start;
@@ -159,9 +226,39 @@ static inline int endp_back_channel(int endpoint)
struct mgcp_trunk_config *mgcp_trunk_alloc(struct mgcp_config *cfg, int index);
struct mgcp_trunk_config *mgcp_trunk_num(struct mgcp_config *cfg, int index);
void mgcp_rtp_end_config(struct mgcp_endpoint *endp, int expect_ssrc_change,
struct mgcp_rtp_end *rtp);
uint32_t mgcp_rtp_packet_duration(struct mgcp_endpoint *endp,
struct mgcp_rtp_end *rtp);
void mgcp_state_calc_loss(struct mgcp_rtp_state *s, struct mgcp_rtp_end *,
uint32_t *expected, int *loss);
uint32_t mgcp_state_calc_jitter(struct mgcp_rtp_state *);
/* payload processing default functions */
int mgcp_rtp_processing_default(struct mgcp_endpoint *endp, struct mgcp_rtp_end *dst_end,
char *data, int *len, int buf_size);
int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
struct mgcp_rtp_end *dst_end,
struct mgcp_rtp_end *src_end);
void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
int *payload_type,
const char**subtype_name,
const char**fmtp_extra);
/* internal RTP Annex A counting */
void mgcp_rtp_annex_count(struct mgcp_endpoint *endp, struct mgcp_rtp_state *state,
const uint16_t seq, const int32_t transit,
const uint32_t ssrc);
int mgcp_set_ip_tos(int fd, int tos);
enum {
MGCP_DEST_NET = 0,
MGCP_DEST_BTS,
};
#define MGCP_DUMMY_LOAD 0x23
#endif

View File

@@ -0,0 +1,89 @@
/*
* (C) 2014 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef OPENBSC_MGCP_TRANSCODE_H
#define OPENBSC_MGCP_TRANSCODE_H
#include "bscconfig.h"
#include <gsm.h>
#ifdef HAVE_BCG729
#include <bcg729/decoder.h>
#include <bcg729/encoder.h>
#endif
enum audio_format {
AF_INVALID,
AF_S16,
AF_L16,
AF_GSM,
AF_G729,
AF_PCMA
};
struct mgcp_process_rtp_state {
/* decoding */
enum audio_format src_fmt;
union {
gsm gsm_handle;
#ifdef HAVE_BCG729
bcg729DecoderChannelContextStruct *g729_dec;
#endif
} src;
size_t src_frame_size;
size_t src_samples_per_frame;
/* processing */
/* encoding */
enum audio_format dst_fmt;
union {
gsm gsm_handle;
#ifdef HAVE_BCG729
bcg729EncoderChannelContextStruct *g729_enc;
#endif
} dst;
size_t dst_frame_size;
size_t dst_samples_per_frame;
int dst_packet_duration;
int is_running;
uint16_t next_seq;
uint32_t next_time;
int16_t samples[10*160];
size_t sample_cnt;
size_t sample_offs;
};
int mgcp_transcoding_setup(struct mgcp_endpoint *endp,
struct mgcp_rtp_end *dst_end,
struct mgcp_rtp_end *src_end);
void mgcp_transcoding_net_downlink_format(struct mgcp_endpoint *endp,
int *payload_type,
const char**audio_name,
const char**fmtp_extra);
int mgcp_transcoding_process_rtp(struct mgcp_endpoint *endp,
struct mgcp_rtp_end *dst_end,
char *data, int *len, int buf_size);
int mgcp_transcoding_get_frame_size(void *state_, int nsamples, int dst);
#endif /* OPENBSC_MGCP_TRANSCODE_H */

View File

@@ -44,6 +44,10 @@ struct gsm_call {
uint32_t callref;
/* the 'remote' transaction */
uint32_t remote_ref;
/* the capabilities */
uint8_t lchan_type;
struct gsm_mncc_bearer_cap bcap;
};
#define MNCC_SETUP_REQ 0x0101
@@ -92,9 +96,15 @@ struct gsm_call {
#define MNCC_FRAME_RECV 0x0201
#define MNCC_FRAME_DROP 0x0202
#define MNCC_LCHAN_MODIFY 0x0203
#define MNCC_RTP_CREATE 0x0204
#define MNCC_RTP_CONNECT 0x0205
#define MNCC_RTP_FREE 0x0206
#define GSM_TCHF_FRAME 0x0300
#define GSM_TCHF_FRAME_EFR 0x0301
#define GSM_TCHH_FRAME 0x0302
#define GSM_TCH_FRAME_AMR 0x0303
#define GSM_BAD_FRAME 0x03ff
#define MNCC_SOCKET_HELLO 0x0400
@@ -160,7 +170,7 @@ struct gsm_data_frame {
unsigned char data[0];
};
#define MNCC_SOCK_VERSION 2
#define MNCC_SOCK_VERSION 5
struct gsm_mncc_hello {
uint32_t msg_type;
uint32_t version;
@@ -176,6 +186,15 @@ struct gsm_mncc_hello {
uint32_t lchan_type_offset;
};
struct gsm_mncc_rtp {
uint32_t msg_type;
uint32_t callref;
uint32_t ip;
uint16_t port;
uint32_t payload_type;
uint32_t payload_msg_type;
};
char *get_mncc_name(int value);
void mncc_set_cause(struct gsm_mncc *data, int loc, int val);
void cc_tx_to_mncc(struct gsm_network *net, struct msgb *msg);
@@ -188,4 +207,12 @@ int mncc_sock_from_cc(struct gsm_network *net, struct msgb *msg);
int mncc_sock_init(struct gsm_network *gsmnet);
#define mncc_is_data_frame(msg_type) \
(msg_type == GSM_TCHF_FRAME \
|| msg_type == GSM_TCHF_FRAME_EFR \
|| msg_type == GSM_TCHH_FRAME \
|| msg_type == GSM_TCH_FRAME_AMR \
|| msg_type == GSM_BAD_FRAME)
#endif

View File

@@ -3,10 +3,4 @@
#include <stdint.h>
struct mncc_int {
uint8_t def_codec[2];
};
extern struct mncc_int mncc_int;
#endif

View File

@@ -0,0 +1,47 @@
/*
* (C) 2013 by On-Waves
* (C) 2013 by Holger Hans Peter Freyther <zecke@selfish.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef NAT_REWRITE_FILE_H
#define NAT_REWRITE_FILE_H
#include <osmocom/core/linuxrbtree.h>
struct vty;
struct nat_rewrite_rule {
/* For digits 0-9 and + */
struct nat_rewrite_rule *rules[11];
char empty;
char prefix[14];
char rewrite[6];
};
struct nat_rewrite {
struct nat_rewrite_rule rule;
size_t prefixes;
};
struct nat_rewrite *nat_rewrite_parse(void *ctx, const char *filename);
struct nat_rewrite_rule *nat_rewrite_lookup(struct nat_rewrite *, const char *prefix);
void nat_rewrite_dump(struct nat_rewrite *rewr);
void nat_rewrite_dump_vty(struct vty *vty, struct nat_rewrite *rewr);
#endif

View File

@@ -4,9 +4,17 @@
#define OSMO_BSC_H
#include "bsc_api.h"
#include "bsc_msg_filter.h"
#define BSS_SEND_USSD 1
enum bsc_con {
BSC_CON_SUCCESS,
BSC_CON_REJECT_NO_LINK,
BSC_CON_REJECT_RF_GRACE,
BSC_CON_NO_MEM,
};
struct sccp_connection;
struct osmo_msc_data;
struct bsc_msc_connection;
@@ -15,8 +23,14 @@ struct osmo_bsc_sccp_con {
struct llist_head entry;
int ciphering_handled;
/* for audio handling */
uint16_t cic;
int rtp_port;
/* for advanced ping/pong */
int send_ping;
/* SCCP connection realted */
struct sccp_connection *sccp;
struct osmo_msc_data *msc;
@@ -28,14 +42,16 @@ struct osmo_bsc_sccp_con {
struct gsm_subscriber_connection *conn;
uint8_t new_subscriber;
struct bsc_filter_state filter_state;
};
struct bsc_api *osmo_bsc_api();
int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg);
int bsc_open_connection(struct osmo_bsc_sccp_con *sccp, struct msgb *msg);
int bsc_create_new_connection(struct gsm_subscriber_connection *conn,
struct osmo_msc_data *msc);
enum bsc_con bsc_create_new_connection(struct gsm_subscriber_connection *conn,
struct osmo_msc_data *msc, int send_ping);
int bsc_delete_connection(struct osmo_bsc_sccp_con *sccp);
struct osmo_msc_data *bsc_find_msc(struct gsm_subscriber_connection *conn, struct msgb *);
@@ -48,4 +64,8 @@ int bsc_handle_dt1(struct osmo_bsc_sccp_con *conn, struct msgb *msg, unsigned in
int bsc_ctrl_cmds_install();
void bsc_gen_location_state_trap(struct gsm_bts *bts);
struct llist_head *bsc_access_lists(void);
#endif

View File

@@ -33,6 +33,8 @@ struct osmo_bsc_rf {
const char *last_state_command;
char *last_rf_lock_ctrl_command;
/* delay the command */
char last_request;
struct osmo_timer_list delay_cmd;

View File

@@ -1,8 +1,8 @@
/*
* Data for the true BSC
*
* (C) 2010-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010-2011 by On-Waves
* (C) 2010-2015 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010-2015 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
@@ -63,9 +63,12 @@ struct osmo_msc_data {
int pong_timeout;
struct osmo_timer_list ping_timer;
struct osmo_timer_list pong_timer;
int advanced_ping;
struct bsc_msc_connection *msc_con;
int core_ncc;
int core_mcc;
int core_lac;
int core_ci;
int rtp_base;
/* audio codecs */
@@ -83,6 +86,14 @@ struct osmo_msc_data {
struct osmo_wqueue mgcp_agent;
int nr;
/* ussd msc connection lost text */
char *ussd_msc_lost_txt;
/* ussd text when MSC has entered the grace period */
char *ussd_grace_txt;
char *acc_lst_name;
};
/*
@@ -100,12 +111,18 @@ struct osmo_bsc_data {
char *rf_ctrl_name;
struct osmo_bsc_rf *rf_ctrl;
int auto_off_timeout;
/* ussd text when there is no MSC available */
char *ussd_no_msc_txt;
char *acc_lst_name;
};
int osmo_bsc_msc_init(struct osmo_msc_data *msc);
int osmo_bsc_sccp_init(struct gsm_network *gsmnet);
int msc_queue_write(struct bsc_msc_connection *conn, struct msgb *msg, int proto);
int msc_queue_write_with_ping(struct bsc_msc_connection *, struct msgb *msg, int proto);
int osmo_bsc_audio_init(struct gsm_network *network);

View File

@@ -0,0 +1,32 @@
#ifndef _OPENBSC_OSMUX_H_
#define _OPENBSC_OSMUX_H_
#include <osmocom/netif/osmux.h>
#define OSMUX_PORT 1984
enum {
OSMUX_ROLE_BSC = 0,
OSMUX_ROLE_BSC_NAT,
};
int osmux_init(int role, struct mgcp_config *cfg);
int osmux_enable_endpoint(struct mgcp_endpoint *endp, int role,
struct in_addr *addr, uint16_t port);
void osmux_disable_endpoint(struct mgcp_endpoint *endp);
int osmux_xfrm_to_rtp(struct mgcp_endpoint *endp, int type, char *buf, int rc);
int osmux_xfrm_to_osmux(int type, char *buf, int rc, struct mgcp_endpoint *endp);
int osmux_send_dummy(struct mgcp_endpoint *endp);
int osmux_get_cid(void);
void osmux_put_cid(uint8_t osmux_cid);
enum osmux_state {
OSMUX_STATE_DISABLED = 0,
OSMUX_STATE_ACTIVATING,
OSMUX_STATE_ENABLED,
};
#endif

View File

@@ -55,7 +55,7 @@ struct gsm48_si_ro_info {
int rest_octets_si3(uint8_t *data, const struct gsm48_si_ro_info *si3);
/* Generate SI4 Rest Octets (Chapter 10.5.2.35) */
int rest_octets_si4(uint8_t *data, const struct gsm48_si_ro_info *si4);
int rest_octets_si4(uint8_t *data, const struct gsm48_si_ro_info *si4, int len);
enum pbcch_carrier_type {
PBCCH_BCCH,

View File

@@ -33,11 +33,16 @@
#define RTP_PT_GSM_HALF 96
#define RTP_PT_GSM_EFR 97
#define RTP_PT_AMR 98
#define RTP_LEN_GSM_FULL 33
#define RTP_LEN_GSM_HALF 15
#define RTP_LEN_GSM_EFR 31
#define RTP_GSM_DURATION 160
enum rtp_rx_action {
RTP_NONE,
RTP_PROXY,
RTP_RECV_UPSTREAM,
RTP_PROXY, /* forward from BTS to BTS */
RTP_RECV_UPSTREAM, /* forward to application */
RTP_RECV_APP, /* receive RTP frames from application */
};
enum rtp_tx_action {
@@ -69,6 +74,8 @@ struct rtp_socket {
struct {
struct gsm_network *net;
uint32_t callref;
uint8_t payload_type; /* dynamic PT */
int msg_type; /* message type for dynamic PT */
} receive;
};
enum rtp_tx_action tx_action;

View File

@@ -7,6 +7,15 @@
#include <osmocom/gprs/gprs_ns.h>
#include <openbsc/gprs_sgsn.h>
struct gprs_gsup_client;
enum sgsn_auth_policy {
SGSN_AUTH_POLICY_OPEN,
SGSN_AUTH_POLICY_CLOSED,
SGSN_AUTH_POLICY_ACL_ONLY,
SGSN_AUTH_POLICY_REMOTE
};
struct sgsn_config {
/* parsed from config file */
@@ -15,6 +24,15 @@ struct sgsn_config {
/* misc */
struct gprs_ns_inst *nsi;
enum sgsn_auth_policy auth_policy;
struct llist_head imsi_acl;
struct sockaddr_in gsup_server_addr;
int gsup_server_port;
int require_authentication;
int require_update_location;
};
struct sgsn_instance {
@@ -28,6 +46,10 @@ struct sgsn_instance {
struct osmo_timer_list gtp_timer;
/* GSN instance for libgtp */
struct gsn_t *gsn;
/* Subscriber */
struct gprs_gsup_client *gsup_client;
/* LLME inactivity timer */
struct osmo_timer_list llme_timer;
};
extern struct sgsn_instance *sgsn;

View File

@@ -0,0 +1,4 @@
#pragma once
int smpp_openbsc_init(void *ctx, uint16_t port);
void smpp_openbsc_set_net(struct gsm_network *net);

View File

@@ -14,6 +14,9 @@ struct gsm_trans {
/* Entry in list of all transactions */
struct llist_head entry;
/* Back pointer to the netweork struct */
struct gsm_network *net;
/* The protocol within which we live */
uint8_t protocol;
@@ -28,12 +31,13 @@ struct gsm_trans {
/* reference from MNCC or other application */
uint32_t callref;
uint32_t callref_keep; /* to remember callref, even if it is removed */
/* if traffic channel receive was requested */
int tch_recv;
/* is thats one paging? */
struct gsm_network **paging_request;
struct subscr_request *paging_request;
union {
struct {
@@ -46,6 +50,7 @@ struct gsm_trans {
int T308_second; /* used to send release again */
struct osmo_timer_list timer;
struct gsm_mncc msg; /* stores setup/disconnect/release message */
struct rtp_socket *rs; /* application traffic via RTP */
} cc;
struct {
struct gsm411_smc_inst smc_inst;
@@ -58,17 +63,18 @@ struct gsm_trans {
struct gsm_trans *trans_find_by_id(struct gsm_subscriber *subscr,
struct gsm_trans *trans_find_by_id(struct gsm_subscriber_connection *conn,
uint8_t proto, uint8_t trans_id);
struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
uint32_t callref);
struct gsm_trans *trans_alloc(struct gsm_subscriber *subscr,
struct gsm_trans *trans_alloc(struct gsm_network *net,
struct gsm_subscriber *subscr,
uint8_t protocol, uint8_t trans_id,
uint32_t callref);
void trans_free(struct gsm_trans *trans);
int trans_assign_trans_id(struct gsm_subscriber *subscr,
int trans_assign_trans_id(struct gsm_network *net, struct gsm_subscriber *subscr,
uint8_t protocol, uint8_t ti_flag);
int trans_has_conn(const struct gsm_subscriber_connection *conn);

View File

@@ -32,6 +32,8 @@
#include <openbsc/gsm_data.h>
#include <openbsc/mncc.h>
struct decoded_trau_frame;
/* map a TRAU mux map entry */
int trau_mux_map(const struct gsm_e1_subslot *src,
const struct gsm_e1_subslot *dst);
@@ -51,5 +53,18 @@ int trau_recv_lchan(struct gsm_lchan *lchan, uint32_t callref);
/* send trau from application */
int trau_send_frame(struct gsm_lchan *lchan, struct gsm_data_frame *frame);
/* switch trau muxer to new lchan */
int switch_trau_mux(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan);
/* callback invoked if we receive TRAU frames */
int subch_cb(struct subch_demux *dmx, int ch, uint8_t *data, int len, void *_priv);
/* TRAU frame transcoding */
struct msgb *trau_decode_fr(uint32_t callref,
const struct decoded_trau_frame *tf);
struct msgb *trau_decode_efr(uint32_t callref,
const struct decoded_trau_frame *tf);
void trau_encode_fr(struct decoded_trau_frame *tf,
const unsigned char *data);
void trau_encode_efr(struct decoded_trau_frame *tf,
const unsigned char *data);

View File

@@ -14,8 +14,6 @@ struct buffer *vty_argv_to_buffer(int argc, const char *argv[], int base);
extern struct cmd_element cfg_description_cmd;
extern struct cmd_element cfg_no_description_cmd;
extern struct cmd_element ournode_exit_cmd;
extern struct cmd_element ournode_end_cmd;
enum bsc_vty_node {
GSMNET_NODE = _LAST_OSMOVTY_NODE + 1,
@@ -34,6 +32,7 @@ enum bsc_vty_node {
TRUNK_NODE,
PGROUP_NODE,
MNCC_INT_NODE,
NITB_NODE,
BSC_NODE,
SMPP_NODE,
SMPP_ESME_NODE,

52
openbsc/osmoappdesc.py Normal file
View File

@@ -0,0 +1,52 @@
#!/usr/bin/env python
# (C) 2013 by Katerina Barone-Adesi <kat.obsc@gmail.com>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
# Most systems won't be able to use these, so they're separated out
nitb_e1_configs = [
"doc/examples/osmo-nitb/bs11/openbsc-2bts-2trx.cfg",
"doc/examples/osmo-nitb/bs11/openbsc-1bts-2trx-hopping.cfg",
"doc/examples/osmo-nitb/bs11/openbsc-1bts-2trx.cfg",
"doc/examples/osmo-nitb/bs11/openbsc.cfg",
"doc/examples/osmo-nitb/nokia/openbsc_nokia_3trx.cfg",
"doc/examples/osmo-nitb/nanobts/openbsc-multitrx.cfg",
"doc/examples/osmo-nitb/rbs2308/openbsc.cfg"
]
app_configs = {
"osmo-bsc": ["doc/examples/osmo-bsc/osmo-bsc.cfg"],
"nat": ["doc/examples/osmo-bsc_nat/osmo-bsc_nat.cfg"],
"mgcp": ["doc/examples/osmo-bsc_mgcp/mgcp.cfg"],
"gbproxy": ["doc/examples/osmo-gbproxy/osmo-gbproxy.cfg"],
"sgsn": ["doc/examples/osmo-sgsn/osmo-sgsn.cfg"],
"nitb": ["doc/examples/osmo-nitb/nanobts/openbsc-multitrx.cfg",
"doc/examples/osmo-nitb/nanobts/openbsc.cfg"]
}
apps = [(4242, "src/osmo-bsc/osmo-bsc", "OsmoBSC", "osmo-bsc"),
(4244, "src/osmo-bsc_nat/osmo-bsc_nat", "OsmoBSCNAT", "nat"),
(4243, "src/osmo-bsc_mgcp/osmo-bsc_mgcp", "OpenBSC MGCP", "mgcp"),
(4246, "src/gprs/osmo-gbproxy", "OsmoGbProxy", "gbproxy"),
(4245, "src/gprs/osmo-sgsn", "OsmoSGSN", "sgsn"),
(4242, "src/osmo-nitb/osmo-nitb", "OpenBSC", "nitb")
]
vty_command = ["./src/osmo-nitb/osmo-nitb", "-c",
"doc/examples/osmo-nitb/nanobts/openbsc.cfg"]
vty_app = apps[-1]

View File

@@ -1,8 +1,8 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS)
AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(COVERAGE_LDFLAGS)
SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libctrl osmo-nitb osmo-bsc_mgcp utils ipaccess gprs
SUBDIRS = libcommon libmgcp libbsc libmsc libtrau libfilter osmo-nitb osmo-bsc_mgcp utils ipaccess gprs
# Conditional modules
if BUILD_NAT

View File

@@ -1,9 +1,9 @@
INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CFLAGS=-Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOCTRL_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) $(LIBOSMOGB_CFLAGS) $(COVERAGE_CFLAGS)
OSMO_LIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \
$(LIBOSMOGB_LIBS)
$(LIBOSMOCTRL_LIBS) $(LIBOSMOGB_LIBS)
noinst_HEADERS = gprs_sndcp.h
@@ -13,12 +13,18 @@ else
bin_PROGRAMS = osmo-gbproxy
endif
osmo_gbproxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c
osmo_gbproxy_SOURCES = gb_proxy.c gb_proxy_main.c gb_proxy_vty.c \
gb_proxy_patch.c gb_proxy_tlli.c gb_proxy_peer.c \
gprs_gb_parse.c gprs_llc_parse.c crc24.c gprs_utils.c
osmo_gbproxy_LDADD = $(top_builddir)/src/libcommon/libcommon.a \
$(OSMO_LIBS)
$(OSMO_LIBS) -lrt
osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \
sgsn_main.c sgsn_vty.c sgsn_libgtp.c \
gprs_llc.c gprs_llc_vty.c crc24.c
osmo_sgsn_LDADD = $(top_builddir)/src/libcommon/libcommon.a \
-lgtp $(OSMO_LIBS)
gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c crc24.c \
sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \
gprs_gsup_messages.c gprs_utils.c gprs_gsup_client.c \
gsm_04_08_gprs.c
osmo_sgsn_LDADD = \
$(top_builddir)/src/libcommon/libcommon.a \
-lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) -lrt

File diff suppressed because it is too large Load Diff

View File

@@ -48,12 +48,10 @@
#include <osmocom/vty/command.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/logging.h>
#include <osmocom/vty/ports.h>
#include "../../bscconfig.h"
/* this is here for the vty... it will never be called */
void subscr_put() { abort(); }
#define _GNU_SOURCE
#include <getopt.h>
@@ -66,7 +64,7 @@ const char *openbsc_copyright =
"There is NO WARRANTY, to the extent permitted by law.\r\n";
static char *config_file = "osmo_gbproxy.cfg";
struct gbproxy_config gbcfg;
struct gbproxy_config gbcfg = {0};
static int daemonize = 0;
/* Pointer to the SGSN peer */
@@ -80,7 +78,7 @@ static int proxy_ns_cb(enum gprs_ns_evt event, struct gprs_nsvc *nsvc,
switch (event) {
case GPRS_NS_EVT_UNIT_DATA:
rc = gbprox_rcvmsg(msg, nsvc, bvci);
rc = gbprox_rcvmsg(&gbcfg, msg, nsvc->nsei, bvci, nsvc->nsvci);
break;
default:
LOGP(DGPRS, LOGL_ERROR, "SGSN: Unknown event %u from NS\n", event);
@@ -171,7 +169,7 @@ static void handle_options(int argc, char **argv)
daemonize = 1;
break;
case 'c':
config_file = strdup(optarg);
config_file = optarg;
break;
case 'T':
log_set_print_timestamp(osmo_stderr_target, 1);
@@ -250,7 +248,7 @@ int main(int argc, char **argv)
rate_ctr_init(tall_bsc_ctx);
rc = telnet_init(tall_bsc_ctx, &dummy_network, 4246);
rc = telnet_init(tall_bsc_ctx, &dummy_network, OSMO_VTY_PORT_GBPROXY);
if (rc < 0)
exit(1);
@@ -259,11 +257,12 @@ int main(int argc, char **argv)
LOGP(DGPRS, LOGL_ERROR, "Unable to instantiate NS\n");
exit(1);
}
gbproxy_init_config(&gbcfg);
gbcfg.nsi = bssgp_nsi;
gprs_ns_vty_init(bssgp_nsi);
gprs_ns_set_log_ss(DNS);
bssgp_set_log_ss(DBSSGP);
osmo_signal_register_handler(SS_L_NS, &gbprox_signal, NULL);
osmo_signal_register_handler(SS_L_NS, &gbprox_signal, &gbcfg);
rc = gbproxy_parse_config(config_file, &gbcfg);
if (rc < 0) {

View File

@@ -0,0 +1,459 @@
/* Gb-proxy message patching */
/* (C) 2014 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <openbsc/gb_proxy.h>
#include <openbsc/gprs_utils.h>
#include <openbsc/gprs_gb_parse.h>
#include <openbsc/gsm_04_08_gprs.h>
#include <openbsc/gsm_data.h>
#include <openbsc/debug.h>
#include <osmocom/gprs/protocol/gsm_08_18.h>
#include <osmocom/core/rate_ctr.h>
/* patch RA identifier in place */
static void gbproxy_patch_raid(uint8_t *raid_enc, struct gbproxy_peer *peer,
int to_bss, const char *log_text)
{
struct gbproxy_patch_state *state = &peer->patch_state;
int old_mcc;
int old_mnc;
struct gprs_ra_id raid;
enum gbproxy_peer_ctr counter =
to_bss ?
GBPROX_PEER_CTR_RAID_PATCHED_SGSN :
GBPROX_PEER_CTR_RAID_PATCHED_BSS;
if (!state->local_mcc || !state->local_mnc)
return;
gsm48_parse_ra(&raid, raid_enc);
old_mcc = raid.mcc;
old_mnc = raid.mnc;
if (!to_bss) {
/* BSS -> SGSN */
if (state->local_mcc)
raid.mcc = peer->cfg->core_mcc;
if (state->local_mnc)
raid.mnc = peer->cfg->core_mnc;
} else {
/* SGSN -> BSS */
if (state->local_mcc)
raid.mcc = state->local_mcc;
if (state->local_mnc)
raid.mnc = state->local_mnc;
}
LOGP(DGPRS, LOGL_DEBUG,
"Patching %s to %s: "
"%d-%d-%d-%d -> %d-%d-%d-%d\n",
log_text,
to_bss ? "BSS" : "SGSN",
old_mcc, old_mnc, raid.lac, raid.rac,
raid.mcc, raid.mnc, raid.lac, raid.rac);
gsm48_construct_ra(raid_enc, &raid);
rate_ctr_inc(&peer->ctrg->ctr[counter]);
}
static void gbproxy_patch_apn_ie(struct msgb *msg,
uint8_t *apn_ie, size_t apn_ie_len,
struct gbproxy_peer *peer,
size_t *new_apn_ie_len, const char *log_text)
{
struct apn_ie_hdr {
uint8_t iei;
uint8_t apn_len;
uint8_t apn[0];
} *hdr = (void *)apn_ie;
size_t apn_len = hdr->apn_len;
uint8_t *apn = hdr->apn;
OSMO_ASSERT(apn_ie_len == apn_len + sizeof(struct apn_ie_hdr));
OSMO_ASSERT(apn_ie_len > 2 && apn_ie_len <= 102);
if (peer->cfg->core_apn_size == 0) {
char str1[110];
/* Remove the IE */
LOGP(DGPRS, LOGL_DEBUG,
"Patching %s to SGSN: Removing APN '%s'\n",
log_text,
gprs_apn_to_str(str1, apn, apn_len));
*new_apn_ie_len = 0;
gprs_msgb_resize_area(msg, apn_ie, apn_ie_len, 0);
} else {
/* Resize the IE */
char str1[110];
char str2[110];
OSMO_ASSERT(peer->cfg->core_apn_size <= 100);
LOGP(DGPRS, LOGL_DEBUG,
"Patching %s to SGSN: "
"Replacing APN '%s' -> '%s'\n",
log_text,
gprs_apn_to_str(str1, apn, apn_len),
gprs_apn_to_str(str2, peer->cfg->core_apn,
peer->cfg->core_apn_size));
*new_apn_ie_len = peer->cfg->core_apn_size + 2;
gprs_msgb_resize_area(msg, apn, apn_len, peer->cfg->core_apn_size);
memcpy(apn, peer->cfg->core_apn, peer->cfg->core_apn_size);
hdr->apn_len = peer->cfg->core_apn_size;
}
rate_ctr_inc(&peer->ctrg->ctr[GBPROX_PEER_CTR_APN_PATCHED]);
}
static int gbproxy_patch_tlli(uint8_t *tlli_enc,
struct gbproxy_peer *peer,
uint32_t new_tlli,
int to_bss, const char *log_text)
{
uint32_t tlli_be;
uint32_t tlli;
enum gbproxy_peer_ctr counter =
to_bss ?
GBPROX_PEER_CTR_TLLI_PATCHED_SGSN :
GBPROX_PEER_CTR_TLLI_PATCHED_BSS;
memcpy(&tlli_be, tlli_enc, sizeof(tlli_be));
tlli = ntohl(tlli_be);
if (tlli == new_tlli)
return 0;
LOGP(DGPRS, LOGL_DEBUG,
"Patching %ss: "
"Replacing %08x -> %08x\n",
log_text, tlli, new_tlli);
tlli_be = htonl(new_tlli);
memcpy(tlli_enc, &tlli_be, sizeof(tlli_be));
rate_ctr_inc(&peer->ctrg->ctr[counter]);
return 1;
}
static int gbproxy_patch_ptmsi(uint8_t *ptmsi_enc,
struct gbproxy_peer *peer,
uint32_t new_ptmsi,
int to_bss, const char *log_text)
{
uint32_t ptmsi_be;
uint32_t ptmsi;
enum gbproxy_peer_ctr counter =
to_bss ?
GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN :
GBPROX_PEER_CTR_PTMSI_PATCHED_BSS;
memcpy(&ptmsi_be, ptmsi_enc, sizeof(ptmsi_be));
ptmsi = ntohl(ptmsi_be);
if (ptmsi == new_ptmsi)
return 0;
LOGP(DGPRS, LOGL_DEBUG,
"Patching %ss: "
"Replacing %08x -> %08x\n",
log_text, ptmsi, new_ptmsi);
ptmsi_be = htonl(new_ptmsi);
memcpy(ptmsi_enc, &ptmsi_be, sizeof(ptmsi_be));
rate_ctr_inc(&peer->ctrg->ctr[counter]);
return 1;
}
int gbproxy_patch_llc(struct msgb *msg, uint8_t *llc, size_t llc_len,
struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info, int *len_change,
struct gprs_gb_parse_context *parse_ctx)
{
struct gprs_llc_hdr_parsed *ghp = &parse_ctx->llc_hdr_parsed;
int have_patched = 0;
int fcs;
struct gbproxy_config *cfg = peer->cfg;
if (parse_ctx->ptmsi_enc && link_info &&
!parse_ctx->old_raid_is_foreign && peer->cfg->patch_ptmsi) {
uint32_t ptmsi;
if (parse_ctx->to_bss)
ptmsi = link_info->tlli.ptmsi;
else
ptmsi = link_info->sgsn_tlli.ptmsi;
if (ptmsi != GSM_RESERVED_TMSI) {
if (gbproxy_patch_ptmsi(parse_ctx->ptmsi_enc, peer,
ptmsi, parse_ctx->to_bss, "P-TMSI"))
have_patched = 1;
} else {
/* TODO: invalidate old RAI if present (see below) */
}
}
if (parse_ctx->new_ptmsi_enc && link_info && cfg->patch_ptmsi) {
uint32_t ptmsi;
if (parse_ctx->to_bss)
ptmsi = link_info->tlli.ptmsi;
else
ptmsi = link_info->sgsn_tlli.ptmsi;
OSMO_ASSERT(ptmsi);
if (gbproxy_patch_ptmsi(parse_ctx->new_ptmsi_enc, peer,
ptmsi, parse_ctx->to_bss, "new P-TMSI"))
have_patched = 1;
}
if (parse_ctx->raid_enc) {
gbproxy_patch_raid(parse_ctx->raid_enc, peer, parse_ctx->to_bss,
parse_ctx->llc_msg_name);
have_patched = 1;
}
if (parse_ctx->old_raid_enc && !parse_ctx->old_raid_is_foreign) {
/* TODO: Patch to invalid if P-TMSI unknown. */
gbproxy_patch_raid(parse_ctx->old_raid_enc, peer, parse_ctx->to_bss,
parse_ctx->llc_msg_name);
have_patched = 1;
}
if (parse_ctx->apn_ie &&
cfg->core_apn &&
!parse_ctx->to_bss &&
gbproxy_imsi_matches(cfg, GBPROX_MATCH_PATCHING, link_info) &&
cfg->core_apn) {
size_t new_len;
gbproxy_patch_apn_ie(msg,
parse_ctx->apn_ie, parse_ctx->apn_ie_len,
peer, &new_len, parse_ctx->llc_msg_name);
*len_change += (int)new_len - (int)parse_ctx->apn_ie_len;
have_patched = 1;
}
if (have_patched) {
llc_len += *len_change;
ghp->crc_length += *len_change;
/* Fix FCS */
fcs = gprs_llc_fcs(llc, ghp->crc_length);
LOGP(DLLC, LOGL_DEBUG, "Updated LLC message, CRC: %06x -> %06x\n",
ghp->fcs, fcs);
llc[llc_len - 3] = fcs & 0xff;
llc[llc_len - 2] = (fcs >> 8) & 0xff;
llc[llc_len - 1] = (fcs >> 16) & 0xff;
}
return have_patched;
}
/* patch BSSGP message to use core_mcc/mnc on the SGSN side */
void gbproxy_patch_bssgp(struct msgb *msg, uint8_t *bssgp, size_t bssgp_len,
struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info, int *len_change,
struct gprs_gb_parse_context *parse_ctx)
{
const char *err_info = NULL;
int err_ctr = -1;
if (parse_ctx->bssgp_raid_enc)
gbproxy_patch_raid(parse_ctx->bssgp_raid_enc, peer,
parse_ctx->to_bss, "BSSGP");
if (parse_ctx->need_decryption &&
(peer->cfg->patch_ptmsi || peer->cfg->core_apn)) {
/* Patching LLC messages has been requested
* explicitly, but the message (including the
* type) is encrypted, so we possibly fail to
* patch the LLC part of the message. */
err_ctr = GBPROX_PEER_CTR_PATCH_CRYPT_ERR;
err_info = "GMM message is encrypted";
goto patch_error;
}
if (!link_info && parse_ctx->tlli_enc && parse_ctx->to_bss) {
/* Happens with unknown (not cached) TLLI coming from
* the SGSN */
/* TODO: What shall be done with the message in this case? */
err_ctr = GBPROX_PEER_CTR_TLLI_UNKNOWN;
err_info = "TLLI sent by the SGSN is unknown";
goto patch_error;
}
if (!link_info)
return;
if (parse_ctx->tlli_enc && peer->cfg->patch_ptmsi) {
uint32_t tlli = gbproxy_map_tlli(parse_ctx->tlli,
link_info, parse_ctx->to_bss);
if (tlli) {
gbproxy_patch_tlli(parse_ctx->tlli_enc, peer, tlli,
parse_ctx->to_bss, "TLLI");
parse_ctx->tlli = tlli;
} else {
/* Internal error */
err_ctr = GBPROX_PEER_CTR_PATCH_ERR;
err_info = "Replacement TLLI is 0";
goto patch_error;
}
}
if (parse_ctx->bssgp_ptmsi_enc && peer->cfg->patch_ptmsi) {
uint32_t ptmsi;
if (parse_ctx->to_bss)
ptmsi = link_info->tlli.ptmsi;
else
ptmsi = link_info->sgsn_tlli.ptmsi;
if (ptmsi != GSM_RESERVED_TMSI)
gbproxy_patch_ptmsi(
parse_ctx->bssgp_ptmsi_enc, peer,
ptmsi, parse_ctx->to_bss, "BSSGP P-TMSI");
}
if (parse_ctx->llc) {
uint8_t *llc = parse_ctx->llc;
size_t llc_len = parse_ctx->llc_len;
int llc_len_change = 0;
gbproxy_patch_llc(msg, llc, llc_len, peer, link_info,
&llc_len_change, parse_ctx);
/* Note that the APN might have been resized here, but no
* pointer int the parse_ctx will refer to an adress after the
* APN. So it's possible to patch first and do the TLLI
* handling afterwards. */
if (llc_len_change) {
llc_len += llc_len_change;
/* Fix LLC IE len */
/* TODO: This is a kludge, but the a pointer to the
* start of the IE is not available here */
if (llc[-2] == BSSGP_IE_LLC_PDU && llc[-1] & 0x80) {
/* most probably a one byte length */
if (llc_len > 127) {
err_info = "Cannot increase size";
err_ctr = GBPROX_PEER_CTR_PATCH_ERR;
goto patch_error;
}
llc[-1] = llc_len | 0x80;
} else {
llc[-2] = (llc_len >> 8) & 0x7f;
llc[-1] = llc_len & 0xff;
}
*len_change += llc_len_change;
}
/* Note that the tp struct might contain invalid pointers here
* if the LLC field has changed its size */
parse_ctx->llc_len = llc_len;
}
return;
patch_error:
OSMO_ASSERT(err_ctr >= 0);
rate_ctr_inc(&peer->ctrg->ctr[err_ctr]);
LOGP(DGPRS, LOGL_ERROR,
"NSEI=%u(%s) failed to patch BSSGP message as requested: %s.\n",
msgb_nsei(msg), parse_ctx->to_bss ? "SGSN" : "BSS",
err_info);
}
void gbproxy_clear_patch_filter(struct gbproxy_match *match)
{
if (match->enable) {
regfree(&match->re_comp);
match->enable = 0;
}
talloc_free(match->re_str);
match->re_str = NULL;
}
int gbproxy_set_patch_filter(struct gbproxy_match *match, const char *filter,
const char **err_msg)
{
static char err_buf[300];
int rc;
gbproxy_clear_patch_filter(match);
if (!filter)
return 0;
rc = regcomp(&match->re_comp, filter,
REG_EXTENDED | REG_NOSUB | REG_ICASE);
if (rc == 0) {
match->enable = 1;
match->re_str = talloc_strdup(tall_bsc_ctx, filter);
return 0;
}
if (err_msg) {
regerror(rc, &match->re_comp,
err_buf, sizeof(err_buf));
*err_msg = err_buf;
}
return -1;
}
int gbproxy_check_imsi(struct gbproxy_match *match,
const uint8_t *imsi, size_t imsi_len)
{
char mi_buf[200];
int rc;
if (!match->enable)
return 1;
rc = gprs_is_mi_imsi(imsi, imsi_len);
if (rc > 0)
rc = gsm48_mi_to_string(mi_buf, sizeof(mi_buf), imsi, imsi_len);
if (rc <= 0) {
LOGP(DGPRS, LOGL_NOTICE, "Invalid IMSI %s\n",
osmo_hexdump(imsi, imsi_len));
return -1;
}
LOGP(DGPRS, LOGL_DEBUG, "Checking IMSI '%s' (%d)\n", mi_buf, rc);
rc = regexec(&match->re_comp, mi_buf, 0, NULL, 0);
if (rc == REG_NOMATCH) {
LOGP(DGPRS, LOGL_INFO,
"IMSI '%s' doesn't match pattern '%s'\n",
mi_buf, match->re_str);
return 0;
}
return 1;
}

View File

@@ -0,0 +1,200 @@
/* Gb proxy peer handling */
/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2010-2013 by On-Waves
* (C) 2013 by Holger Hans Peter Freyther
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <openbsc/gb_proxy.h>
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_data_shared.h>
#include <openbsc/gsm_04_08_gprs.h>
#include <openbsc/debug.h>
#include <osmocom/gprs/protocol/gsm_08_18.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/talloc.h>
#include <string.h>
static const struct rate_ctr_desc peer_ctr_description[] = {
{ "blocked", "BVC Block " },
{ "unblocked", "BVC Unblock " },
{ "dropped", "BVC blocked, dropped packet " },
{ "inv-nsei", "NSEI mismatch " },
{ "tx-err", "NS Transmission error " },
{ "raid-mod.bss", "RAID patched (BSS )" },
{ "raid-mod.sgsn", "RAID patched (SGSN)" },
{ "apn-mod.sgsn", "APN patched " },
{ "tlli-mod.bss", "TLLI patched (BSS )" },
{ "tlli-mod.sgsn", "TLLI patched (SGSN)" },
{ "ptmsi-mod.bss", "P-TMSI patched (BSS )" },
{ "ptmsi-mod.sgsn","P-TMSI patched (SGSN)" },
{ "mod-crypt-err", "Patch error: encrypted " },
{ "mod-err", "Patch error: other " },
{ "attach-reqs", "Attach Request count " },
{ "attach-rejs", "Attach Reject count " },
{ "tlli-unknown", "TLLI from SGSN unknown " },
{ "tlli-cache", "TLLI cache size " },
};
static const struct rate_ctr_group_desc peer_ctrg_desc = {
.group_name_prefix = "gbproxy.peer",
.group_description = "GBProxy Peer Statistics",
.num_ctr = ARRAY_SIZE(peer_ctr_description),
.ctr_desc = peer_ctr_description,
};
/* Find the gbprox_peer by its BVCI */
struct gbproxy_peer *gbproxy_peer_by_bvci(struct gbproxy_config *cfg, uint16_t bvci)
{
struct gbproxy_peer *peer;
llist_for_each_entry(peer, &cfg->bts_peers, list) {
if (peer->bvci == bvci)
return peer;
}
return NULL;
}
/* Find the gbprox_peer by its NSEI */
struct gbproxy_peer *gbproxy_peer_by_nsei(struct gbproxy_config *cfg,
uint16_t nsei)
{
struct gbproxy_peer *peer;
llist_for_each_entry(peer, &cfg->bts_peers, list) {
if (peer->nsei == nsei)
return peer;
}
return NULL;
}
/* look-up a peer by its Routeing Area Identification (RAI) */
struct gbproxy_peer *gbproxy_peer_by_rai(struct gbproxy_config *cfg,
const uint8_t *ra)
{
struct gbproxy_peer *peer;
llist_for_each_entry(peer, &cfg->bts_peers, list) {
if (!memcmp(peer->ra, ra, 6))
return peer;
}
return NULL;
}
/* look-up a peer by its Location Area Identification (LAI) */
struct gbproxy_peer *gbproxy_peer_by_lai(struct gbproxy_config *cfg,
const uint8_t *la)
{
struct gbproxy_peer *peer;
llist_for_each_entry(peer, &cfg->bts_peers, list) {
if (!memcmp(peer->ra, la, 5))
return peer;
}
return NULL;
}
/* look-up a peer by its Location Area Code (LAC) */
struct gbproxy_peer *gbproxy_peer_by_lac(struct gbproxy_config *cfg,
const uint8_t *la)
{
struct gbproxy_peer *peer;
llist_for_each_entry(peer, &cfg->bts_peers, list) {
if (!memcmp(peer->ra + 3, la + 3, 2))
return peer;
}
return NULL;
}
struct gbproxy_peer *gbproxy_peer_by_bssgp_tlv(struct gbproxy_config *cfg,
struct tlv_parsed *tp)
{
if (TLVP_PRESENT(tp, BSSGP_IE_BVCI)) {
uint16_t bvci;
bvci = ntohs(tlvp_val16_unal(tp, BSSGP_IE_BVCI));
if (bvci >= 2)
return gbproxy_peer_by_bvci(cfg, bvci);
}
if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA)) {
uint8_t *rai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA);
/* Only compare LAC part, since MCC/MNC are possibly patched.
* Since the LAC of different BSS must be different when
* MCC/MNC are patched, collisions shouldn't happen. */
return gbproxy_peer_by_lac(cfg, rai);
}
if (TLVP_PRESENT(tp, BSSGP_IE_LOCATION_AREA)) {
uint8_t *lai = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_LOCATION_AREA);
return gbproxy_peer_by_lac(cfg, lai);
}
return NULL;
}
struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci)
{
struct gbproxy_peer *peer;
peer = talloc_zero(tall_bsc_ctx, struct gbproxy_peer);
if (!peer)
return NULL;
peer->bvci = bvci;
peer->ctrg = rate_ctr_group_alloc(peer, &peer_ctrg_desc, bvci);
peer->cfg = cfg;
llist_add(&peer->list, &cfg->bts_peers);
INIT_LLIST_HEAD(&peer->patch_state.logical_links);
return peer;
}
void gbproxy_peer_free(struct gbproxy_peer *peer)
{
llist_del(&peer->list);
gbproxy_delete_link_infos(peer);
rate_ctr_group_free(peer->ctrg);
peer->ctrg = NULL;
talloc_free(peer);
}
int gbproxy_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci)
{
int counter = 0;
struct gbproxy_peer *peer, *tmp;
llist_for_each_entry_safe(peer, tmp, &cfg->bts_peers, list) {
if (peer->nsei != nsei)
continue;
if (bvci && peer->bvci != bvci)
continue;
gbproxy_peer_free(peer);
counter += 1;
}
return counter;
}

View File

@@ -0,0 +1,719 @@
/* Gb-proxy TLLI state handling */
/* (C) 2014 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/gsm/gsm48.h>
#include <openbsc/gb_proxy.h>
#include <openbsc/gprs_utils.h>
#include <openbsc/gprs_gb_parse.h>
#include <openbsc/debug.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/core/talloc.h>
struct gbproxy_link_info *gbproxy_link_info_by_tlli(struct gbproxy_peer *peer,
uint32_t tlli)
{
struct gbproxy_link_info *link_info;
struct gbproxy_patch_state *state = &peer->patch_state;
if (!tlli)
return NULL;
llist_for_each_entry(link_info, &state->logical_links, list)
if (link_info->tlli.current == tlli ||
link_info->tlli.assigned == tlli)
return link_info;
return NULL;
}
struct gbproxy_link_info *gbproxy_link_info_by_ptmsi(
struct gbproxy_peer *peer,
uint32_t ptmsi)
{
struct gbproxy_link_info *link_info;
struct gbproxy_patch_state *state = &peer->patch_state;
if (ptmsi == GSM_RESERVED_TMSI)
return NULL;
llist_for_each_entry(link_info, &state->logical_links, list)
if (link_info->tlli.ptmsi == ptmsi)
return link_info;
return NULL;
}
struct gbproxy_link_info *gbproxy_link_info_by_any_sgsn_tlli(
struct gbproxy_peer *peer,
uint32_t tlli)
{
struct gbproxy_link_info *link_info;
struct gbproxy_patch_state *state = &peer->patch_state;
if (!tlli)
return NULL;
/* Don't care about the NSEI */
llist_for_each_entry(link_info, &state->logical_links, list)
if (link_info->sgsn_tlli.current == tlli ||
link_info->sgsn_tlli.assigned == tlli)
return link_info;
return NULL;
}
struct gbproxy_link_info *gbproxy_link_info_by_sgsn_tlli(
struct gbproxy_peer *peer,
uint32_t tlli, uint32_t sgsn_nsei)
{
struct gbproxy_link_info *link_info;
struct gbproxy_patch_state *state = &peer->patch_state;
if (!tlli)
return NULL;
llist_for_each_entry(link_info, &state->logical_links, list)
if ((link_info->sgsn_tlli.current == tlli ||
link_info->sgsn_tlli.assigned == tlli) &&
link_info->sgsn_nsei == sgsn_nsei)
return link_info;
return NULL;
}
struct gbproxy_link_info *gbproxy_link_info_by_imsi(
struct gbproxy_peer *peer,
const uint8_t *imsi,
size_t imsi_len)
{
struct gbproxy_link_info *link_info;
struct gbproxy_patch_state *state = &peer->patch_state;
if (!gprs_is_mi_imsi(imsi, imsi_len))
return NULL;
llist_for_each_entry(link_info, &state->logical_links, list) {
if (link_info->imsi_len != imsi_len)
continue;
if (memcmp(link_info->imsi, imsi, imsi_len) != 0)
continue;
return link_info;
}
return NULL;
}
void gbproxy_link_info_discard_messages(struct gbproxy_link_info *link_info)
{
struct msgb *msg, *nxt;
llist_for_each_entry_safe(msg, nxt, &link_info->stored_msgs, list) {
llist_del(&msg->list);
msgb_free(msg);
}
}
void gbproxy_delete_link_info(struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info)
{
struct gbproxy_patch_state *state = &peer->patch_state;
gbproxy_link_info_discard_messages(link_info);
llist_del(&link_info->list);
talloc_free(link_info);
state->logical_link_count -= 1;
peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
state->logical_link_count;
}
void gbproxy_delete_link_infos(struct gbproxy_peer *peer)
{
struct gbproxy_link_info *link_info, *nxt;
struct gbproxy_patch_state *state = &peer->patch_state;
llist_for_each_entry_safe(link_info, nxt, &state->logical_links, list)
gbproxy_delete_link_info(peer, link_info);
OSMO_ASSERT(state->logical_link_count == 0);
OSMO_ASSERT(llist_empty(&state->logical_links));
}
void gbproxy_attach_link_info(struct gbproxy_peer *peer, time_t now,
struct gbproxy_link_info *link_info)
{
struct gbproxy_patch_state *state = &peer->patch_state;
link_info->timestamp = now;
llist_add(&link_info->list, &state->logical_links);
state->logical_link_count += 1;
peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
state->logical_link_count;
}
int gbproxy_remove_stale_link_infos(struct gbproxy_peer *peer, time_t now)
{
struct gbproxy_patch_state *state = &peer->patch_state;
int exceeded_max_len = 0;
int deleted_count = 0;
int check_for_age;
if (peer->cfg->tlli_max_len > 0)
exceeded_max_len =
state->logical_link_count - peer->cfg->tlli_max_len;
check_for_age = peer->cfg->tlli_max_age > 0;
for (; exceeded_max_len > 0; exceeded_max_len--) {
struct gbproxy_link_info *link_info;
OSMO_ASSERT(!llist_empty(&state->logical_links));
link_info = llist_entry(state->logical_links.prev,
struct gbproxy_link_info,
list);
LOGP(DGPRS, LOGL_INFO,
"Removing TLLI %08x from list "
"(stale, length %d, max_len exceeded)\n",
link_info->tlli.current, state->logical_link_count);
gbproxy_delete_link_info(peer, link_info);
deleted_count += 1;
}
while (check_for_age && !llist_empty(&state->logical_links)) {
time_t age;
struct gbproxy_link_info *link_info;
link_info = llist_entry(state->logical_links.prev,
struct gbproxy_link_info,
list);
age = now - link_info->timestamp;
/* age < 0 only happens after system time jumps, discard entry */
if (age <= peer->cfg->tlli_max_age && age >= 0) {
check_for_age = 0;
continue;
}
LOGP(DGPRS, LOGL_INFO,
"Removing TLLI %08x from list "
"(stale, age %d, max_age exceeded)\n",
link_info->tlli.current, (int)age);
gbproxy_delete_link_info(peer, link_info);
deleted_count += 1;
}
return deleted_count;
}
struct gbproxy_link_info *gbproxy_link_info_alloc( struct gbproxy_peer *peer)
{
struct gbproxy_link_info *link_info;
link_info = talloc_zero(peer, struct gbproxy_link_info);
link_info->tlli.ptmsi = GSM_RESERVED_TMSI;
link_info->sgsn_tlli.ptmsi = GSM_RESERVED_TMSI;
link_info->vu_gen_tx_bss = GBPROXY_INIT_VU_GEN_TX;
INIT_LLIST_HEAD(&link_info->stored_msgs);
return link_info;
}
void gbproxy_detach_link_info(
struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info)
{
struct gbproxy_patch_state *state = &peer->patch_state;
llist_del(&link_info->list);
OSMO_ASSERT(state->logical_link_count > 0);
state->logical_link_count -= 1;
peer->ctrg->ctr[GBPROX_PEER_CTR_TLLI_CACHE_SIZE].current =
state->logical_link_count;
}
void gbproxy_update_link_info(struct gbproxy_link_info *link_info,
const uint8_t *imsi, size_t imsi_len)
{
if (!gprs_is_mi_imsi(imsi, imsi_len))
return;
link_info->imsi_len = imsi_len;
link_info->imsi =
talloc_realloc_size(link_info, link_info->imsi, imsi_len);
OSMO_ASSERT(link_info->imsi != NULL);
memcpy(link_info->imsi, imsi, imsi_len);
}
void gbproxy_reassign_tlli(struct gbproxy_tlli_state *tlli_state,
struct gbproxy_peer *peer, uint32_t new_tlli)
{
if (new_tlli == tlli_state->current)
return;
LOGP(DGPRS, LOGL_INFO,
"The TLLI has been reassigned from %08x to %08x\n",
tlli_state->current, new_tlli);
/* Remember assigned TLLI */
tlli_state->assigned = new_tlli;
tlli_state->bss_validated = 0;
tlli_state->net_validated = 0;
}
uint32_t gbproxy_map_tlli(uint32_t other_tlli,
struct gbproxy_link_info *link_info, int to_bss)
{
uint32_t tlli = 0;
struct gbproxy_tlli_state *src, *dst;
if (to_bss) {
src = &link_info->sgsn_tlli;
dst = &link_info->tlli;
} else {
src = &link_info->tlli;
dst = &link_info->sgsn_tlli;
}
if (src->current == other_tlli)
tlli = dst->current;
else if (src->assigned == other_tlli)
tlli = dst->assigned;
return tlli;
}
static void gbproxy_validate_tlli(struct gbproxy_tlli_state *tlli_state,
uint32_t tlli, int to_bss)
{
LOGP(DGPRS, LOGL_DEBUG,
"%s({current = %08x, assigned = %08x, net_vld = %d, bss_vld = %d}, %08x)\n",
__func__, tlli_state->current, tlli_state->assigned,
tlli_state->net_validated, tlli_state->bss_validated, tlli);
if (!tlli_state->assigned || tlli_state->assigned != tlli)
return;
/* TODO: Is this ok? Check spec */
if (gprs_tlli_type(tlli) != TLLI_LOCAL)
return;
/* See GSM 04.08, 4.7.1.5 */
if (to_bss)
tlli_state->net_validated = 1;
else
tlli_state->bss_validated = 1;
if (!tlli_state->bss_validated || !tlli_state->net_validated)
return;
LOGP(DGPRS, LOGL_INFO,
"The TLLI %08x has been validated (was %08x)\n",
tlli_state->assigned, tlli_state->current);
tlli_state->current = tlli;
tlli_state->assigned = 0;
}
static void gbproxy_touch_link_info(struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info,
time_t now)
{
gbproxy_detach_link_info(peer, link_info);
gbproxy_attach_link_info(peer, now, link_info);
}
static void gbproxy_unregister_link_info(struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info)
{
if (!link_info)
return;
if (link_info->tlli.ptmsi == GSM_RESERVED_TMSI && !link_info->imsi_len) {
LOGP(DGPRS, LOGL_INFO,
"Removing TLLI %08x from list (P-TMSI or IMSI are not set)\n",
link_info->tlli.current);
gbproxy_delete_link_info(peer, link_info);
return;
}
link_info->tlli.current = 0;
link_info->tlli.assigned = 0;
link_info->sgsn_tlli.current = 0;
link_info->sgsn_tlli.assigned = 0;
link_info->is_deregistered = 1;
gbproxy_reset_link(link_info);
return;
}
int gbproxy_imsi_matches(struct gbproxy_config *cfg,
enum gbproxy_match_id match_id,
struct gbproxy_link_info *link_info)
{
struct gbproxy_match *match;
OSMO_ASSERT(match_id >= 0 && match_id < ARRAY_SIZE(cfg->matches));
match = &cfg->matches[match_id];
if (!match->enable)
return 1;
return link_info != NULL && link_info->is_matching[match_id];
}
void gbproxy_assign_imsi(struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info,
struct gprs_gb_parse_context *parse_ctx)
{
int imsi_matches;
struct gbproxy_link_info *other_link_info;
enum gbproxy_match_id match_id;
/* Make sure that there is a second entry with the same IMSI */
other_link_info = gbproxy_link_info_by_imsi(
peer, parse_ctx->imsi, parse_ctx->imsi_len);
if (other_link_info && other_link_info != link_info) {
char mi_buf[200];
mi_buf[0] = '\0';
gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
parse_ctx->imsi, parse_ctx->imsi_len);
LOGP(DGPRS, LOGL_INFO,
"Removing TLLI %08x from list (IMSI %s re-used)\n",
other_link_info->tlli.current, mi_buf);
gbproxy_delete_link_info(peer, other_link_info);
}
/* Update the IMSI field */
gbproxy_update_link_info(link_info,
parse_ctx->imsi, parse_ctx->imsi_len);
/* Check, whether the IMSI matches */
OSMO_ASSERT(ARRAY_SIZE(link_info->is_matching) ==
ARRAY_SIZE(peer->cfg->matches));
for (match_id = 0; match_id < ARRAY_SIZE(link_info->is_matching);
++match_id) {
imsi_matches = gbproxy_check_imsi(
&peer->cfg->matches[match_id],
parse_ctx->imsi, parse_ctx->imsi_len);
if (imsi_matches >= 0)
link_info->is_matching[match_id] = imsi_matches;
}
}
static int gbproxy_tlli_match(const struct gbproxy_tlli_state *a,
const struct gbproxy_tlli_state *b)
{
if (a->current && a->current == b->current)
return 1;
if (a->assigned && a->assigned == b->assigned)
return 1;
if (a->ptmsi != GSM_RESERVED_TMSI && a->ptmsi == b->ptmsi)
return 1;
return 0;
}
static void gbproxy_remove_matching_link_infos(
struct gbproxy_peer *peer, struct gbproxy_link_info *link_info)
{
struct gbproxy_link_info *info, *nxt;
struct gbproxy_patch_state *state = &peer->patch_state;
/* Make sure that there is no second entry with the same P-TMSI or TLLI */
llist_for_each_entry_safe(info, nxt, &state->logical_links, list) {
if (info == link_info)
continue;
if (!gbproxy_tlli_match(&link_info->tlli, &info->tlli) &&
(link_info->sgsn_nsei != info->sgsn_nsei ||
!gbproxy_tlli_match(&link_info->sgsn_tlli, &info->sgsn_tlli)))
continue;
LOGP(DGPRS, LOGL_INFO,
"Removing TLLI %08x from list (P-TMSI/TLLI re-used)\n",
info->tlli.current);
gbproxy_delete_link_info(peer, info);
}
}
static struct gbproxy_link_info *gbproxy_get_link_info_ul(
struct gbproxy_peer *peer,
int *tlli_is_valid,
struct gprs_gb_parse_context *parse_ctx)
{
struct gbproxy_link_info *link_info = NULL;
if (parse_ctx->tlli_enc) {
link_info = gbproxy_link_info_by_tlli(peer, parse_ctx->tlli);
if (link_info) {
*tlli_is_valid = 1;
return link_info;
}
}
*tlli_is_valid = 0;
if (!link_info && parse_ctx->imsi) {
link_info = gbproxy_link_info_by_imsi(
peer, parse_ctx->imsi, parse_ctx->imsi_len);
}
if (!link_info && parse_ctx->ptmsi_enc && !parse_ctx->old_raid_is_foreign) {
uint32_t bss_ptmsi;
gprs_parse_tmsi(parse_ctx->ptmsi_enc, &bss_ptmsi);
link_info = gbproxy_link_info_by_ptmsi(peer, bss_ptmsi);
}
if (!link_info)
return NULL;
link_info->is_deregistered = 0;
return link_info;
}
struct gbproxy_link_info *gbproxy_update_link_state_ul(
struct gbproxy_peer *peer,
time_t now,
struct gprs_gb_parse_context *parse_ctx)
{
struct gbproxy_link_info *link_info;
int tlli_is_valid;
link_info = gbproxy_get_link_info_ul(peer, &tlli_is_valid, parse_ctx);
if (parse_ctx->tlli_enc && parse_ctx->llc) {
uint32_t sgsn_tlli;
if (!link_info) {
LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list\n",
parse_ctx->tlli);
link_info = gbproxy_link_info_alloc(peer);
gbproxy_attach_link_info(peer, now, link_info);
/* Setup TLLIs */
sgsn_tlli = gbproxy_make_sgsn_tlli(peer, link_info,
parse_ctx->tlli);
link_info->sgsn_tlli.current = sgsn_tlli;
link_info->tlli.current = parse_ctx->tlli;
} else if (!tlli_is_valid) {
/* New TLLI (info found by IMSI or P-TMSI) */
link_info->tlli.current = parse_ctx->tlli;
link_info->tlli.assigned = 0;
link_info->sgsn_tlli.current =
gbproxy_make_sgsn_tlli(peer, link_info,
parse_ctx->tlli);
link_info->sgsn_tlli.assigned = 0;
gbproxy_touch_link_info(peer, link_info, now);
} else {
sgsn_tlli = gbproxy_map_tlli(parse_ctx->tlli, link_info, 0);
if (!sgsn_tlli)
sgsn_tlli = gbproxy_make_sgsn_tlli(peer, link_info,
parse_ctx->tlli);
gbproxy_validate_tlli(&link_info->tlli,
parse_ctx->tlli, 0);
gbproxy_validate_tlli(&link_info->sgsn_tlli,
sgsn_tlli, 0);
gbproxy_touch_link_info(peer, link_info, now);
}
} else if (link_info) {
gbproxy_touch_link_info(peer, link_info, now);
}
if (parse_ctx->imsi && link_info && link_info->imsi_len == 0)
gbproxy_assign_imsi(peer, link_info, parse_ctx);
return link_info;
}
static struct gbproxy_link_info *gbproxy_get_link_info_dl(
struct gbproxy_peer *peer,
struct gprs_gb_parse_context *parse_ctx)
{
struct gbproxy_link_info *link_info = NULL;
/* Which key to use depends on its availability only, if that fails, do
* not retry it with another key (e.g. IMSI). */
if (parse_ctx->tlli_enc)
link_info = gbproxy_link_info_by_sgsn_tlli(peer, parse_ctx->tlli,
parse_ctx->peer_nsei);
/* TODO: Get link_info by (SGSN) P-TMSI if that is available (see
* GSM 08.18, 7.2) instead of using the IMSI as key. */
else if (parse_ctx->imsi)
link_info = gbproxy_link_info_by_imsi(
peer, parse_ctx->imsi, parse_ctx->imsi_len);
if (link_info)
link_info->is_deregistered = 0;
return link_info;
}
struct gbproxy_link_info *gbproxy_update_link_state_dl(
struct gbproxy_peer *peer,
time_t now,
struct gprs_gb_parse_context *parse_ctx)
{
struct gbproxy_link_info *link_info = NULL;
link_info = gbproxy_get_link_info_dl(peer, parse_ctx);
if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc && link_info) {
/* A new P-TMSI has been signalled in the message,
* register new TLLI */
uint32_t new_sgsn_ptmsi;
uint32_t new_bss_ptmsi = GSM_RESERVED_TMSI;
gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_sgsn_ptmsi);
if (link_info->sgsn_tlli.ptmsi == new_sgsn_ptmsi)
new_bss_ptmsi = link_info->tlli.ptmsi;
if (new_bss_ptmsi == GSM_RESERVED_TMSI)
new_bss_ptmsi = gbproxy_make_bss_ptmsi(peer, new_sgsn_ptmsi);
LOGP(DGPRS, LOGL_INFO,
"Got new PTMSI %08x from SGSN, using %08x for BSS\n",
new_sgsn_ptmsi, new_bss_ptmsi);
/* Setup PTMSIs */
link_info->sgsn_tlli.ptmsi = new_sgsn_ptmsi;
link_info->tlli.ptmsi = new_bss_ptmsi;
} else if (parse_ctx->tlli_enc && parse_ctx->new_ptmsi_enc && !link_info &&
!peer->cfg->patch_ptmsi) {
/* A new P-TMSI has been signalled in the message with an unknown
* TLLI, create a new link_info */
/* TODO: Add a test case for this branch */
uint32_t new_ptmsi;
gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_ptmsi);
LOGP(DGPRS, LOGL_INFO,
"Adding TLLI %08x to list (SGSN, new P-TMSI is %08x)\n",
parse_ctx->tlli, new_ptmsi);
link_info = gbproxy_link_info_alloc(peer);
link_info->sgsn_tlli.current = parse_ctx->tlli;
link_info->tlli.current = parse_ctx->tlli;
link_info->sgsn_tlli.ptmsi = new_ptmsi;
link_info->tlli.ptmsi = new_ptmsi;
gbproxy_attach_link_info(peer, now, link_info);
} else if (parse_ctx->tlli_enc && parse_ctx->llc && !link_info &&
!peer->cfg->patch_ptmsi) {
/* Unknown SGSN TLLI, create a new link_info */
uint32_t new_ptmsi;
link_info = gbproxy_link_info_alloc(peer);
LOGP(DGPRS, LOGL_INFO, "Adding TLLI %08x to list (SGSN)\n",
parse_ctx->tlli);
gbproxy_attach_link_info(peer, now, link_info);
/* Setup TLLIs */
link_info->sgsn_tlli.current = parse_ctx->tlli;
link_info->tlli.current = parse_ctx->tlli;
if (!parse_ctx->new_ptmsi_enc)
return link_info;
/* A new P-TMSI has been signalled in the message */
gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_ptmsi);
LOGP(DGPRS, LOGL_INFO,
"Assigning new P-TMSI %08x\n", new_ptmsi);
/* Setup P-TMSIs */
link_info->sgsn_tlli.ptmsi = new_ptmsi;
link_info->tlli.ptmsi = new_ptmsi;
} else if (parse_ctx->tlli_enc && parse_ctx->llc && link_info) {
uint32_t bss_tlli = gbproxy_map_tlli(parse_ctx->tlli,
link_info, 1);
gbproxy_validate_tlli(&link_info->sgsn_tlli, parse_ctx->tlli, 1);
gbproxy_validate_tlli(&link_info->tlli, bss_tlli, 1);
gbproxy_touch_link_info(peer, link_info, now);
} else if (link_info) {
gbproxy_touch_link_info(peer, link_info, now);
}
if (parse_ctx->imsi && link_info && link_info->imsi_len == 0)
gbproxy_assign_imsi(peer, link_info, parse_ctx);
return link_info;
}
void gbproxy_update_link_state_after(
struct gbproxy_peer *peer,
struct gbproxy_link_info *link_info,
time_t now,
struct gprs_gb_parse_context *parse_ctx)
{
if (parse_ctx->invalidate_tlli && link_info) {
int keep_info =
peer->cfg->keep_link_infos == GBPROX_KEEP_ALWAYS ||
(peer->cfg->keep_link_infos == GBPROX_KEEP_REATTACH &&
parse_ctx->await_reattach) ||
(peer->cfg->keep_link_infos == GBPROX_KEEP_IDENTIFIED &&
link_info->imsi_len > 0);
if (keep_info) {
LOGP(DGPRS, LOGL_INFO, "Unregistering TLLI %08x\n",
link_info->tlli.current);
gbproxy_unregister_link_info(peer, link_info);
} else {
LOGP(DGPRS, LOGL_INFO, "Removing TLLI %08x from list\n",
link_info->tlli.current);
gbproxy_delete_link_info(peer, link_info);
}
} else if (parse_ctx->to_bss && parse_ctx->tlli_enc &&
parse_ctx->new_ptmsi_enc && link_info) {
/* A new PTMSI has been signaled in the message,
* register new TLLI */
uint32_t new_sgsn_ptmsi = link_info->sgsn_tlli.ptmsi;
uint32_t new_bss_ptmsi = link_info->tlli.ptmsi;
uint32_t new_sgsn_tlli;
uint32_t new_bss_tlli = 0;
new_sgsn_tlli = gprs_tmsi2tlli(new_sgsn_ptmsi, TLLI_LOCAL);
if (new_bss_ptmsi != GSM_RESERVED_TMSI)
new_bss_tlli = gprs_tmsi2tlli(new_bss_ptmsi, TLLI_LOCAL);
LOGP(DGPRS, LOGL_INFO,
"Assigning new TLLI %08x to SGSN, %08x to BSS\n",
new_sgsn_tlli, new_bss_tlli);
gbproxy_reassign_tlli(&link_info->sgsn_tlli,
peer, new_sgsn_tlli);
gbproxy_reassign_tlli(&link_info->tlli,
peer, new_bss_tlli);
gbproxy_remove_matching_link_infos(peer, link_info);
}
gbproxy_remove_stale_link_infos(peer, now);
}

View File

@@ -21,17 +21,23 @@
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <time.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/rate_ctr.h>
#include <openbsc/gsm_04_08.h>
#include <osmocom/gprs/gprs_ns.h>
#include <openbsc/debug.h>
#include <openbsc/gb_proxy.h>
#include <openbsc/gprs_utils.h>
#include <openbsc/vty.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/vty.h>
#include <osmocom/vty/misc.h>
static struct gbproxy_config *g_cfg = NULL;
@@ -44,13 +50,87 @@ static struct cmd_node gbproxy_node = {
1,
};
static const struct value_string keep_modes[] = {
{GBPROX_KEEP_NEVER, "never"},
{GBPROX_KEEP_REATTACH, "re-attach"},
{GBPROX_KEEP_IDENTIFIED, "identified"},
{GBPROX_KEEP_ALWAYS, "always"},
{0, NULL}
};
static const struct value_string match_ids[] = {
{GBPROX_MATCH_PATCHING, "patching"},
{GBPROX_MATCH_ROUTING, "routing"},
{0, NULL}
};
static void gbprox_vty_print_peer(struct vty *vty, struct gbproxy_peer *peer)
{
struct gprs_ra_id raid;
gsm48_parse_ra(&raid, peer->ra);
vty_out(vty, "NSEI %5u, PTP-BVCI %5u, "
"RAI %u-%u-%u-%u",
peer->nsei, peer->bvci,
raid.mcc, raid.mnc, raid.lac, raid.rac);
if (peer->blocked)
vty_out(vty, " [BVC-BLOCKED]");
vty_out(vty, "%s", VTY_NEWLINE);
}
static int config_write_gbproxy(struct vty *vty)
{
enum gbproxy_match_id match_id;
vty_out(vty, "gbproxy%s", VTY_NEWLINE);
vty_out(vty, " sgsn nsei %u%s", g_cfg->nsip_sgsn_nsei,
VTY_NEWLINE);
if (g_cfg->core_mcc > 0)
vty_out(vty, " core-mobile-country-code %d%s",
g_cfg->core_mcc, VTY_NEWLINE);
if (g_cfg->core_mnc > 0)
vty_out(vty, " core-mobile-network-code %d%s",
g_cfg->core_mnc, VTY_NEWLINE);
for (match_id = 0; match_id < ARRAY_SIZE(g_cfg->matches); ++match_id) {
struct gbproxy_match *match = &g_cfg->matches[match_id];
if (match->re_str)
vty_out(vty, " match-imsi %s %s%s",
get_value_string(match_ids, match_id),
match->re_str, VTY_NEWLINE);
}
if (g_cfg->core_apn != NULL) {
if (g_cfg->core_apn_size > 0) {
char str[500] = {0};
vty_out(vty, " core-access-point-name %s%s",
gprs_apn_to_str(str, g_cfg->core_apn,
g_cfg->core_apn_size),
VTY_NEWLINE);
} else {
vty_out(vty, " core-access-point-name none%s",
VTY_NEWLINE);
}
}
if (g_cfg->route_to_sgsn2)
vty_out(vty, " secondary-sgsn nsei %u%s", g_cfg->nsip_sgsn2_nsei,
VTY_NEWLINE);
if (g_cfg->tlli_max_age > 0)
vty_out(vty, " link-list max-age %d%s",
g_cfg->tlli_max_age, VTY_NEWLINE);
if (g_cfg->tlli_max_len > 0)
vty_out(vty, " link-list max-length %d%s",
g_cfg->tlli_max_len, VTY_NEWLINE);
vty_out(vty, " link-list keep-mode %s%s",
get_value_string(keep_modes, g_cfg->keep_link_infos),
VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -70,22 +150,635 @@ DEFUN(cfg_nsip_sgsn_nsei,
"NSEI to be used in the connection with the SGSN\n"
"The NSEI\n")
{
unsigned int port = atoi(argv[0]);
unsigned int nsei = atoi(argv[0]);
if (g_cfg->route_to_sgsn2 && g_cfg->nsip_sgsn2_nsei == nsei) {
vty_out(vty, "SGSN NSEI %d conflicts with secondary SGSN NSEI%s",
nsei, VTY_NEWLINE);
return CMD_WARNING;
}
g_cfg->nsip_sgsn_nsei = nsei;
return CMD_SUCCESS;
}
#define GBPROXY_CORE_MNC_STR "Use this network code for the core network\n"
DEFUN(cfg_gbproxy_core_mnc,
cfg_gbproxy_core_mnc_cmd,
"core-mobile-network-code <1-999>",
GBPROXY_CORE_MNC_STR "NCC value\n")
{
g_cfg->core_mnc = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_no_core_mnc,
cfg_gbproxy_no_core_mnc_cmd,
"no core-mobile-network-code",
NO_STR GBPROXY_CORE_MNC_STR)
{
g_cfg->core_mnc = 0;
return CMD_SUCCESS;
}
#define GBPROXY_CORE_MCC_STR "Use this country code for the core network\n"
DEFUN(cfg_gbproxy_core_mcc,
cfg_gbproxy_core_mcc_cmd,
"core-mobile-country-code <1-999>",
GBPROXY_CORE_MCC_STR "MCC value\n")
{
g_cfg->core_mcc = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_no_core_mcc,
cfg_gbproxy_no_core_mcc_cmd,
"no core-mobile-country-code",
NO_STR GBPROXY_CORE_MCC_STR)
{
g_cfg->core_mcc = 0;
return CMD_SUCCESS;
}
#define GBPROXY_MATCH_IMSI_STR "Restrict actions to certain IMSIs\n"
DEFUN(cfg_gbproxy_match_imsi,
cfg_gbproxy_match_imsi_cmd,
"match-imsi (patching|routing) .REGEXP",
GBPROXY_MATCH_IMSI_STR
"Patch MS related information elements on match only\n"
"Route to the secondary SGSN on match only\n"
"Regular expression for the IMSI match\n")
{
const char *filter = argv[1];
const char *err_msg = NULL;
struct gbproxy_match *match;
enum gbproxy_match_id match_id = get_string_value(match_ids, argv[0]);
OSMO_ASSERT(match_id >= GBPROX_MATCH_PATCHING &&
match_id < GBPROX_MATCH_LAST);
match = &g_cfg->matches[match_id];
if (gbproxy_set_patch_filter(match, filter, &err_msg) != 0) {
vty_out(vty, "Match expression invalid: %s%s",
err_msg, VTY_NEWLINE);
return CMD_WARNING;
}
g_cfg->acquire_imsi = 1;
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_no_match_imsi,
cfg_gbproxy_no_match_imsi_cmd,
"no match-imsi",
NO_STR GBPROXY_MATCH_IMSI_STR)
{
enum gbproxy_match_id match_id;
for (match_id = 0; match_id < ARRAY_SIZE(g_cfg->matches); ++match_id)
gbproxy_clear_patch_filter(&g_cfg->matches[match_id]);
g_cfg->acquire_imsi = 0;
return CMD_SUCCESS;
}
#define GBPROXY_CORE_APN_STR "Use this access point name (APN) for the backbone\n"
#define GBPROXY_CORE_APN_ARG_STR "Replace APN by this string\n" "Remove APN\n"
static int set_core_apn(struct vty *vty, const char *apn)
{
int apn_len;
if (!apn) {
talloc_free(g_cfg->core_apn);
g_cfg->core_apn = NULL;
g_cfg->core_apn_size = 0;
return CMD_SUCCESS;
}
apn_len = strlen(apn);
if (apn_len >= 100) {
vty_out(vty, "APN string too long (max 99 chars)%s",
VTY_NEWLINE);
return CMD_WARNING;
}
if (apn_len == 0) {
talloc_free(g_cfg->core_apn);
/* TODO: replace NULL */
g_cfg->core_apn = talloc_zero_size(NULL, 2);
g_cfg->core_apn_size = 0;
} else {
/* TODO: replace NULL */
g_cfg->core_apn =
talloc_realloc_size(NULL, g_cfg->core_apn, apn_len + 1);
g_cfg->core_apn_size =
gprs_str_to_apn(g_cfg->core_apn, apn_len + 1, apn);
}
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_core_apn,
cfg_gbproxy_core_apn_cmd,
"core-access-point-name (APN|none)",
GBPROXY_CORE_APN_STR GBPROXY_CORE_APN_ARG_STR)
{
if (strcmp(argv[0], "none") == 0)
return set_core_apn(vty, "");
else
return set_core_apn(vty, argv[0]);
}
DEFUN(cfg_gbproxy_no_core_apn,
cfg_gbproxy_no_core_apn_cmd,
"no core-access-point-name",
NO_STR GBPROXY_CORE_APN_STR)
{
return set_core_apn(vty, NULL);
}
/* TODO: Remove the patch-ptmsi command, since P-TMSI patching is enabled
* automatically when needed. This command is only left for manual testing
* (e.g. doing P-TMSI patching without using a secondary SGSN)
*/
#define GBPROXY_PATCH_PTMSI_STR "Patch P-TMSI/TLLI\n"
DEFUN(cfg_gbproxy_patch_ptmsi,
cfg_gbproxy_patch_ptmsi_cmd,
"patch-ptmsi",
GBPROXY_PATCH_PTMSI_STR)
{
g_cfg->patch_ptmsi = 1;
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_no_patch_ptmsi,
cfg_gbproxy_no_patch_ptmsi_cmd,
"no patch-ptmsi",
NO_STR GBPROXY_PATCH_PTMSI_STR)
{
g_cfg->patch_ptmsi = 0;
return CMD_SUCCESS;
}
/* TODO: Remove the acquire-imsi command, since that feature is enabled
* automatically when IMSI matching is enabled. This command is only left for
* manual testing (e.g. doing IMSI acquisition without IMSI based patching)
*/
#define GBPROXY_ACQUIRE_IMSI_STR "Acquire the IMSI before establishing a LLC connection (Experimental)\n"
DEFUN(cfg_gbproxy_acquire_imsi,
cfg_gbproxy_acquire_imsi_cmd,
"acquire-imsi",
GBPROXY_ACQUIRE_IMSI_STR)
{
g_cfg->acquire_imsi = 1;
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_no_acquire_imsi,
cfg_gbproxy_no_acquire_imsi_cmd,
"no acquire-imsi",
NO_STR GBPROXY_ACQUIRE_IMSI_STR)
{
g_cfg->acquire_imsi = 0;
return CMD_SUCCESS;
}
#define GBPROXY_SECOND_SGSN_STR "Route matching LLC connections to a second SGSN (Experimental)\n"
DEFUN(cfg_gbproxy_secondary_sgsn,
cfg_gbproxy_secondary_sgsn_cmd,
"secondary-sgsn nsei <0-65534>",
GBPROXY_SECOND_SGSN_STR
"NSEI to be used in the connection with the SGSN\n"
"The NSEI\n")
{
unsigned int nsei = atoi(argv[0]);
if (g_cfg->nsip_sgsn_nsei == nsei) {
vty_out(vty, "Secondary SGSN NSEI %d conflicts with primary SGSN NSEI%s",
nsei, VTY_NEWLINE);
return CMD_WARNING;
}
g_cfg->route_to_sgsn2 = 1;
g_cfg->nsip_sgsn2_nsei = nsei;
g_cfg->patch_ptmsi = 1;
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_no_secondary_sgsn,
cfg_gbproxy_no_secondary_sgsn_cmd,
"no secondary-sgsn",
NO_STR GBPROXY_SECOND_SGSN_STR)
{
g_cfg->route_to_sgsn2 = 0;
g_cfg->nsip_sgsn2_nsei = 0xFFFF;
g_cfg->patch_ptmsi = 0;
return CMD_SUCCESS;
}
#define GBPROXY_LINK_LIST_STR "Set TLLI list parameters\n"
#define GBPROXY_MAX_AGE_STR "Limit maximum age\n"
DEFUN(cfg_gbproxy_link_list_max_age,
cfg_gbproxy_link_list_max_age_cmd,
"link-list max-age <1-999999>",
GBPROXY_LINK_LIST_STR GBPROXY_MAX_AGE_STR
"Maximum age in seconds\n")
{
g_cfg->tlli_max_age = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_link_list_no_max_age,
cfg_gbproxy_link_list_no_max_age_cmd,
"no link-list max-age",
NO_STR GBPROXY_LINK_LIST_STR GBPROXY_MAX_AGE_STR)
{
g_cfg->tlli_max_age = 0;
return CMD_SUCCESS;
}
#define GBPROXY_MAX_LEN_STR "Limit list length\n"
DEFUN(cfg_gbproxy_link_list_max_len,
cfg_gbproxy_link_list_max_len_cmd,
"link-list max-length <1-99999>",
GBPROXY_LINK_LIST_STR GBPROXY_MAX_LEN_STR
"Maximum number of logical links in the list\n")
{
g_cfg->tlli_max_len = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_link_list_no_max_len,
cfg_gbproxy_link_list_no_max_len_cmd,
"no link-list max-length",
NO_STR GBPROXY_LINK_LIST_STR GBPROXY_MAX_LEN_STR)
{
g_cfg->tlli_max_len = 0;
return CMD_SUCCESS;
}
DEFUN(cfg_gbproxy_link_list_keep_mode,
cfg_gbproxy_link_list_keep_mode_cmd,
"link-list keep-mode (never|re-attach|identified|always)",
GBPROXY_LINK_LIST_STR "How to keep entries for detached logical links\n"
"Discard entry immediately after detachment\n"
"Keep entry if a re-attachment has be requested\n"
"Keep entry if it associated with an IMSI\n"
"Don't discard entries after detachment\n")
{
int val = get_string_value(keep_modes, argv[0]);
OSMO_ASSERT(val >= GBPROX_KEEP_NEVER && val <= GBPROX_KEEP_ALWAYS);
g_cfg->keep_link_infos = val;
return CMD_SUCCESS;
}
DEFUN(show_gbproxy, show_gbproxy_cmd, "show gbproxy [stats]",
SHOW_STR "Display information about the Gb proxy\n" "Show statistics\n")
{
struct gbproxy_peer *peer;
int show_stats = argc >= 1;
if (show_stats)
vty_out_rate_ctr_group(vty, "", g_cfg->ctrg);
llist_for_each_entry(peer, &g_cfg->bts_peers, list) {
gbprox_vty_print_peer(vty, peer);
if (show_stats)
vty_out_rate_ctr_group(vty, " ", peer->ctrg);
}
return CMD_SUCCESS;
}
DEFUN(show_gbproxy_links, show_gbproxy_links_cmd, "show gbproxy links",
SHOW_STR "Display information about the Gb proxy\n" "Show logical links\n")
{
struct gbproxy_peer *peer;
char mi_buf[200];
time_t now;
struct timespec ts = {0,};
clock_gettime(CLOCK_MONOTONIC, &ts);
now = ts.tv_sec;
llist_for_each_entry(peer, &g_cfg->bts_peers, list) {
struct gbproxy_link_info *link_info;
struct gbproxy_patch_state *state = &peer->patch_state;
gbprox_vty_print_peer(vty, peer);
llist_for_each_entry(link_info, &state->logical_links, list) {
time_t age = now - link_info->timestamp;
int stored_msgs = 0;
struct llist_head *iter;
llist_for_each(iter, &link_info->stored_msgs)
stored_msgs++;
if (link_info->imsi > 0) {
snprintf(mi_buf, sizeof(mi_buf), "(invalid)");
gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
link_info->imsi,
link_info->imsi_len);
} else {
snprintf(mi_buf, sizeof(mi_buf), "(none)");
}
vty_out(vty, " TLLI %08x, IMSI %s, AGE %d",
link_info->tlli.current, mi_buf, (int)age);
if (stored_msgs)
vty_out(vty, ", STORED %d", stored_msgs);
if (g_cfg->route_to_sgsn2)
vty_out(vty, ", SGSN NSEI %d",
link_info->sgsn_nsei);
if (link_info->is_deregistered)
vty_out(vty, ", DE-REGISTERED");
vty_out(vty, "%s", VTY_NEWLINE);
}
}
return CMD_SUCCESS;
}
DEFUN(delete_gb_bvci, delete_gb_bvci_cmd,
"delete-gbproxy-peer <0-65534> bvci <2-65534>",
"Delete a GBProxy peer by NSEI and optionally BVCI\n"
"NSEI number\n"
"Only delete peer with a matching BVCI\n"
"BVCI number\n")
{
const uint16_t nsei = atoi(argv[0]);
const uint16_t bvci = atoi(argv[1]);
int counter;
counter = gbproxy_cleanup_peers(g_cfg, nsei, bvci);
if (counter == 0) {
vty_out(vty, "BVC not found%s", VTY_NEWLINE);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
DEFUN(delete_gb_nsei, delete_gb_nsei_cmd,
"delete-gbproxy-peer <0-65534> (only-bvc|only-nsvc|all) [dry-run]",
"Delete a GBProxy peer by NSEI and optionally BVCI\n"
"NSEI number\n"
"Only delete BSSGP connections (BVC)\n"
"Only delete dynamic NS connections (NS-VC)\n"
"Delete BVC and dynamic NS connections\n"
"Show what would be deleted instead of actually deleting\n"
)
{
const uint16_t nsei = atoi(argv[0]);
const char *mode = argv[1];
int dry_run = argc > 2;
int delete_bvc = 0;
int delete_nsvc = 0;
int counter;
if (strcmp(mode, "only-bvc") == 0)
delete_bvc = 1;
else if (strcmp(mode, "only-nsvc") == 0)
delete_nsvc = 1;
else
delete_bvc = delete_nsvc = 1;
if (delete_bvc) {
if (!dry_run)
counter = gbproxy_cleanup_peers(g_cfg, nsei, 0);
else {
struct gbproxy_peer *peer;
counter = 0;
llist_for_each_entry(peer, &g_cfg->bts_peers, list) {
if (peer->nsei != nsei)
continue;
vty_out(vty, "BVC: ");
gbprox_vty_print_peer(vty, peer);
counter += 1;
}
}
vty_out(vty, "%sDeleted %d BVC%s",
dry_run ? "Not " : "", counter, VTY_NEWLINE);
}
if (delete_nsvc) {
struct gprs_ns_inst *nsi = g_cfg->nsi;
struct gprs_nsvc *nsvc, *nsvc2;
counter = 0;
llist_for_each_entry_safe(nsvc, nsvc2, &nsi->gprs_nsvcs, list) {
if (nsvc->nsei != nsei)
continue;
if (nsvc->persistent)
continue;
if (!dry_run)
gprs_nsvc_delete(nsvc);
else
vty_out(vty, "NS-VC: NSEI %5u, NS-VCI %5u, "
"remote %s%s",
nsvc->nsei, nsvc->nsvci,
gprs_ns_ll_str(nsvc), VTY_NEWLINE);
counter += 1;
}
vty_out(vty, "%sDeleted %d NS-VC%s",
dry_run ? "Not " : "", counter, VTY_NEWLINE);
}
return CMD_SUCCESS;
}
#define GBPROXY_DELETE_LINK_STR \
"Delete a GBProxy logical link entry by NSEI and identification\nNSEI number\n"
DEFUN(delete_gb_link_by_id, delete_gb_link_by_id_cmd,
"delete-gbproxy-link <0-65534> (tlli|imsi|sgsn-nsei) IDENT",
GBPROXY_DELETE_LINK_STR
"Delete entries with a matching TLLI (hex)\n"
"Delete entries with a matching IMSI\n"
"Delete entries with a matching SGSN NSEI\n"
"Identification to match\n")
{
const uint16_t nsei = atoi(argv[0]);
enum {MATCH_TLLI = 't', MATCH_IMSI = 'i', MATCH_SGSN = 's'} match;
uint32_t ident = 0;
const char *imsi = NULL;
struct gbproxy_peer *peer = 0;
struct gbproxy_link_info *link_info, *nxt;
struct gbproxy_patch_state *state;
char mi_buf[200];
int found = 0;
match = argv[1][0];
switch (match) {
case MATCH_TLLI: ident = strtoll(argv[2], NULL, 16); break;
case MATCH_IMSI: imsi = argv[2]; break;
case MATCH_SGSN: ident = strtoll(argv[2], NULL, 0); break;
};
peer = gbproxy_peer_by_nsei(g_cfg, nsei);
if (!peer) {
vty_out(vty, "Didn't find peer with NSEI %d%s",
nsei, VTY_NEWLINE);
return CMD_WARNING;
}
state = &peer->patch_state;
llist_for_each_entry_safe(link_info, nxt, &state->logical_links, list) {
switch (match) {
case MATCH_TLLI:
if (link_info->tlli.current != ident)
continue;
break;
case MATCH_SGSN:
if (link_info->sgsn_nsei != ident)
continue;
break;
case MATCH_IMSI:
if (!link_info->imsi)
continue;
mi_buf[0] = '\0';
gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
link_info->imsi,
link_info->imsi_len);
if (strcmp(mi_buf, imsi) != 0)
continue;
break;
}
vty_out(vty, "Deleting link with TLLI %08x%s", link_info->tlli.current,
VTY_NEWLINE);
gbproxy_delete_link_info(peer, link_info);
found += 1;
}
if (!found && argc >= 2) {
vty_out(vty, "Didn't find link entry with %s %s%s",
argv[1], argv[2], VTY_NEWLINE);
}
return CMD_SUCCESS;
}
DEFUN(delete_gb_link, delete_gb_link_cmd,
"delete-gbproxy-link <0-65534> (stale|de-registered)",
GBPROXY_DELETE_LINK_STR
"Delete stale entries\n"
"Delete de-registered entries\n")
{
const uint16_t nsei = atoi(argv[0]);
enum {MATCH_STALE = 's', MATCH_DEREGISTERED = 'd'} match;
struct gbproxy_peer *peer = 0;
struct gbproxy_link_info *link_info, *nxt;
struct gbproxy_patch_state *state;
time_t now;
struct timespec ts = {0,};
int found = 0;
match = argv[1][0];
peer = gbproxy_peer_by_nsei(g_cfg, nsei);
if (!peer) {
vty_out(vty, "Didn't find peer with NSEI %d%s",
nsei, VTY_NEWLINE);
return CMD_WARNING;
}
state = &peer->patch_state;
clock_gettime(CLOCK_MONOTONIC, &ts);
now = ts.tv_sec;
if (match == MATCH_STALE) {
found = gbproxy_remove_stale_link_infos(peer, now);
if (found)
vty_out(vty, "Deleted %d stale logical link%s%s",
found, found == 1 ? "" : "s", VTY_NEWLINE);
} else {
llist_for_each_entry_safe(link_info, nxt,
&state->logical_links, list) {
if (!link_info->is_deregistered)
continue;
gbproxy_delete_link_info(peer, link_info);
found += 1;
}
}
if (found)
vty_out(vty, "Deleted %d %s logical link%s%s",
found, argv[1], found == 1 ? "" : "s", VTY_NEWLINE);
g_cfg->nsip_sgsn_nsei = port;
return CMD_SUCCESS;
}
int gbproxy_vty_init(void)
{
install_element_ve(&show_gbproxy_cmd);
install_element_ve(&show_gbproxy_links_cmd);
install_element(ENABLE_NODE, &delete_gb_bvci_cmd);
install_element(ENABLE_NODE, &delete_gb_nsei_cmd);
install_element(ENABLE_NODE, &delete_gb_link_by_id_cmd);
install_element(ENABLE_NODE, &delete_gb_link_cmd);
install_element(CONFIG_NODE, &cfg_gbproxy_cmd);
install_node(&gbproxy_node, config_write_gbproxy);
install_default(GBPROXY_NODE);
install_element(GBPROXY_NODE, &ournode_exit_cmd);
install_element(GBPROXY_NODE, &ournode_end_cmd);
vty_install_default(GBPROXY_NODE);
install_element(GBPROXY_NODE, &cfg_nsip_sgsn_nsei_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_core_mcc_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_core_mnc_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_match_imsi_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_core_apn_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_secondary_sgsn_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_patch_ptmsi_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_acquire_imsi_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_max_age_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_max_len_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_keep_mode_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mcc_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_mnc_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_match_imsi_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_core_apn_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_secondary_sgsn_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_patch_ptmsi_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_no_acquire_imsi_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_no_max_age_cmd);
install_element(GBPROXY_NODE, &cfg_gbproxy_link_list_no_max_len_cmd);
return 0;
}

View File

@@ -0,0 +1,630 @@
/* GPRS Gb message parser */
/* (C) 2014 by On-Waves
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <osmocom/gsm/gsm48.h>
#include <openbsc/gprs_gb_parse.h>
#include <openbsc/gprs_utils.h>
#include <openbsc/gsm_04_08_gprs.h>
#include <openbsc/debug.h>
#include <osmocom/gprs/gprs_bssgp.h>
static int gprs_gb_parse_gmm_attach_req(uint8_t *data, size_t data_len,
struct gprs_gb_parse_context *parse_ctx)
{
uint8_t *value;
size_t value_len;
parse_ctx->llc_msg_name = "ATTACH_REQ";
/* Skip MS network capability */
if (gprs_shift_lv(&data, &data_len, NULL, &value_len) <= 0 ||
value_len < 1 || value_len > 8)
/* invalid */
return 0;
/* Skip Attach type */
/* Skip Ciphering key sequence number */
/* Skip DRX parameter */
gprs_shift_v_fixed(&data, &data_len, 3, NULL);
/* Get Mobile identity */
if (gprs_shift_lv(&data, &data_len, &value, &value_len) <= 0 ||
value_len < 5 || value_len > 8)
/* invalid */
return 0;
if (gprs_is_mi_tmsi(value, value_len)) {
parse_ctx->ptmsi_enc = value + 1;
} else if (gprs_is_mi_imsi(value, value_len)) {
parse_ctx->imsi = value;
parse_ctx->imsi_len = value_len;
}
if (gprs_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
return 0;
parse_ctx->old_raid_enc = value;
return 1;
}
static int gprs_gb_parse_gmm_attach_ack(uint8_t *data, size_t data_len,
struct gprs_gb_parse_context *parse_ctx)
{
uint8_t *value;
size_t value_len;
parse_ctx->llc_msg_name = "ATTACH_ACK";
/* Skip Attach result */
/* Skip Force to standby */
/* Skip Periodic RA update timer */
/* Skip Radio priority for SMS */
/* Skip Spare half octet */
gprs_shift_v_fixed(&data, &data_len, 3, NULL);
if (gprs_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
return 0;
parse_ctx->raid_enc = value;
/* Skip P-TMSI signature (P-TMSI signature, opt, TV, length 4) */
gprs_match_tv_fixed(&data, &data_len, GSM48_IE_GMM_PTMSI_SIG, 3, NULL);
/* Skip Negotiated READY timer value (GPRS timer, opt, TV, length 2) */
gprs_match_tv_fixed(&data, &data_len, GSM48_IE_GMM_TIMER_READY, 1, NULL);
/* Allocated P-TMSI (Mobile identity, opt, TLV, length 7) */
if (gprs_match_tlv(&data, &data_len, GSM48_IE_GMM_ALLOC_PTMSI,
&value, &value_len) > 0 &&
gprs_is_mi_tmsi(value, value_len))
parse_ctx->new_ptmsi_enc = value + 1;
return 1;
}
static int gprs_gb_parse_gmm_attach_rej(uint8_t *data, size_t data_len,
struct gprs_gb_parse_context *parse_ctx)
{
uint8_t *value;
parse_ctx->llc_msg_name = "ATTACH_REJ";
/* GMM cause */
if (gprs_shift_v_fixed(&data, &data_len, 1, &value) <= 0)
return 0;
parse_ctx->invalidate_tlli = 1;
return 1;
}
static int gprs_gb_parse_gmm_detach_req(uint8_t *data, size_t data_len,
struct gprs_gb_parse_context *parse_ctx)
{
uint8_t *value;
size_t value_len;
int detach_type;
int power_off;
parse_ctx->llc_msg_name = "DETACH_REQ";
/* Skip spare half octet */
/* Get Detach type */
if (gprs_shift_v_fixed(&data, &data_len, 1, &value) <= 0)
/* invalid */
return 0;
detach_type = *value & 0x07;
power_off = *value & 0x08 ? 1 : 0;
if (parse_ctx->to_bss) {
/* Network originated */
if (detach_type == GPRS_DET_T_MT_REATT_REQ)
parse_ctx->await_reattach = 1;
} else {
/* Mobile originated */
if (power_off)
parse_ctx->invalidate_tlli = 1;
/* Get P-TMSI (Mobile identity), see GSM 24.008, 9.4.5.2 */
if (gprs_match_tlv(&data, &data_len,
GSM48_IE_GMM_ALLOC_PTMSI, &value, &value_len) > 0)
{
if (gprs_is_mi_tmsi(value, value_len))
parse_ctx->ptmsi_enc = value + 1;
}
}
return 1;
}
static int gprs_gb_parse_gmm_ra_upd_req(uint8_t *data, size_t data_len,
struct gprs_gb_parse_context *parse_ctx)
{
uint8_t *value;
parse_ctx->llc_msg_name = "RA_UPD_REQ";
/* Skip Update type */
/* Skip GPRS ciphering key sequence number */
gprs_shift_v_fixed(&data, &data_len, 1, NULL);
if (gprs_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
return 0;
parse_ctx->old_raid_enc = value;
return 1;
}
static int gprs_gb_parse_gmm_ra_upd_rej(uint8_t *data, size_t data_len,
struct gprs_gb_parse_context *parse_ctx)
{
uint8_t *value;
uint8_t cause;
int force_standby;
parse_ctx->llc_msg_name = "RA_UPD_REJ";
/* GMM cause */
if (gprs_shift_v_fixed(&data, &data_len, 1, &value) <= 0)
return 0;
cause = value[0];
/* Force to standby, 1/2 */
/* spare bits, 1/2 */
if (gprs_shift_v_fixed(&data, &data_len, 1, &value) <= 0)
return 0;
force_standby = (value[0] & 0x07) == 0x01;
if (cause == GMM_CAUSE_IMPL_DETACHED && !force_standby)
parse_ctx->await_reattach = 1;
parse_ctx->invalidate_tlli = 1;
return 1;
}
static int gprs_gb_parse_gmm_ra_upd_ack(uint8_t *data, size_t data_len,
struct gprs_gb_parse_context *parse_ctx)
{
uint8_t *value;
size_t value_len;
parse_ctx->llc_msg_name = "RA_UPD_ACK";
/* Skip Force to standby */
/* Skip Update result */
/* Skip Periodic RA update timer */
gprs_shift_v_fixed(&data, &data_len, 2, NULL);
if (gprs_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
return 0;
parse_ctx->raid_enc = value;
/* Skip P-TMSI signature (P-TMSI signature, opt, TV, length 4) */
gprs_match_tv_fixed(&data, &data_len, GSM48_IE_GMM_PTMSI_SIG, 3, NULL);
/* Allocated P-TMSI (Mobile identity, opt, TLV, length 7) */
if (gprs_match_tlv(&data, &data_len, GSM48_IE_GMM_ALLOC_PTMSI,
&value, &value_len) > 0 &&
gprs_is_mi_tmsi(value, value_len))
parse_ctx->new_ptmsi_enc = value + 1;
return 1;
}
static int gprs_gb_parse_gmm_ptmsi_reall_cmd(uint8_t *data, size_t data_len,
struct gprs_gb_parse_context *parse_ctx)
{
uint8_t *value;
size_t value_len;
parse_ctx->llc_msg_name = "PTMSI_REALL_CMD";
LOGP(DLLC, LOGL_NOTICE,
"Got P-TMSI Reallocation Command which is not covered by unit tests yet.\n");
/* Allocated P-TMSI */
if (gprs_shift_lv(&data, &data_len, &value, &value_len) > 0 &&
gprs_is_mi_tmsi(value, value_len))
parse_ctx->new_ptmsi_enc = value + 1;
if (gprs_shift_v_fixed(&data, &data_len, 6, &value) <= 0)
return 0;
parse_ctx->raid_enc = value;
return 1;
}
static int gprs_gb_parse_gmm_id_resp(uint8_t *data, size_t data_len,
struct gprs_gb_parse_context *parse_ctx)
{
uint8_t *value;
size_t value_len;
parse_ctx->llc_msg_name = "ID_RESP";
/* Mobile identity, Mobile identity 10.5.1.4, M LV 2-10 */
if (gprs_shift_lv(&data, &data_len, &value, &value_len) <= 0 ||
value_len < 1 || value_len > 9)
/* invalid */
return 0;
if (gprs_is_mi_tmsi(value, value_len)) {
parse_ctx->ptmsi_enc = value + 1;
} else if (gprs_is_mi_imsi(value, value_len)) {
parse_ctx->imsi = value;
parse_ctx->imsi_len = value_len;
}
return 1;
}
static int gprs_gb_parse_gsm_act_pdp_req(uint8_t *data, size_t data_len,
struct gprs_gb_parse_context *parse_ctx)
{
ssize_t old_len;
uint8_t *value;
size_t value_len;
parse_ctx->llc_msg_name = "ACT_PDP_REQ";
/* Skip Requested NSAPI */
/* Skip Requested LLC SAPI */
gprs_shift_v_fixed(&data, &data_len, 2, NULL);
/* Skip Requested QoS (support 04.08 and 24.008) */
if (gprs_shift_lv(&data, &data_len, NULL, &value_len) <= 0 ||
value_len < 4 || value_len > 14)
/* invalid */
return 0;
/* Skip Requested PDP address */
if (gprs_shift_lv(&data, &data_len, NULL, &value_len) <= 0 ||
value_len < 2 || value_len > 18)
/* invalid */
return 0;
/* Access point name */
old_len = gprs_match_tlv(&data, &data_len,
GSM48_IE_GSM_APN, &value, &value_len);
if (old_len > 0 && value_len >=1 && value_len <= 100) {
parse_ctx->apn_ie = data - old_len;
parse_ctx->apn_ie_len = old_len;
}
return 1;
}
int gprs_gb_parse_dtap(uint8_t *data, size_t data_len,
struct gprs_gb_parse_context *parse_ctx)
{
struct gsm48_hdr *g48h;
if (gprs_shift_v_fixed(&data, &data_len, sizeof(*g48h), (uint8_t **)&g48h) <= 0)
return 0;
parse_ctx->g48_hdr = g48h;
if ((g48h->proto_discr & 0x0f) != GSM48_PDISC_MM_GPRS &&
(g48h->proto_discr & 0x0f) != GSM48_PDISC_SM_GPRS)
return 1;
switch (g48h->msg_type) {
case GSM48_MT_GMM_ATTACH_REQ:
return gprs_gb_parse_gmm_attach_req(data, data_len, parse_ctx);
case GSM48_MT_GMM_ATTACH_REJ:
return gprs_gb_parse_gmm_attach_rej(data, data_len, parse_ctx);
case GSM48_MT_GMM_ATTACH_ACK:
return gprs_gb_parse_gmm_attach_ack(data, data_len, parse_ctx);
case GSM48_MT_GMM_RA_UPD_REQ:
return gprs_gb_parse_gmm_ra_upd_req(data, data_len, parse_ctx);
case GSM48_MT_GMM_RA_UPD_REJ:
return gprs_gb_parse_gmm_ra_upd_rej(data, data_len, parse_ctx);
case GSM48_MT_GMM_RA_UPD_ACK:
return gprs_gb_parse_gmm_ra_upd_ack(data, data_len, parse_ctx);
case GSM48_MT_GMM_PTMSI_REALL_CMD:
return gprs_gb_parse_gmm_ptmsi_reall_cmd(data, data_len, parse_ctx);
case GSM48_MT_GSM_ACT_PDP_REQ:
return gprs_gb_parse_gsm_act_pdp_req(data, data_len, parse_ctx);
case GSM48_MT_GMM_ID_RESP:
return gprs_gb_parse_gmm_id_resp(data, data_len, parse_ctx);
case GSM48_MT_GMM_DETACH_REQ:
return gprs_gb_parse_gmm_detach_req(data, data_len, parse_ctx);
case GSM48_MT_GMM_DETACH_ACK:
parse_ctx->llc_msg_name = "DETACH_ACK";
parse_ctx->invalidate_tlli = 1;
break;
default:
break;
};
return 1;
}
int gprs_gb_parse_llc(uint8_t *llc, size_t llc_len,
struct gprs_gb_parse_context *parse_ctx)
{
struct gprs_llc_hdr_parsed *ghp = &parse_ctx->llc_hdr_parsed;
int rc;
int fcs;
/* parse LLC */
rc = gprs_llc_hdr_parse(ghp, llc, llc_len);
gprs_llc_hdr_dump(ghp);
if (rc != 0) {
LOGP(DLLC, LOGL_NOTICE, "Error during LLC header parsing\n");
return 0;
}
fcs = gprs_llc_fcs(llc, ghp->crc_length);
LOGP(DLLC, LOGL_DEBUG, "Got LLC message, CRC: %06x (computed %06x)\n",
ghp->fcs, fcs);
if (!ghp->data)
return 0;
if (ghp->sapi != GPRS_SAPI_GMM)
return 1;
if (ghp->cmd != GPRS_LLC_UI)
return 1;
if (ghp->is_encrypted) {
parse_ctx->need_decryption = 1;
return 0;
}
return gprs_gb_parse_dtap(ghp->data, ghp->data_len, parse_ctx);
}
int gprs_gb_parse_bssgp(uint8_t *bssgp, size_t bssgp_len,
struct gprs_gb_parse_context *parse_ctx)
{
struct bssgp_normal_hdr *bgph;
struct bssgp_ud_hdr *budh = NULL;
struct tlv_parsed *tp = &parse_ctx->bssgp_tp;
uint8_t pdu_type;
uint8_t *data;
size_t data_len;
int rc;
if (bssgp_len < sizeof(struct bssgp_normal_hdr))
return 0;
bgph = (struct bssgp_normal_hdr *)bssgp;
pdu_type = bgph->pdu_type;
if (pdu_type == BSSGP_PDUT_UL_UNITDATA ||
pdu_type == BSSGP_PDUT_DL_UNITDATA) {
if (bssgp_len < sizeof(struct bssgp_ud_hdr))
return 0;
budh = (struct bssgp_ud_hdr *)bssgp;
bgph = NULL;
data = budh->data;
data_len = bssgp_len - sizeof(*budh);
} else {
data = bgph->data;
data_len = bssgp_len - sizeof(*bgph);
}
parse_ctx->pdu_type = pdu_type;
parse_ctx->bud_hdr = budh;
parse_ctx->bgp_hdr = bgph;
parse_ctx->bssgp_data = data;
parse_ctx->bssgp_data_len = data_len;
if (bssgp_tlv_parse(tp, data, data_len) < 0)
return 0;
if (budh)
parse_ctx->tlli_enc = (uint8_t *)&budh->tlli;
if (TLVP_PRESENT(tp, BSSGP_IE_ROUTEING_AREA))
parse_ctx->bssgp_raid_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_ROUTEING_AREA);
if (TLVP_PRESENT(tp, BSSGP_IE_CELL_ID))
parse_ctx->bssgp_raid_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_CELL_ID);
if (TLVP_PRESENT(tp, BSSGP_IE_IMSI)) {
parse_ctx->imsi = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_IMSI);
parse_ctx->imsi_len = TLVP_LEN(tp, BSSGP_IE_IMSI);
}
if (TLVP_PRESENT(tp, BSSGP_IE_TLLI)) {
if (parse_ctx->tlli_enc)
/* This is TLLI old, don't confuse it with TLLI current */
parse_ctx->old_tlli_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TLLI);
else
parse_ctx->tlli_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TLLI);
}
if (TLVP_PRESENT(tp, BSSGP_IE_TMSI) && pdu_type == BSSGP_PDUT_PAGING_PS)
parse_ctx->bssgp_ptmsi_enc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_TMSI);
if (TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU)) {
uint8_t *llc = (uint8_t *)TLVP_VAL(tp, BSSGP_IE_LLC_PDU);
size_t llc_len = TLVP_LEN(tp, BSSGP_IE_LLC_PDU);
rc = gprs_gb_parse_llc(llc, llc_len, parse_ctx);
if (!rc)
return 0;
parse_ctx->llc = llc;
parse_ctx->llc_len = llc_len;
}
if (parse_ctx->tlli_enc) {
uint32_t tmp_tlli;
memcpy(&tmp_tlli, parse_ctx->tlli_enc, sizeof(tmp_tlli));
parse_ctx->tlli = ntohl(tmp_tlli);
}
if (parse_ctx->bssgp_raid_enc && parse_ctx->old_raid_enc &&
memcmp(parse_ctx->bssgp_raid_enc, parse_ctx->old_raid_enc, 6) != 0)
parse_ctx->old_raid_is_foreign = 1;
return 1;
}
void gprs_gb_log_parse_context(int log_level,
struct gprs_gb_parse_context *parse_ctx,
const char *default_msg_name)
{
const char *msg_name;
const char *sep = "";
if (!parse_ctx->tlli_enc &&
!parse_ctx->ptmsi_enc &&
!parse_ctx->new_ptmsi_enc &&
!parse_ctx->bssgp_ptmsi_enc &&
!parse_ctx->imsi)
return;
msg_name = gprs_gb_message_name(parse_ctx, default_msg_name);
if (parse_ctx->llc_msg_name)
msg_name = parse_ctx->llc_msg_name;
LOGP(DGPRS, log_level, "%s: Got", msg_name);
if (parse_ctx->tlli_enc) {
LOGPC(DGPRS, log_level, "%s TLLI %08x", sep, parse_ctx->tlli);
sep = ",";
}
if (parse_ctx->old_tlli_enc) {
LOGPC(DGPRS, log_level, "%s old TLLI %02x%02x%02x%02x", sep,
parse_ctx->old_tlli_enc[0],
parse_ctx->old_tlli_enc[1],
parse_ctx->old_tlli_enc[2],
parse_ctx->old_tlli_enc[3]);
sep = ",";
}
if (parse_ctx->bssgp_raid_enc) {
struct gprs_ra_id raid;
gsm48_parse_ra(&raid, parse_ctx->bssgp_raid_enc);
LOGPC(DGPRS, log_level, "%s BSSGP RAID %u-%u-%u-%u", sep,
raid.mcc, raid.mnc, raid.lac, raid.rac);
sep = ",";
}
if (parse_ctx->raid_enc) {
struct gprs_ra_id raid;
gsm48_parse_ra(&raid, parse_ctx->raid_enc);
LOGPC(DGPRS, log_level, "%s RAID %u-%u-%u-%u", sep,
raid.mcc, raid.mnc, raid.lac, raid.rac);
sep = ",";
}
if (parse_ctx->old_raid_enc) {
struct gprs_ra_id raid;
gsm48_parse_ra(&raid, parse_ctx->old_raid_enc);
LOGPC(DGPRS, log_level, "%s old RAID %u-%u-%u-%u", sep,
raid.mcc, raid.mnc, raid.lac, raid.rac);
sep = ",";
}
if (parse_ctx->bssgp_ptmsi_enc) {
uint32_t ptmsi = GSM_RESERVED_TMSI;
gprs_parse_tmsi(parse_ctx->bssgp_ptmsi_enc, &ptmsi);
LOGPC(DGPRS, log_level, "%s BSSGP PTMSI %08x", sep, ptmsi);
sep = ",";
}
if (parse_ctx->ptmsi_enc) {
uint32_t ptmsi = GSM_RESERVED_TMSI;
gprs_parse_tmsi(parse_ctx->ptmsi_enc, &ptmsi);
LOGPC(DGPRS, log_level, "%s PTMSI %08x", sep, ptmsi);
sep = ",";
}
if (parse_ctx->new_ptmsi_enc) {
uint32_t new_ptmsi = GSM_RESERVED_TMSI;
gprs_parse_tmsi(parse_ctx->new_ptmsi_enc, &new_ptmsi);
LOGPC(DGPRS, log_level, "%s new PTMSI %08x", sep, new_ptmsi);
sep = ",";
}
if (parse_ctx->imsi) {
char mi_buf[200];
mi_buf[0] = '\0';
gsm48_mi_to_string(mi_buf, sizeof(mi_buf),
parse_ctx->imsi, parse_ctx->imsi_len);
LOGPC(DGPRS, log_level, "%s IMSI %s",
sep, mi_buf);
sep = ",";
}
if (parse_ctx->invalidate_tlli) {
LOGPC(DGPRS, log_level, "%s invalidate", sep);
sep = ",";
}
if (parse_ctx->await_reattach) {
LOGPC(DGPRS, log_level, "%s re-attach", sep);
sep = ",";
}
LOGPC(DGPRS, log_level, "\n");
}
const char *gprs_gb_message_name(const struct gprs_gb_parse_context *parse_ctx,
const char *default_msg_name)
{
if (parse_ctx->llc_msg_name)
return parse_ctx->llc_msg_name;
if (parse_ctx->g48_hdr)
return "GMM";
if (parse_ctx->llc)
return "LLC";
if (parse_ctx->bud_hdr)
return "BSSGP-UNITDATA";
if (parse_ctx->bgp_hdr)
return "BSSGP";
return "unknown";
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,288 @@
/* GPRS Subscriber Update Protocol client */
/* (C) 2014 by Sysmocom s.f.m.c. GmbH
* All Rights Reserved
*
* Author: Jacob Erlbeck
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <openbsc/gprs_gsup_client.h>
#include <osmocom/abis/ipa.h>
#include <osmocom/gsm/protocol/ipaccess.h>
#include <osmocom/core/msgb.h>
#include <openbsc/debug.h>
#include <errno.h>
#include <string.h>
extern void *tall_bsc_ctx;
static void start_test_procedure(struct gprs_gsup_client *gsupc);
static void gsup_client_send_ping(struct gprs_gsup_client *gsupc)
{
struct msgb *msg = gprs_gsup_msgb_alloc();
msg->l2h = msgb_put(msg, 1);
msg->l2h[0] = IPAC_MSGT_PING;
ipa_msg_push_header(msg, IPAC_PROTO_IPACCESS);
ipa_client_conn_send(gsupc->link, msg);
}
static int gsup_client_connect(struct gprs_gsup_client *gsupc)
{
int rc;
if (gsupc->is_connected)
return 0;
if (osmo_timer_pending(&gsupc->connect_timer)) {
LOGP(DLINP, LOGL_DEBUG,
"GSUP connect: connect timer already running\n");
osmo_timer_del(&gsupc->connect_timer);
}
if (osmo_timer_pending(&gsupc->ping_timer)) {
LOGP(DLINP, LOGL_DEBUG,
"GSUP connect: ping timer already running\n");
osmo_timer_del(&gsupc->ping_timer);
}
if (ipa_client_conn_clear_queue(gsupc->link) > 0)
LOGP(DLINP, LOGL_DEBUG, "GSUP connect: discarded stored messages\n");
rc = ipa_client_conn_open(gsupc->link);
if (rc >= 0) {
LOGP(DGPRS, LOGL_INFO, "GSUP connecting to %s:%d\n",
gsupc->link->addr, gsupc->link->port);
return 0;
}
LOGP(DGPRS, LOGL_INFO, "GSUP failed to connect to %s:%d: %s\n",
gsupc->link->addr, gsupc->link->port, strerror(-rc));
if (rc == -EBADF || rc == -ENOTSOCK || rc == -EAFNOSUPPORT ||
rc == -EINVAL)
return rc;
osmo_timer_schedule(&gsupc->connect_timer, GPRS_GSUP_RECONNECT_INTERVAL, 0);
LOGP(DGPRS, LOGL_INFO, "Scheduled timer to retry GSUP connect to %s:%d\n",
gsupc->link->addr, gsupc->link->port);
return 0;
}
static void connect_timer_cb(void *gsupc_)
{
struct gprs_gsup_client *gsupc = gsupc_;
if (gsupc->is_connected)
return;
gsup_client_connect(gsupc);
}
static void gsup_client_updown_cb(struct ipa_client_conn *link, int up)
{
struct gprs_gsup_client *gsupc = link->data;
LOGP(DGPRS, LOGL_INFO, "GSUP link to %s:%d %s\n",
link->addr, link->port, up ? "UP" : "DOWN");
gsupc->is_connected = up;
if (up) {
start_test_procedure(gsupc);
osmo_timer_del(&gsupc->connect_timer);
} else {
osmo_timer_del(&gsupc->ping_timer);
osmo_timer_schedule(&gsupc->connect_timer,
GPRS_GSUP_RECONNECT_INTERVAL, 0);
}
}
static int gsup_client_read_cb(struct ipa_client_conn *link, struct msgb *msg)
{
struct ipaccess_head *hh = (struct ipaccess_head *) msg->data;
struct ipaccess_head_ext *he = (struct ipaccess_head_ext *) msgb_l2(msg);
struct gprs_gsup_client *gsupc = (struct gprs_gsup_client *)link->data;
int rc;
static struct ipaccess_unit ipa_dev = {
.unit_name = "SGSN"
};
msg->l2h = &hh->data[0];
rc = ipaccess_bts_handle_ccm(link, &ipa_dev, msg);
if (rc < 0) {
LOGP(DGPRS, LOGL_NOTICE,
"GSUP received an invalid IPA/CCM message from %s:%d\n",
link->addr, link->port);
/* Link has been closed */
gsupc->is_connected = 0;
msgb_free(msg);
return -1;
}
if (rc == 1) {
uint8_t msg_type = *(msg->l2h);
/* CCM message */
if (msg_type == IPAC_MSGT_PONG) {
LOGP(DGPRS, LOGL_DEBUG, "GSUP receiving PONG\n");
gsupc->got_ipa_pong = 1;
}
msgb_free(msg);
return 0;
}
if (hh->proto != IPAC_PROTO_OSMO)
goto invalid;
if (!he || msgb_l2len(msg) < sizeof(*he) ||
he->proto != IPAC_PROTO_EXT_GSUP)
goto invalid;
msg->l2h = &he->data[0];
OSMO_ASSERT(gsupc->read_cb != NULL);
gsupc->read_cb(gsupc, msg);
/* Not freeing msg here, because that must be done by the read_cb. */
return 0;
invalid:
LOGP(DGPRS, LOGL_NOTICE,
"GSUP received an invalid IPA message from %s:%d, size = %d\n",
link->addr, link->port, msgb_length(msg));
msgb_free(msg);
return -1;
}
static void ping_timer_cb(void *gsupc_)
{
struct gprs_gsup_client *gsupc = gsupc_;
LOGP(DGPRS, LOGL_INFO, "GSUP ping callback (%s, %s PONG)\n",
gsupc->is_connected ? "connected" : "not connected",
gsupc->got_ipa_pong ? "got" : "didn't get");
if (gsupc->got_ipa_pong) {
start_test_procedure(gsupc);
return;
}
LOGP(DGPRS, LOGL_NOTICE, "GSUP ping timed out, reconnecting\n");
ipa_client_conn_close(gsupc->link);
gsupc->is_connected = 0;
gsup_client_connect(gsupc);
}
static void start_test_procedure(struct gprs_gsup_client *gsupc)
{
gsupc->ping_timer.data = gsupc;
gsupc->ping_timer.cb = &ping_timer_cb;
gsupc->got_ipa_pong = 0;
osmo_timer_schedule(&gsupc->ping_timer, GPRS_GSUP_PING_INTERVAL, 0);
LOGP(DGPRS, LOGL_DEBUG, "GSUP sending PING\n");
gsup_client_send_ping(gsupc);
}
struct gprs_gsup_client *gprs_gsup_client_create(const char *ip_addr,
unsigned int tcp_port,
gprs_gsup_read_cb_t read_cb)
{
struct gprs_gsup_client *gsupc;
int rc;
gsupc = talloc_zero(tall_bsc_ctx, struct gprs_gsup_client);
OSMO_ASSERT(gsupc);
gsupc->link = ipa_client_conn_create(gsupc,
/* no e1inp */ NULL,
0,
ip_addr, tcp_port,
gsup_client_updown_cb,
gsup_client_read_cb,
/* default write_cb */ NULL,
gsupc);
if (!gsupc->link)
goto failed;
gsupc->connect_timer.data = gsupc;
gsupc->connect_timer.cb = &connect_timer_cb;
rc = gsup_client_connect(gsupc);
if (rc < 0)
goto failed;
gsupc->read_cb = read_cb;
return gsupc;
failed:
gprs_gsup_client_destroy(gsupc);
return NULL;
}
void gprs_gsup_client_destroy(struct gprs_gsup_client *gsupc)
{
osmo_timer_del(&gsupc->connect_timer);
osmo_timer_del(&gsupc->ping_timer);
if (gsupc->link) {
ipa_client_conn_close(gsupc->link);
ipa_client_conn_destroy(gsupc->link);
gsupc->link = NULL;
}
talloc_free(gsupc);
}
int gprs_gsup_client_send(struct gprs_gsup_client *gsupc, struct msgb *msg)
{
if (!gsupc) {
msgb_free(msg);
return -ENOTCONN;
}
if (!gsupc->is_connected) {
msgb_free(msg);
return -EAGAIN;
}
ipa_prepend_header_ext(msg, IPAC_PROTO_EXT_GSUP);
ipa_msg_push_header(msg, IPAC_PROTO_OSMO);
ipa_client_conn_send(gsupc->link, msg);
return 0;
}
struct msgb *gprs_gsup_msgb_alloc(void)
{
return msgb_alloc_headroom(4000, 64, __func__);
}

View File

@@ -0,0 +1,439 @@
/* GPRS Subscriber Update Protocol message encoder/decoder */
/*
* (C) 2014 by Sysmocom s.f.m.c. GmbH
* (C) 2015 by Holger Hans Peter Freyther
* All Rights Reserved
*
* Author: Jacob Erlbeck
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <openbsc/gprs_gsup_messages.h>
#include <openbsc/debug.h>
#include <openbsc/gprs_utils.h>
#include <osmocom/gsm/tlv.h>
#include <osmocom/core/msgb.h>
#include <stdint.h>
static uint64_t decode_big_endian(const uint8_t *data, size_t data_len)
{
uint64_t value = 0;
while (data_len > 0) {
value = (value << 8) + *data;
data += 1;
data_len -= 1;
}
return value;
}
static uint8_t *encode_big_endian(uint64_t value, size_t data_len)
{
static uint8_t buf[sizeof(uint64_t)];
int idx;
OSMO_ASSERT(data_len <= ARRAY_SIZE(buf));
for (idx = data_len - 1; idx >= 0; idx--) {
buf[idx] = (uint8_t)value;
value = value >> 8;
}
return buf;
}
static int decode_pdp_info(uint8_t *data, size_t data_len,
struct gprs_gsup_pdp_info *pdp_info)
{
int rc;
uint8_t tag;
uint8_t *value;
size_t value_len;
/* specific parts */
while (data_len > 0) {
enum gprs_gsup_iei iei;
rc = gprs_shift_tlv(&data, &data_len, &tag, &value, &value_len);
if (rc < 0)
return -GMM_CAUSE_PROTO_ERR_UNSPEC;
iei = tag;
switch (iei) {
case GPRS_GSUP_PDP_CONTEXT_ID_IE:
pdp_info->context_id = decode_big_endian(value, value_len);
break;
case GPRS_GSUP_PDP_TYPE_IE:
pdp_info->pdp_type =
decode_big_endian(value, value_len) & 0x0fff;
break;
case GPRS_GSUP_ACCESS_POINT_NAME_IE:
pdp_info->apn_enc = value;
pdp_info->apn_enc_len = value_len;
break;
case GPRS_GSUP_PDP_QOS_IE:
pdp_info->qos_enc = value;
pdp_info->qos_enc_len = value_len;
break;
default:
LOGP(DGPRS, LOGL_ERROR,
"GSUP IE type %d not expected in PDP info\n", iei);
continue;
}
}
return 0;
}
static int decode_auth_info(uint8_t *data, size_t data_len,
struct gsm_auth_tuple *auth_tuple)
{
int rc;
uint8_t tag;
uint8_t *value;
size_t value_len;
enum gprs_gsup_iei iei;
/* specific parts */
while (data_len > 0) {
rc = gprs_shift_tlv(&data, &data_len, &tag, &value, &value_len);
if (rc < 0)
return -GMM_CAUSE_PROTO_ERR_UNSPEC;
iei = tag;
switch (iei) {
case GPRS_GSUP_RAND_IE:
if (value_len != sizeof(auth_tuple->rand))
goto parse_error;
memcpy(auth_tuple->rand, value, value_len);
break;
case GPRS_GSUP_SRES_IE:
if (value_len != sizeof(auth_tuple->sres))
goto parse_error;
memcpy(auth_tuple->sres, value, value_len);
break;
case GPRS_GSUP_KC_IE:
if (value_len != sizeof(auth_tuple->kc))
goto parse_error;
memcpy(auth_tuple->kc, value, value_len);
break;
default:
LOGP(DGPRS, LOGL_ERROR,
"GSUP IE type %d not expected in PDP info\n", iei);
continue;
}
}
return 0;
parse_error:
LOGP(DGPRS, LOGL_ERROR,
"GSUP IE type %d, length %zu invalid in PDP info\n", iei, value_len);
return -1;
}
int gprs_gsup_decode(const uint8_t *const_data, size_t data_len,
struct gprs_gsup_message *gsup_msg)
{
int rc;
uint8_t tag;
/* the shift/match functions expect non-const pointers, but we'll
* either copy the data or cast pointers back to const before returning
* them
*/
uint8_t *data = (uint8_t *)const_data;
uint8_t *value;
size_t value_len;
static const struct gprs_gsup_pdp_info empty_pdp_info = {0};
static const struct gsm_auth_tuple empty_auth_info = {0};
static const struct gprs_gsup_message empty_gsup_message = {0};
*gsup_msg = empty_gsup_message;
/* generic part */
rc = gprs_shift_v_fixed(&data, &data_len, 1, &value);
if (rc < 0)
return -GMM_CAUSE_INV_MAND_INFO;
gsup_msg->message_type = decode_big_endian(value, 1);
rc = gprs_match_tlv(&data, &data_len, GPRS_GSUP_IMSI_IE,
&value, &value_len);
if (rc <= 0)
return -GMM_CAUSE_INV_MAND_INFO;
if (value_len * 2 + 1 > sizeof(gsup_msg->imsi))
return -GMM_CAUSE_INV_MAND_INFO;
/* Note that gsm48_decode_bcd_number expects the number of encoded IMSI
* octets in the first octet. By coincidence (the TLV encoding) the byte
* before the value part already contains this length so we can use it
* here.
*/
OSMO_ASSERT(value[-1] == value_len);
gsm48_decode_bcd_number(gsup_msg->imsi, sizeof(gsup_msg->imsi),
value - 1, 0);
/* specific parts */
while (data_len > 0) {
enum gprs_gsup_iei iei;
struct gprs_gsup_pdp_info pdp_info;
struct gsm_auth_tuple auth_info;
rc = gprs_shift_tlv(&data, &data_len, &tag, &value, &value_len);
if (rc < 0)
return -GMM_CAUSE_PROTO_ERR_UNSPEC;
iei = tag;
switch (iei) {
case GPRS_GSUP_IMSI_IE:
case GPRS_GSUP_PDP_TYPE_IE:
case GPRS_GSUP_ACCESS_POINT_NAME_IE:
case GPRS_GSUP_RAND_IE:
case GPRS_GSUP_SRES_IE:
case GPRS_GSUP_KC_IE:
LOGP(DGPRS, LOGL_NOTICE,
"GSUP IE type %d not expected (ignored)\n", iei);
continue;
case GPRS_GSUP_CAUSE_IE:
gsup_msg->cause = decode_big_endian(value, value_len);
break;
case GPRS_GSUP_CANCEL_TYPE_IE:
gsup_msg->cancel_type =
decode_big_endian(value, value_len) + 1;
break;
case GPRS_GSUP_PDP_INFO_COMPL_IE:
gsup_msg->pdp_info_compl = 1;
break;
case GPRS_GSUP_FREEZE_PTMSI_IE:
gsup_msg->freeze_ptmsi = 1;
break;
case GPRS_GSUP_PDP_CONTEXT_ID_IE:
/* When these IE appear in the top-level part of the
* message, they are used by Delete Subscr Info to delete
* single entries. We don't have an extra list for
* these but use the PDP info list instead */
/* fall through */
case GPRS_GSUP_PDP_INFO_IE:
if (gsup_msg->num_pdp_infos >= GPRS_GSUP_MAX_NUM_PDP_INFO) {
LOGP(DGPRS, LOGL_ERROR,
"GSUP IE type %d (PDP_INFO) max exceeded\n",
iei);
return -GMM_CAUSE_COND_IE_ERR;
}
pdp_info = empty_pdp_info;
if (iei == GPRS_GSUP_PDP_INFO_IE) {
rc = decode_pdp_info(value, value_len, &pdp_info);
if (rc < 0)
return rc;
pdp_info.have_info = 1;
} else {
pdp_info.context_id =
decode_big_endian(value, value_len);
}
gsup_msg->pdp_infos[gsup_msg->num_pdp_infos++] =
pdp_info;
break;
case GPRS_GSUP_AUTH_TUPLE_IE:
if (gsup_msg->num_auth_tuples >= GPRS_GSUP_MAX_NUM_AUTH_INFO) {
LOGP(DGPRS, LOGL_ERROR,
"GSUP IE type %d (AUTH_INFO) max exceeded\n",
iei);
return -GMM_CAUSE_INV_MAND_INFO;
}
auth_info = empty_auth_info;
auth_info.key_seq = gsup_msg->num_auth_tuples;
rc = decode_auth_info(value, value_len, &auth_info);
if (rc < 0)
return rc;
gsup_msg->auth_tuples[gsup_msg->num_auth_tuples++] =
auth_info;
break;
case GPRS_GSUP_MSISDN_IE:
gsup_msg->msisdn_enc = value;
gsup_msg->msisdn_enc_len = value_len;
break;
default:
LOGP(DGPRS, LOGL_NOTICE,
"GSUP IE type %d unknown\n", iei);
continue;
}
}
return 0;
}
static void encode_pdp_info(struct msgb *msg, enum gprs_gsup_iei iei,
const struct gprs_gsup_pdp_info *pdp_info)
{
uint8_t *len_field;
size_t old_len;
uint8_t u8;
len_field = msgb_tlv_put(msg, iei, 0, NULL) - 1;
old_len = msgb_length(msg);
u8 = pdp_info->context_id;
msgb_tlv_put(msg, GPRS_GSUP_PDP_CONTEXT_ID_IE, sizeof(u8), &u8);
if (pdp_info->pdp_type) {
msgb_tlv_put(msg, GPRS_GSUP_PDP_TYPE_IE,
GPRS_GSUP_PDP_TYPE_SIZE,
encode_big_endian(pdp_info->pdp_type | 0xf000,
GPRS_GSUP_PDP_TYPE_SIZE));
}
if (pdp_info->apn_enc) {
msgb_tlv_put(msg, GPRS_GSUP_ACCESS_POINT_NAME_IE,
pdp_info->apn_enc_len, pdp_info->apn_enc);
}
if (pdp_info->qos_enc) {
msgb_tlv_put(msg, GPRS_GSUP_PDP_QOS_IE,
pdp_info->qos_enc_len, pdp_info->qos_enc);
}
/* Update length field */
*len_field = msgb_length(msg) - old_len;
}
static void encode_auth_info(struct msgb *msg, enum gprs_gsup_iei iei,
const struct gsm_auth_tuple *auth_tuple)
{
uint8_t *len_field;
size_t old_len;
len_field = msgb_tlv_put(msg, iei, 0, NULL) - 1;
old_len = msgb_length(msg);
msgb_tlv_put(msg, GPRS_GSUP_RAND_IE,
sizeof(auth_tuple->rand), auth_tuple->rand);
msgb_tlv_put(msg, GPRS_GSUP_SRES_IE,
sizeof(auth_tuple->sres), auth_tuple->sres);
msgb_tlv_put(msg, GPRS_GSUP_KC_IE,
sizeof(auth_tuple->kc), auth_tuple->kc);
/* Update length field */
*len_field = msgb_length(msg) - old_len;
}
void gprs_gsup_encode(struct msgb *msg, const struct gprs_gsup_message *gsup_msg)
{
uint8_t u8;
int idx;
uint8_t bcd_buf[GSM48_MI_SIZE] = {0};
size_t bcd_len;
/* generic part */
OSMO_ASSERT(gsup_msg->message_type);
msgb_v_put(msg, gsup_msg->message_type);
bcd_len = gsm48_encode_bcd_number(bcd_buf, sizeof(bcd_buf), 0,
gsup_msg->imsi);
OSMO_ASSERT(bcd_len > 1);
/* Note that gsm48_encode_bcd_number puts the length into the first
* octet. Since msgb_tlv_put will add this length byte, we'll have to
* skip it */
msgb_tlv_put(msg, GPRS_GSUP_IMSI_IE, bcd_len - 1, &bcd_buf[1]);
/* specific parts */
if (gsup_msg->msisdn_enc)
msgb_tlv_put(msg, GPRS_GSUP_MSISDN_IE,
gsup_msg->msisdn_enc_len, gsup_msg->msisdn_enc);
if ((u8 = gsup_msg->cause))
msgb_tlv_put(msg, GPRS_GSUP_CAUSE_IE, sizeof(u8), &u8);
if ((u8 = gsup_msg->cancel_type)) {
u8 -= 1;
msgb_tlv_put(msg, GPRS_GSUP_CANCEL_TYPE_IE, sizeof(u8), &u8);
}
if (gsup_msg->pdp_info_compl)
msgb_tlv_put(msg, GPRS_GSUP_PDP_INFO_COMPL_IE, 0, &u8);
if (gsup_msg->freeze_ptmsi)
msgb_tlv_put(msg, GPRS_GSUP_FREEZE_PTMSI_IE, 0, &u8);
for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) {
const struct gprs_gsup_pdp_info *pdp_info;
pdp_info = &gsup_msg->pdp_infos[idx];
if (pdp_info->context_id == 0)
continue;
if (pdp_info->have_info) {
encode_pdp_info(msg, GPRS_GSUP_PDP_INFO_IE, pdp_info);
} else {
u8 = pdp_info->context_id;
msgb_tlv_put(msg, GPRS_GSUP_PDP_CONTEXT_ID_IE,
sizeof(u8), &u8);
}
}
for (idx = 0; idx < gsup_msg->num_auth_tuples; idx++) {
const struct gsm_auth_tuple *auth_info;
auth_info = &gsup_msg->auth_tuples[idx];
if (auth_info->key_seq == GSM_KEY_SEQ_INVAL)
continue;
encode_auth_info(msg, GPRS_GSUP_AUTH_TUPLE_IE, auth_info);
}
}

View File

@@ -36,6 +36,23 @@
#include <openbsc/crc24.h>
#include <openbsc/sgsn.h>
static struct gprs_llc_llme *llme_alloc(uint32_t tlli);
/* If the TLLI is foreign, return its local version */
static inline uint32_t tlli_foreign2local(uint32_t tlli)
{
uint32_t new_tlli;
if (gprs_tlli_type(tlli) == TLLI_FOREIGN) {
new_tlli = tlli | 0x40000000;
LOGP(DLLC, LOGL_NOTICE, "TLLI 0x%08x is foreign, converting to "
"local TLLI 0x%08x\n", tlli, new_tlli);
} else
new_tlli = tlli;
return new_tlli;
}
/* Entry function from upper level (LLC), asking us to transmit a BSSGP PDU
* to a remote MS (identified by TLLI) at a BTS identified by its BVCI and NSEI */
static int _bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx)
@@ -52,6 +69,12 @@ static int _bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx)
dup.drx_parms = mmctx->drx_parms;
dup.ms_ra_cap.len = mmctx->ms_radio_access_capa.len;
dup.ms_ra_cap.v = mmctx->ms_radio_access_capa.buf;
/* make sure we only send it to the right llme */
OSMO_ASSERT(msgb_tlli(msg) == mmctx->llme->tlli
|| msgb_tlli(msg) == mmctx->llme->old_tlli
|| tlli_foreign2local(msgb_tlli(msg)) == mmctx->llme->tlli
|| tlli_foreign2local(msgb_tlli(msg)) == mmctx->llme->old_tlli);
}
memcpy(&dup.qos_profile, qos_profile_default,
sizeof(qos_profile_default));
@@ -61,7 +84,7 @@ static int _bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx)
/* Section 8.9.9 LLC layer parameter default values */
static const struct gprs_llc_params llc_default_params[] = {
static const struct gprs_llc_params llc_default_params[NUM_SAPIS] = {
[1] = {
.t200_201 = 5,
.n200 = 3,
@@ -131,28 +154,11 @@ static const struct gprs_llc_params llc_default_params[] = {
LLIST_HEAD(gprs_llc_llmes);
void *llc_tall_ctx;
/* If the TLLI is foreign, return its local version */
static inline uint32_t tlli_foreign2local(uint32_t tlli)
{
uint32_t new_tlli;
if (gprs_tlli_type(tlli) == TLLI_FOREIGN) {
new_tlli = tlli | 0x40000000;
DEBUGP(DLLC, "TLLI 0x%08x is foreign, converting to "
"local TLLI 0x%08x\n", tlli, new_tlli);
} else
new_tlli = tlli;
return new_tlli;
}
/* lookup LLC Entity based on DLCI (TLLI+SAPI tuple) */
static struct gprs_llc_lle *lle_by_tlli_sapi(uint32_t tlli, uint8_t sapi)
static struct gprs_llc_lle *lle_by_tlli_sapi(const uint32_t tlli, uint8_t sapi)
{
struct gprs_llc_llme *llme;
tlli = tlli_foreign2local(tlli);
llist_for_each_entry(llme, &gprs_llc_llmes, list) {
if (llme->tlli == tlli || llme->old_tlli == tlli)
return &llme->lle[sapi];
@@ -160,6 +166,72 @@ static struct gprs_llc_lle *lle_by_tlli_sapi(uint32_t tlli, uint8_t sapi)
return NULL;
}
struct gprs_llc_lle *gprs_lle_get_or_create(const uint32_t tlli, uint8_t sapi)
{
struct gprs_llc_llme *llme;
struct gprs_llc_lle *lle;
lle = lle_by_tlli_sapi(tlli, sapi);
if (lle)
return lle;
lle = lle_by_tlli_sapi(tlli_foreign2local(tlli), sapi);
if (lle)
return lle;
LOGP(DLLC, LOGL_NOTICE, "LLC: unknown TLLI 0x%08x, "
"creating LLME on the fly\n", tlli);
llme = llme_alloc(tlli);
lle = &llme->lle[sapi];
return lle;
}
struct llist_head *gprs_llme_list(void)
{
return &gprs_llc_llmes;
}
/* lookup LLC Entity for RX based on DLCI (TLLI+SAPI tuple) */
static struct gprs_llc_lle *lle_for_rx_by_tlli_sapi(const uint32_t tlli,
uint8_t sapi, enum gprs_llc_cmd cmd)
{
struct gprs_llc_lle *lle;
/* We already know about this TLLI */
lle = lle_by_tlli_sapi(tlli, sapi);
if (lle)
return lle;
/* Maybe it is a routing area update but we already know this sapi? */
if (gprs_tlli_type(tlli) == TLLI_FOREIGN) {
lle = lle_by_tlli_sapi(tlli_foreign2local(tlli), sapi);
if (lle) {
LOGP(DLLC, LOGL_NOTICE,
"LLC RX: Found a local entry for TLLI 0x%08x\n",
tlli);
return lle;
}
}
/* 7.2.1.1 LLC belonging to unassigned TLLI+SAPI shall be discarded,
* except UID and XID frames with SAPI=1 */
if (sapi == GPRS_SAPI_GMM &&
(cmd == GPRS_LLC_XID || cmd == GPRS_LLC_UI)) {
struct gprs_llc_llme *llme;
/* FIXME: don't use the TLLI but the 0xFFFF unassigned? */
llme = llme_alloc(tlli);
LOGP(DLLC, LOGL_NOTICE, "LLC RX: unknown TLLI 0x%08x, "
"creating LLME on the fly\n", tlli);
lle = &llme->lle[sapi];
return lle;
}
LOGP(DLLC, LOGL_NOTICE,
"unknown TLLI(0x%08x)/SAPI(%d): Silently dropping\n",
tlli, sapi);
return NULL;
}
static void lle_init(struct gprs_llc_llme *llme, uint8_t sapi)
{
struct gprs_llc_lle *lle = &llme->lle[sapi];
@@ -184,6 +256,7 @@ static struct gprs_llc_llme *llme_alloc(uint32_t tlli)
llme->tlli = tlli;
llme->old_tlli = 0xffffffff;
llme->state = GPRS_LLMS_UNASSIGNED;
llme->age_timestamp = GPRS_LLME_RESET_AGE;
for (i = 0; i < ARRAY_SIZE(llme->lle); i++)
lle_init(llme, i);
@@ -199,68 +272,8 @@ static void llme_free(struct gprs_llc_llme *llme)
talloc_free(llme);
}
enum gprs_llc_cmd {
GPRS_LLC_NULL,
GPRS_LLC_RR,
GPRS_LLC_ACK,
GPRS_LLC_RNR,
GPRS_LLC_SACK,
GPRS_LLC_DM,
GPRS_LLC_DISC,
GPRS_LLC_UA,
GPRS_LLC_SABM,
GPRS_LLC_FRMR,
GPRS_LLC_XID,
GPRS_LLC_UI,
};
static const struct value_string llc_cmd_strs[] = {
{ GPRS_LLC_NULL, "NULL" },
{ GPRS_LLC_RR, "RR" },
{ GPRS_LLC_ACK, "ACK" },
{ GPRS_LLC_RNR, "RNR" },
{ GPRS_LLC_SACK, "SACK" },
{ GPRS_LLC_DM, "DM" },
{ GPRS_LLC_DISC, "DISC" },
{ GPRS_LLC_UA, "UA" },
{ GPRS_LLC_SABM, "SABM" },
{ GPRS_LLC_FRMR, "FRMR" },
{ GPRS_LLC_XID, "XID" },
{ GPRS_LLC_UI, "UI" },
{ 0, NULL }
};
struct gprs_llc_hdr_parsed {
uint8_t sapi;
uint8_t is_cmd:1,
ack_req:1,
is_encrypted:1;
uint32_t seq_rx;
uint32_t seq_tx;
uint32_t fcs;
uint32_t fcs_calc;
uint8_t *data;
uint16_t data_len;
uint16_t crc_length;
enum gprs_llc_cmd cmd;
};
#define LLC_ALLOC_SIZE 16384
#define UI_HDR_LEN 3
#define N202 4
#define CRC24_LENGTH 3
static int gprs_llc_fcs(uint8_t *data, unsigned int len)
{
uint32_t fcs_calc;
fcs_calc = crc24_calc(INIT_CRC24, data, len);
fcs_calc = ~fcs_calc;
fcs_calc &= 0xffffff;
return fcs_calc;
}
#if 0
/* FIXME: Unused code... */
static void t200_expired(void *data)
{
struct gprs_llc_lle *lle = data;
@@ -283,6 +296,9 @@ static void t200_expired(void *data)
/* FIXME: re-start T200 */
lle->retrans_ctr++;
break;
default:
LOGP(DLLC, LOGL_ERROR, "LLC unhandled state: %d\n", lle->state);
break;
}
}
@@ -297,6 +313,7 @@ static void t201_expired(void *data)
lle->retrans_ctr++;
}
}
#endif
int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, int command,
enum gprs_llc_u_cmd u_cmd, int pf_bit)
@@ -361,18 +378,12 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
/* Identifiers from UP: (TLLI, SAPI) + (BVCI, NSEI) */
/* look-up or create the LL Entity for this (TLLI, SAPI) tuple */
lle = lle_by_tlli_sapi(msgb_tlli(msg), sapi);
if (!lle) {
struct gprs_llc_llme *llme;
LOGP(DLLC, LOGL_ERROR, "LLC TX: unknown TLLI 0x%08x, "
"creating LLME on the fly\n", msgb_tlli(msg));
llme = llme_alloc(msgb_tlli(msg));
lle = &llme->lle[sapi];
}
lle = gprs_lle_get_or_create(msgb_tlli(msg), sapi);
if (msg->len > lle->params.n201_u) {
LOGP(DLLC, LOGL_ERROR, "Cannot Tx %u bytes (N201-U=%u)\n",
msg->len, lle->params.n201_u);
msgb_free(msg);
return -EFBIG;
}
@@ -430,6 +441,7 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command,
kc, iv, GPRS_CIPH_SGSN2MS);
if (rc < 0) {
LOGP(DLLC, LOGL_ERROR, "Error crypting UI frame: %d\n", rc);
msgb_free(msg);
return rc;
}
@@ -495,20 +507,6 @@ static void rx_llc_xid(struct gprs_llc_lle *lle,
}
}
static void gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph)
{
DEBUGP(DLLC, "LLC SAPI=%u %c %c FCS=0x%06x",
gph->sapi, gph->is_cmd ? 'C' : 'R', gph->ack_req ? 'A' : ' ',
gph->fcs);
if (gph->cmd)
DEBUGPC(DLLC, "CMD=%s ", get_value_string(llc_cmd_strs, gph->cmd));
if (gph->data)
DEBUGPC(DLLC, "DATA ");
DEBUGPC(DLLC, "\n");
}
static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph,
struct gprs_llc_lle *lle)
{
@@ -547,7 +545,23 @@ static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph,
"TLLI=%08x dropping UI, N(U=%d) not in window V(URV(UR:%d).\n",
lle->llme ? lle->llme->tlli : -1,
gph->seq_tx, lle->vu_recv);
return -EIO;
/* HACK: non-standard recovery handling. If remote LLE
* is re-transmitting the same sequence number for
* three times, don't discard the frame but pass it on
* and 'learn' the new sequence number */
if (gph->seq_tx != lle->vu_recv_last) {
lle->vu_recv_last = gph->seq_tx;
lle->vu_recv_duplicates = 0;
} else {
lle->vu_recv_duplicates++;
if (lle->vu_recv_duplicates < 3)
return -EIO;
LOGP(DLLC, LOGL_NOTICE, "TLLI=%08x recovering "
"N(U=%d) after receiving %u duplicates\n",
lle->llme ? lle->llme->tlli : -1,
gph->seq_tx, lle->vu_recv_duplicates);
}
}
/* Increment the sequence number that we expect in the next frame */
lle->vu_recv = (gph->seq_tx + 1) % 512;
@@ -555,166 +569,9 @@ static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph,
if ((gph->seq_tx + 1) / 512)
lle->oc_ui_recv += 512;
break;
}
return 0;
}
/* parse a GPRS LLC header, also check for invalid frames */
static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
uint8_t *llc_hdr, int len)
{
uint8_t *ctrl = llc_hdr+1;
if (len <= CRC24_LENGTH)
return -EIO;
ghp->crc_length = len - CRC24_LENGTH;
ghp->ack_req = 0;
/* Section 5.5: FCS */
ghp->fcs = *(llc_hdr + len - 3);
ghp->fcs |= *(llc_hdr + len - 2) << 8;
ghp->fcs |= *(llc_hdr + len - 1) << 16;
/* Section 6.2.1: invalid PD field */
if (llc_hdr[0] & 0x80)
return -EIO;
/* This only works for the MS->SGSN direction */
if (llc_hdr[0] & 0x40)
ghp->is_cmd = 0;
else
ghp->is_cmd = 1;
ghp->sapi = llc_hdr[0] & 0xf;
/* Section 6.2.3: check for reserved SAPI */
switch (ghp->sapi) {
case 0:
case 4:
case 6:
case 0xa:
case 0xc:
case 0xd:
case 0xf:
return -EINVAL;
}
if ((ctrl[0] & 0x80) == 0) {
/* I (Information transfer + Supervisory) format */
uint8_t k;
ghp->data = ctrl + 3;
if (ctrl[0] & 0x40)
ghp->ack_req = 1;
ghp->seq_tx = (ctrl[0] & 0x1f) << 4;
ghp->seq_tx |= (ctrl[1] >> 4);
ghp->seq_rx = (ctrl[1] & 0x7) << 6;
ghp->seq_rx |= (ctrl[2] >> 2);
switch (ctrl[2] & 0x03) {
case 0:
ghp->cmd = GPRS_LLC_RR;
break;
case 1:
ghp->cmd = GPRS_LLC_ACK;
break;
case 2:
ghp->cmd = GPRS_LLC_RNR;
break;
case 3:
ghp->cmd = GPRS_LLC_SACK;
k = ctrl[3] & 0x1f;
ghp->data += 1 + k;
break;
}
ghp->data_len = (llc_hdr + len - 3) - ghp->data;
} else if ((ctrl[0] & 0xc0) == 0x80) {
/* S (Supervisory) format */
ghp->data = NULL;
ghp->data_len = 0;
if (ctrl[0] & 0x20)
ghp->ack_req = 1;
ghp->seq_rx = (ctrl[0] & 0x7) << 6;
ghp->seq_rx |= (ctrl[1] >> 2);
switch (ctrl[1] & 0x03) {
case 0:
ghp->cmd = GPRS_LLC_RR;
break;
case 1:
ghp->cmd = GPRS_LLC_ACK;
break;
case 2:
ghp->cmd = GPRS_LLC_RNR;
break;
case 3:
ghp->cmd = GPRS_LLC_SACK;
break;
}
} else if ((ctrl[0] & 0xe0) == 0xc0) {
/* UI (Unconfirmed Inforamtion) format */
ghp->cmd = GPRS_LLC_UI;
ghp->data = ctrl + 2;
ghp->data_len = (llc_hdr + len - 3) - ghp->data;
ghp->seq_tx = (ctrl[0] & 0x7) << 6;
ghp->seq_tx |= (ctrl[1] >> 2);
if (ctrl[1] & 0x02) {
ghp->is_encrypted = 1;
/* FIXME: encryption */
}
if (ctrl[1] & 0x01) {
/* FCS over hdr + all inf fields */
} else {
/* FCS over hdr + N202 octets (4) */
if (ghp->crc_length > UI_HDR_LEN + N202)
ghp->crc_length = UI_HDR_LEN + N202;
}
} else {
/* U (Unnumbered) format: 1 1 1 P/F M4 M3 M2 M1 */
ghp->data = NULL;
ghp->data_len = 0;
switch (ctrl[0] & 0xf) {
case GPRS_LLC_U_NULL_CMD:
ghp->cmd = GPRS_LLC_NULL;
break;
case GPRS_LLC_U_DM_RESP:
ghp->cmd = GPRS_LLC_DM;
break;
case GPRS_LLC_U_DISC_CMD:
ghp->cmd = GPRS_LLC_DISC;
break;
case GPRS_LLC_U_UA_RESP:
ghp->cmd = GPRS_LLC_UA;
break;
case GPRS_LLC_U_SABM_CMD:
ghp->cmd = GPRS_LLC_SABM;
break;
case GPRS_LLC_U_FRMR_RESP:
ghp->cmd = GPRS_LLC_FRMR;
break;
case GPRS_LLC_U_XID:
ghp->cmd = GPRS_LLC_XID;
ghp->data = ctrl + 1;
ghp->data_len = (llc_hdr + len - 3) - ghp->data;
break;
default:
return -EIO;
}
}
/* FIXME: parse sack frame */
if (ghp->cmd == GPRS_LLC_SACK) {
LOGP(DLLC, LOGL_NOTICE, "Unsupported SACK frame\n");
return -EIO;
default:
LOGP(DLLC, LOGL_NOTICE, "Unhandled command: %d\n", gph->cmd);
break;
}
return 0;
@@ -723,7 +580,6 @@ static int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
/* receive an incoming LLC PDU (BSSGP-UL-UNITDATA-IND, 7.2.4.2) */
int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
{
struct bssgp_ud_hdr *udh = (struct bssgp_ud_hdr *) msgb_bssgph(msg);
struct gprs_llc_hdr *lh = (struct gprs_llc_hdr *) msgb_llch(msg);
struct gprs_llc_hdr_parsed llhp;
struct gprs_llc_lle *lle;
@@ -752,26 +608,24 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
}
/* find the LLC Entity for this TLLI+SAPI tuple */
lle = lle_by_tlli_sapi(msgb_tlli(msg), llhp.sapi);
/* 7.2.1.1 LLC belonging to unassigned TLLI+SAPI shall be discarded,
* except UID and XID frames with SAPI=1 */
lle = lle_for_rx_by_tlli_sapi(msgb_tlli(msg), llhp.sapi, llhp.cmd);
if (!lle) {
if (llhp.sapi == GPRS_SAPI_GMM &&
(llhp.cmd == GPRS_LLC_XID || llhp.cmd == GPRS_LLC_UI)) {
struct gprs_llc_llme *llme;
/* FIXME: don't use the TLLI but the 0xFFFF unassigned? */
llme = llme_alloc(msgb_tlli(msg));
LOGP(DLLC, LOGL_DEBUG, "LLC RX: unknown TLLI 0x%08x, "
"creating LLME on the fly\n", msgb_tlli(msg));
lle = &llme->lle[llhp.sapi];
} else {
LOGP(DLLC, LOGL_NOTICE,
"unknown TLLI/SAPI: Silently dropping\n");
return 0;
switch (llhp.sapi) {
case GPRS_SAPI_SNDCP3:
case GPRS_SAPI_SNDCP5:
case GPRS_SAPI_SNDCP9:
case GPRS_SAPI_SNDCP11:
/* Ask an upper layer for help. */
return sgsn_force_reattach_oldmsg(msg);
default:
break;
}
return 0;
}
/* reset age computation */
lle->llme->age_timestamp = GPRS_LLME_RESET_AGE;
/* decrypt information field + FCS, if needed! */
if (llhp.is_encrypted) {
uint32_t iov_ui = 0; /* FIXME: randomly select for TLLI */
@@ -893,8 +747,8 @@ int gprs_llgmm_assign(struct gprs_llc_llme *llme,
} else if (old_tlli != 0xffffffff && new_tlli != 0xffffffff) {
/* TLLI Change 8.3.2 */
/* Both TLLI Old and TLLI New are assigned; use New when
* (re)transmitting. Accept toth Old and New on Rx */
llme->old_tlli = llme->tlli;
* (re)transmitting. Accept both Old and New on Rx */
llme->old_tlli = old_tlli;
llme->tlli = new_tlli;
llme->state = GPRS_LLMS_ASSIGNED;
} else if (old_tlli != 0xffffffff && new_tlli == 0xffffffff) {
@@ -914,6 +768,27 @@ int gprs_llgmm_assign(struct gprs_llc_llme *llme,
/* Chapter 7.2.1.2 LLGMM-RESET.req */
int gprs_llgmm_reset(struct gprs_llc_llme *llme)
{
struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID");
int random = rand();
struct gprs_llc_lle *lle = &llme->lle[1];
/* First XID component must be RESET */
msgb_put_xid_par(msg, GPRS_LLC_XID_T_RESET, 0, NULL);
/* randomly select new IOV-UI */
msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &random);
/* Reset some of the LLC parameters. See GSM 04.64, 8.5.3.1 */
lle->vu_recv = 0;
lle->vu_send = 0;
lle->oc_ui_send = 0;
lle->oc_ui_recv = 0;
/* FIXME: Start T200, wait for XID response */
return gprs_llc_tx_xid(lle, msg, 1);
}
int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi)
{
struct msgb *msg = msgb_alloc_headroom(4096, 1024, "LLC_XID");
int random = rand();
@@ -924,7 +799,12 @@ int gprs_llgmm_reset(struct gprs_llc_llme *llme)
msgb_put_xid_par(msg, GPRS_LLC_XID_T_IOV_UI, 4, (uint8_t *) &random);
/* FIXME: Start T200, wait for XID response */
return gprs_llc_tx_xid(&llme->lle[1], msg, 1);
msgb_tlli(msg) = msgb_tlli(oldmsg);
msgb_bvci(msg) = msgb_bvci(oldmsg);
msgb_nsei(msg) = msgb_nsei(oldmsg);
return gprs_llc_tx_u(msg, sapi, 1, GPRS_LLC_U_XID, 1);
}
int gprs_llc_init(const char *cipher_plugin_path)

View File

@@ -0,0 +1,243 @@
/* GPRS LLC protocol implementation as per 3GPP TS 04.64 */
/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <errno.h>
#include <stdint.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/talloc.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <openbsc/gsm_data.h>
#include <openbsc/debug.h>
#include <openbsc/gprs_sgsn.h>
#include <openbsc/gprs_gmm.h>
#include <openbsc/gprs_llc.h>
#include <openbsc/crc24.h>
static const struct value_string llc_cmd_strs[] = {
{ GPRS_LLC_NULL, "NULL" },
{ GPRS_LLC_RR, "RR" },
{ GPRS_LLC_ACK, "ACK" },
{ GPRS_LLC_RNR, "RNR" },
{ GPRS_LLC_SACK, "SACK" },
{ GPRS_LLC_DM, "DM" },
{ GPRS_LLC_DISC, "DISC" },
{ GPRS_LLC_UA, "UA" },
{ GPRS_LLC_SABM, "SABM" },
{ GPRS_LLC_FRMR, "FRMR" },
{ GPRS_LLC_XID, "XID" },
{ GPRS_LLC_UI, "UI" },
{ 0, NULL }
};
#define LLC_ALLOC_SIZE 16384
#define UI_HDR_LEN 3
#define N202 4
#define CRC24_LENGTH 3
int gprs_llc_fcs(uint8_t *data, unsigned int len)
{
uint32_t fcs_calc;
fcs_calc = crc24_calc(INIT_CRC24, data, len);
fcs_calc = ~fcs_calc;
fcs_calc &= 0xffffff;
return fcs_calc;
}
void gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph)
{
DEBUGP(DLLC, "LLC SAPI=%u %c %c FCS=0x%06x",
gph->sapi, gph->is_cmd ? 'C' : 'R', gph->ack_req ? 'A' : ' ',
gph->fcs);
if (gph->cmd)
DEBUGPC(DLLC, "CMD=%s ", get_value_string(llc_cmd_strs, gph->cmd));
if (gph->data)
DEBUGPC(DLLC, "DATA ");
DEBUGPC(DLLC, "\n");
}
/* parse a GPRS LLC header, also check for invalid frames */
int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp,
uint8_t *llc_hdr, int len)
{
uint8_t *ctrl = llc_hdr+1;
if (len <= CRC24_LENGTH)
return -EIO;
ghp->crc_length = len - CRC24_LENGTH;
ghp->ack_req = 0;
/* Section 5.5: FCS */
ghp->fcs = *(llc_hdr + len - 3);
ghp->fcs |= *(llc_hdr + len - 2) << 8;
ghp->fcs |= *(llc_hdr + len - 1) << 16;
/* Section 6.2.1: invalid PD field */
if (llc_hdr[0] & 0x80)
return -EIO;
/* This only works for the MS->SGSN direction */
if (llc_hdr[0] & 0x40)
ghp->is_cmd = 0;
else
ghp->is_cmd = 1;
ghp->sapi = llc_hdr[0] & 0xf;
/* Section 6.2.3: check for reserved SAPI */
switch (ghp->sapi) {
case 0:
case 4:
case 6:
case 0xa:
case 0xc:
case 0xd:
case 0xf:
return -EINVAL;
}
if ((ctrl[0] & 0x80) == 0) {
/* I (Information transfer + Supervisory) format */
uint8_t k;
ghp->data = ctrl + 3;
if (ctrl[0] & 0x40)
ghp->ack_req = 1;
ghp->seq_tx = (ctrl[0] & 0x1f) << 4;
ghp->seq_tx |= (ctrl[1] >> 4);
ghp->seq_rx = (ctrl[1] & 0x7) << 6;
ghp->seq_rx |= (ctrl[2] >> 2);
switch (ctrl[2] & 0x03) {
case 0:
ghp->cmd = GPRS_LLC_RR;
break;
case 1:
ghp->cmd = GPRS_LLC_ACK;
break;
case 2:
ghp->cmd = GPRS_LLC_RNR;
break;
case 3:
ghp->cmd = GPRS_LLC_SACK;
k = ctrl[3] & 0x1f;
ghp->data += 1 + k;
break;
}
ghp->data_len = (llc_hdr + len - 3) - ghp->data;
} else if ((ctrl[0] & 0xc0) == 0x80) {
/* S (Supervisory) format */
ghp->data = NULL;
ghp->data_len = 0;
if (ctrl[0] & 0x20)
ghp->ack_req = 1;
ghp->seq_rx = (ctrl[0] & 0x7) << 6;
ghp->seq_rx |= (ctrl[1] >> 2);
switch (ctrl[1] & 0x03) {
case 0:
ghp->cmd = GPRS_LLC_RR;
break;
case 1:
ghp->cmd = GPRS_LLC_ACK;
break;
case 2:
ghp->cmd = GPRS_LLC_RNR;
break;
case 3:
ghp->cmd = GPRS_LLC_SACK;
break;
}
} else if ((ctrl[0] & 0xe0) == 0xc0) {
/* UI (Unconfirmed Inforamtion) format */
ghp->cmd = GPRS_LLC_UI;
ghp->data = ctrl + 2;
ghp->data_len = (llc_hdr + len - 3) - ghp->data;
ghp->seq_tx = (ctrl[0] & 0x7) << 6;
ghp->seq_tx |= (ctrl[1] >> 2);
if (ctrl[1] & 0x02) {
ghp->is_encrypted = 1;
/* FIXME: encryption */
}
if (ctrl[1] & 0x01) {
/* FCS over hdr + all inf fields */
} else {
/* FCS over hdr + N202 octets (4) */
if (ghp->crc_length > UI_HDR_LEN + N202)
ghp->crc_length = UI_HDR_LEN + N202;
}
} else {
/* U (Unnumbered) format: 1 1 1 P/F M4 M3 M2 M1 */
ghp->data = NULL;
ghp->data_len = 0;
switch (ctrl[0] & 0xf) {
case GPRS_LLC_U_NULL_CMD:
ghp->cmd = GPRS_LLC_NULL;
break;
case GPRS_LLC_U_DM_RESP:
ghp->cmd = GPRS_LLC_DM;
break;
case GPRS_LLC_U_DISC_CMD:
ghp->cmd = GPRS_LLC_DISC;
break;
case GPRS_LLC_U_UA_RESP:
ghp->cmd = GPRS_LLC_UA;
break;
case GPRS_LLC_U_SABM_CMD:
ghp->cmd = GPRS_LLC_SABM;
break;
case GPRS_LLC_U_FRMR_RESP:
ghp->cmd = GPRS_LLC_FRMR;
break;
case GPRS_LLC_U_XID:
ghp->cmd = GPRS_LLC_XID;
ghp->data = ctrl + 1;
ghp->data_len = (llc_hdr + len - 3) - ghp->data;
break;
default:
return -EIO;
}
}
/* FIXME: parse sack frame */
if (ghp->cmd == GPRS_LLC_SACK) {
LOGP(DLLC, LOGL_NOTICE, "Unsupported SACK frame\n");
return -EIO;
}
return 0;
}

View File

@@ -23,6 +23,7 @@
#include <unistd.h>
#include <errno.h>
#include <stdint.h>
#include <time.h>
#include <arpa/inet.h>
@@ -69,9 +70,13 @@ static uint8_t valid_sapis[] = { 1, 2, 3, 5, 7, 8, 9, 11 };
static void vty_dump_llme(struct vty *vty, struct gprs_llc_llme *llme)
{
unsigned int i;
struct timespec now_tp = {0};
clock_gettime(CLOCK_MONOTONIC, &now_tp);
vty_out(vty, "TLLI %08x (Old TLLI %08x) BVCI=%u NSEI=%u: State %s%s",
vty_out(vty, "TLLI %08x (Old TLLI %08x) BVCI=%u NSEI=%u Age=%d: State %s%s",
llme->tlli, llme->old_tlli, llme->bvci, llme->nsei,
llme->age_timestamp == GPRS_LLME_RESET_AGE ? 0 :
(int)(now_tp.tv_sec - (time_t)llme->age_timestamp),
get_value_string(gprs_llc_state_strs, llme->state), VTY_NEWLINE);
for (i = 0; i < ARRAY_SIZE(valid_sapis); i++) {

View File

@@ -35,6 +35,12 @@
#include <openbsc/sgsn.h>
#include <openbsc/gsm_04_08_gprs.h>
#include <openbsc/gprs_gmm.h>
#include <openbsc/gprs_utils.h>
#include "openbsc/gprs_llc.h"
#include <time.h>
#define GPRS_LLME_CHECK_TICK 30
extern struct sgsn_instance *sgsn;
@@ -166,6 +172,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli,
memcpy(&ctx->ra, raid, sizeof(ctx->ra));
ctx->tlli = tlli;
ctx->mm_state = GMM_DEREGISTERED;
ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL;
ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, tlli);
INIT_LLIST_HEAD(&ctx->pdp_list);
@@ -186,12 +193,45 @@ void sgsn_mm_ctx_free(struct sgsn_mm_ctx *mm)
/* Free all PDP contexts */
llist_for_each_entry_safe(pdp, pdp2, &mm->pdp_list, list)
sgsn_pdp_ctx_free(pdp);
rate_ctr_group_free(mm->ctrg);
talloc_free(mm);
}
void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *mm)
{
struct gprs_llc_llme *llme = mm->llme;
uint32_t tlli = mm->tlli;
struct sgsn_pdp_ctx *pdp, *pdp2;
/* delete all existing PDP contexts for this MS */
llist_for_each_entry_safe(pdp, pdp2, &mm->pdp_list, list) {
LOGMMCTXP(LOGL_NOTICE, mm,
"Dropping PDP context for NSAPI=%u\n", pdp->nsapi);
sgsn_pdp_ctx_terminate(pdp);
}
if (osmo_timer_pending(&mm->timer)) {
LOGMMCTXP(LOGL_INFO, mm, "Cancelling MM timer %u\n", mm->T);
osmo_timer_del(&mm->timer);
}
/* Detach from subscriber which is possibly freed then */
if (mm->subscr) {
struct gsm_subscriber *subscr = subscr_get(mm->subscr);
gprs_subscr_cleanup(subscr);
subscr_put(subscr);
}
sgsn_mm_ctx_free(mm);
mm = NULL;
/* TLLI unassignment, must be called after sgsn_mm_ctx_free */
gprs_llgmm_assign(llme, tlli, 0xffffffff, GPRS_ALGO_GEA0, NULL);
}
/* look up PDP context by MM context and NSAPI */
struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm,
uint8_t nsapi)
@@ -242,11 +282,40 @@ struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
}
#include <pdp.h>
/* you probably want to call sgsn_delete_pdp_ctx() instead */
/*
* This function will not trigger any GSM DEACT PDP ACK messages, so you
* probably want to call sgsn_delete_pdp_ctx() instead if the connection
* isn't detached already.
*/
void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp)
{
OSMO_ASSERT(pdp->mm != NULL);
/* There might still be pending callbacks in libgtp. So the parts of
* this object relevant to GTP need to remain intact in this case. */
LOGPDPCTXP(LOGL_INFO, pdp, "Forcing release of PDP context\n");
/* Force the deactivation of the SNDCP layer */
sndcp_sm_deactivate_ind(&pdp->mm->llme->lle[pdp->sapi], pdp->nsapi);
/* Detach from MM context */
llist_del(&pdp->list);
pdp->mm = NULL;
sgsn_delete_pdp_ctx(pdp);
}
/*
* Don't call this function directly unless you know what you are doing.
* In normal conditions use sgsn_delete_pdp_ctx and in unspecified or
* implementation dependent abnormal ones sgsn_pdp_ctx_terminate.
*/
void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp)
{
rate_ctr_group_free(pdp->ctrg);
llist_del(&pdp->list);
if (pdp->mm)
llist_del(&pdp->list);
llist_del(&pdp->g_list);
/* _if_ we still have a library handle, at least set it to NULL
@@ -254,7 +323,7 @@ void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp)
* sgsn_libgtp:cb_data_ind() */
if (pdp->lib) {
struct pdp_t *lib = pdp->lib;
LOGP(DGPRS, LOGL_NOTICE, "freeing PDP context that still "
LOGPDPCTXP(LOGL_NOTICE, pdp, "freeing PDP context that still "
"has a libgtp handle attached to it, this shouldn't "
"happen!\n");
osmo_generate_backtrace();
@@ -284,6 +353,12 @@ struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id)
return ggc;
}
void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc)
{
llist_del(&ggc->list);
talloc_free(ggc);
}
struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id)
{
struct sgsn_ggsn_ctx *ggc;
@@ -319,55 +394,146 @@ struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id)
/* APN contexts */
#if 0
struct apn_ctx *apn_ctx_alloc(const char *ap_name)
static struct apn_ctx *sgsn_apn_ctx_alloc(const char *ap_name, const char *imsi_prefix)
{
struct apn_ctx *actx;
actx = talloc_zero(talloc_bsc_ctx, struct apn_ctx);
actx = talloc_zero(tall_bsc_ctx, struct apn_ctx);
if (!actx)
return NULL;
actx->name = talloc_strdup(actx, ap_name);
actx->imsi_prefix = talloc_strdup(actx, imsi_prefix);
llist_add_tail(&actx->list, &sgsn_apn_ctxts);
return actx;
}
struct apn_ctx *apn_ctx_by_name(const char *name)
void sgsn_apn_ctx_free(struct apn_ctx *actx)
{
llist_del(&actx->list);
talloc_free(actx);
}
struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi)
{
struct apn_ctx *actx;
struct apn_ctx *found_actx = NULL;
size_t imsi_prio = 0;
size_t name_prio = 0;
size_t name_req_len = strlen(name);
llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
size_t name_ref_len, imsi_ref_len;
const char *name_ref_start, *name_match_start;
imsi_ref_len = strlen(actx->imsi_prefix);
if (strncmp(actx->imsi_prefix, imsi, imsi_ref_len) != 0)
continue;
if (imsi_ref_len < imsi_prio)
continue;
/* IMSI matches */
name_ref_start = &actx->name[0];
if (name_ref_start[0] == '*') {
/* Suffix match */
name_ref_start += 1;
name_ref_len = strlen(name_ref_start);
if (name_ref_len > name_req_len)
continue;
} else {
name_ref_len = strlen(name_ref_start);
if (name_ref_len != name_req_len)
continue;
}
name_match_start = name + (name_req_len - name_ref_len);
if (strcasecmp(name_match_start, name_ref_start) != 0)
continue;
/* IMSI and name match */
if (imsi_ref_len == imsi_prio && name_ref_len < name_prio)
/* Lower priority, skip */
continue;
imsi_prio = imsi_ref_len;
name_prio = name_ref_len;
found_actx = actx;
}
return found_actx;
}
struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix)
{
struct apn_ctx *actx;
llist_for_each_entry(actx, &sgsn_apn_ctxts, list) {
if (!strcmp(name, actx->name))
if (strcasecmp(name, actx->name) == 0 &&
strcasecmp(imsi_prefix, actx->imsi_prefix) == 0)
return actx;
}
return NULL;
}
struct apn_ctx *apn_ctx_find_alloc(const char *name)
struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix)
{
struct apn_ctx *actx;
actx = apn_ctx_by_name(name);
actx = sgsn_apn_ctx_by_name(name, imsi_prefix);
if (!actx)
actx = apn_ctx_alloc(name);
actx = sgsn_apn_ctx_alloc(name, imsi_prefix);
return actx;
}
#endif
uint32_t sgsn_alloc_ptmsi(void)
{
struct sgsn_mm_ctx *mm;
uint32_t ptmsi;
int max_retries = 100;
restart:
ptmsi = rand();
/* Enforce that the 2 MSB are set without loosing the distance between
* identical values. Since rand() has no duplicate values within a
* period (because the size of the state is the same like the size of
* the random value), this leads to a distance of period/4 when the
* distribution of the 2 MSB is uniform. This approach fails with a
* probability of (3/4)^max_retries, only 1% of the approaches will
* need more than 16 numbers (even distribution assumed).
*
* Alternatively, a freeze list could be used if another PRNG is used
* or when this approach proves to be not sufficient.
*/
if (ptmsi >= 0xC0000000) {
if (!max_retries--)
goto failed;
goto restart;
}
ptmsi |= 0xC0000000;
if (ptmsi == GSM_RESERVED_TMSI) {
if (!max_retries--)
goto failed;
goto restart;
}
llist_for_each_entry(mm, &sgsn_mm_ctxts, list) {
if (mm->p_tmsi == ptmsi)
if (mm->p_tmsi == ptmsi) {
if (!max_retries--)
goto failed;
goto restart;
}
}
return ptmsi;
failed:
LOGP(DGPRS, LOGL_ERROR, "Failed to allocate a P-TMSI\n");
return GSM_RESERVED_TMSI;
}
static void drop_one_pdp(struct sgsn_pdp_ctx *pdp)
@@ -376,7 +542,7 @@ static void drop_one_pdp(struct sgsn_pdp_ctx *pdp)
gsm48_tx_gsm_deact_pdp_req(pdp, GSM_CAUSE_NET_FAIL);
else {
/* FIXME: GPRS paging in case MS is SUSPENDED */
LOGP(DGPRS, LOGL_NOTICE, "Hard-dropping PDP ctx due to GGSN "
LOGPDPCTXP(LOGL_NOTICE, pdp, "Hard-dropping PDP ctx due to GGSN "
"recovery\n");
/* FIXME: how to tell this to libgtp? */
sgsn_pdp_ctx_free(pdp);
@@ -384,7 +550,7 @@ static void drop_one_pdp(struct sgsn_pdp_ctx *pdp)
}
/* High-level function to be called in case a GGSN has disappeared or
* ottherwise lost state (recovery procedure) */
* otherwise lost state (recovery procedure) */
int drop_all_pdp_for_ggsn(struct sgsn_ggsn_ctx *ggsn)
{
struct sgsn_mm_ctx *mm;
@@ -402,3 +568,199 @@ int drop_all_pdp_for_ggsn(struct sgsn_ggsn_ctx *ggsn)
return num;
}
int sgsn_force_reattach_oldmsg(struct msgb *oldmsg)
{
return gsm0408_gprs_force_reattach_oldmsg(oldmsg);
}
void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx)
{
OSMO_ASSERT(mmctx != NULL);
LOGMMCTXP(LOGL_INFO, mmctx, "Subscriber data update\n");
sgsn_auth_update(mmctx);
}
static void insert_qos(struct tlv_parsed *tp, struct sgsn_subscriber_pdp_data *pdp)
{
tp->lv[OSMO_IE_GSM_SUB_QOS].len = pdp->qos_subscribed_len;
tp->lv[OSMO_IE_GSM_SUB_QOS].val = pdp->qos_subscribed;
}
/**
* The tlv_parsed tp parameter will be modified to insert a
* OSMO_IE_GSM_SUB_QOS in case the data is available in the
* PDP context handling.
*/
struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx,
struct tlv_parsed *tp,
enum gsm48_gsm_cause *gsm_cause)
{
char req_apn_str[GSM_APN_LENGTH] = {0};
const struct apn_ctx *apn_ctx = NULL;
const char *selected_apn_str = NULL;
struct sgsn_subscriber_pdp_data *pdp;
struct sgsn_ggsn_ctx *ggsn = NULL;
int allow_any_apn = 0;
if (TLVP_PRESENT(tp, GSM48_IE_GSM_APN)) {
if (TLVP_LEN(tp, GSM48_IE_GSM_APN) >= GSM_APN_LENGTH - 1) {
LOGMMCTXP(LOGL_ERROR, mmctx, "APN IE too long\n");
*gsm_cause = GSM_CAUSE_INV_MAND_INFO;
return NULL;
}
gprs_apn_to_str(req_apn_str,
TLVP_VAL(tp, GSM48_IE_GSM_APN),
TLVP_LEN(tp, GSM48_IE_GSM_APN));
if (strcmp(req_apn_str, "*") == 0)
req_apn_str[0] = 0;
}
if (mmctx->subscr == NULL ||
llist_empty(&mmctx->subscr->sgsn_data->pdp_list))
allow_any_apn = 1;
if (strlen(req_apn_str) == 0 && !allow_any_apn) {
/* No specific APN requested, check for an APN that is both
* granted and configured */
llist_for_each_entry(pdp, &mmctx->subscr->sgsn_data->pdp_list, list) {
if (strcmp(pdp->apn_str, "*") == 0)
{
allow_any_apn = 1;
selected_apn_str = "";
insert_qos(tp, pdp);
continue;
}
if (!llist_empty(&sgsn_apn_ctxts)) {
apn_ctx = sgsn_apn_ctx_match(req_apn_str, mmctx->imsi);
/* Not configured */
if (apn_ctx == NULL)
continue;
}
insert_qos(tp, pdp);
selected_apn_str = pdp->apn_str;
break;
}
} else if (!allow_any_apn) {
/* Check whether the given APN is granted */
llist_for_each_entry(pdp, &mmctx->subscr->sgsn_data->pdp_list, list) {
if (strcmp(pdp->apn_str, "*") == 0) {
insert_qos(tp, pdp);
selected_apn_str = req_apn_str;
allow_any_apn = 1;
continue;
}
if (strcasecmp(pdp->apn_str, req_apn_str) == 0) {
insert_qos(tp, pdp);
selected_apn_str = req_apn_str;
break;
}
}
} else if (strlen(req_apn_str) != 0) {
/* Any APN is allowed */
selected_apn_str = req_apn_str;
} else {
/* Prefer the GGSN associated with the wildcard APN */
selected_apn_str = "";
}
if (!allow_any_apn && selected_apn_str == NULL) {
/* Access not granted */
LOGMMCTXP(LOGL_NOTICE, mmctx,
"The requested APN '%s' is not allowed\n",
req_apn_str);
*gsm_cause = GSM_CAUSE_REQ_SERV_OPT_NOTSUB;
return NULL;
}
if (apn_ctx == NULL && selected_apn_str)
apn_ctx = sgsn_apn_ctx_match(selected_apn_str, mmctx->imsi);
if (apn_ctx != NULL) {
ggsn = apn_ctx->ggsn;
} else if (llist_empty(&sgsn_apn_ctxts)) {
/* No configuration -> use GGSN 0 */
ggsn = sgsn_ggsn_ctx_by_id(0);
} else if (allow_any_apn &&
(selected_apn_str == NULL || strlen(selected_apn_str) == 0)) {
/* No APN given and no default configuration -> Use GGSN 0 */
ggsn = sgsn_ggsn_ctx_by_id(0);
} else {
/* No matching configuration found */
LOGMMCTXP(LOGL_NOTICE, mmctx,
"The selected APN '%s' has not been configured\n",
selected_apn_str);
*gsm_cause = GSM_CAUSE_MISSING_APN;
return NULL;
}
LOGMMCTXP(LOGL_INFO, mmctx,
"Found GGSN %d for APN '%s' (requested '%s')\n",
ggsn->id, selected_apn_str ? selected_apn_str : "---",
req_apn_str);
return ggsn;
}
static void sgsn_llme_cleanup_free(struct gprs_llc_llme *llme)
{
struct sgsn_mm_ctx *mmctx = NULL;
llist_for_each_entry(mmctx, &sgsn_mm_ctxts, list) {
if (llme == mmctx->llme) {
gsm0408_gprs_access_cancelled(mmctx, SGSN_ERROR_CAUSE_NONE);
return;
}
}
/* No MM context found */
LOGP(DGPRS, LOGL_INFO, "Deleting orphaned LLME, TLLI 0x%08x\n",
llme->tlli);
gprs_llgmm_assign(llme, llme->tlli, 0xffffffff, GPRS_ALGO_GEA0, NULL);
}
static void sgsn_llme_check_cb(void *data_)
{
struct gprs_llc_llme *llme, *llme_tmp;
struct timespec now_tp;
time_t now, age;
time_t max_age = gprs_max_time_to_idle();
int rc;
rc = clock_gettime(CLOCK_MONOTONIC, &now_tp);
OSMO_ASSERT(rc >= 0);
now = now_tp.tv_sec;
LOGP(DGPRS, LOGL_DEBUG,
"Checking for inactive LLMEs, time = %u\n", (unsigned)now);
llist_for_each_entry_safe(llme, llme_tmp, &gprs_llc_llmes, list) {
if (llme->age_timestamp == GPRS_LLME_RESET_AGE)
llme->age_timestamp = now;
age = now - llme->age_timestamp;
if (age > max_age || age < 0) {
LOGP(DGPRS, LOGL_INFO,
"Inactivity timeout for TLLI 0x%08x, age %d\n",
llme->tlli, (int)age);
sgsn_llme_cleanup_free(llme);
}
}
osmo_timer_schedule(&sgsn->llme_timer, GPRS_LLME_CHECK_TICK, 0);
}
void sgsn_inst_init()
{
sgsn->llme_timer.cb = sgsn_llme_check_cb;
sgsn->llme_timer.data = NULL;
osmo_timer_schedule(&sgsn->llme_timer, GPRS_LLME_CHECK_TICK, 0);
}

View File

@@ -185,7 +185,6 @@ static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg, uint8_t
unsigned int len)
{
struct sndcp_common_hdr *sch;
struct sndcp_comp_hdr *scomph = NULL;
struct sndcp_udata_hdr *suh;
uint16_t npdu_num;
uint8_t *data;
@@ -193,7 +192,6 @@ static int defrag_input(struct gprs_sndcp_entity *sne, struct msgb *msg, uint8_t
sch = (struct sndcp_common_hdr *) hdr;
if (sch->first) {
scomph = (struct sndcp_comp_hdr *) (hdr + 1);
suh = (struct sndcp_udata_hdr *) (hdr + 1 + sizeof(struct sndcp_common_hdr));
} else
suh = (struct sndcp_udata_hdr *) (hdr + sizeof(struct sndcp_common_hdr));
@@ -360,8 +358,10 @@ static int sndcp_send_ud_frag(struct sndcp_frag_state *fs)
fmsg = msgb_alloc_headroom(fs->sne->lle->params.n201_u+256, 128,
"SNDCP Frag");
if (!fmsg)
if (!fmsg) {
msgb_free(fs->msg);
return -ENOMEM;
}
/* make sure lower layers route the fragment like the original */
msgb_tlli(fmsg) = msgb_tlli(fs->msg);
@@ -418,9 +418,9 @@ static int sndcp_send_ud_frag(struct sndcp_frag_state *fs)
sch->more = more;
rc = gprs_llc_tx_ui(fmsg, lle->sapi, 0, fs->mmcontext);
/* abort in case of error, do not advance frag_nr / next_byte */
if (rc < 0) {
/* abort in case of error, do not advance frag_nr / next_byte */
msgb_free(fmsg);
msgb_free(fs->msg);
return rc;
}
@@ -452,6 +452,7 @@ int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi
sne = gprs_sndcp_entity_by_lle(lle, nsapi);
if (!sne) {
LOGP(DSNDCP, LOGL_ERROR, "Cannot find SNDCP Entity\n");
msgb_free(msg);
return -EIO;
}
@@ -509,7 +510,7 @@ int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
struct sndcp_comp_hdr *scomph = NULL;
struct sndcp_udata_hdr *suh;
uint8_t *npdu;
uint16_t npdu_num;
uint16_t npdu_num __attribute__((unused));
int npdu_len;
sch = (struct sndcp_common_hdr *) hdr;
@@ -561,6 +562,7 @@ int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle,
return sgsn_rx_sndcp_ud_ind(&sne->ra_id, lle->llme->tlli, sne->nsapi, msg, npdu_len, npdu);
}
#if 0
/* Section 5.1.2.1 LL-RESET.ind */
static int sndcp_ll_reset_ind(struct gprs_sndcp_entity *se)
{
@@ -577,7 +579,6 @@ static int sndcp_ll_status_ind()
return 0;
}
#if 0
static struct sndcp_state_list {{
uint32_t states;
unsigned int type;

View File

@@ -43,8 +43,6 @@
static void vty_dump_sne(struct vty *vty, struct gprs_sndcp_entity *sne)
{
unsigned int i;
vty_out(vty, " TLLI %08x SAPI=%u NSAPI=%u:%s",
sne->lle->llme->tlli, sne->lle->sapi, sne->nsapi, VTY_NEWLINE);
vty_out(vty, " Defrag: npdu=%u highest_seg=%u seg_have=0x%08x tot_len=%u%s",

View File

@@ -0,0 +1,782 @@
/* MS subscriber data handling */
/* (C) 2014 by sysmocom s.f.m.c. GmbH
* (C) 2015 by Holger Hans Peter Freyther
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <openbsc/gsm_subscriber.h>
#include <openbsc/gprs_gsup_client.h>
#include <openbsc/sgsn.h>
#include <openbsc/gprs_sgsn.h>
#include <openbsc/gprs_gmm.h>
#include <openbsc/gprs_gsup_messages.h>
#include <openbsc/gprs_utils.h>
#include <openbsc/debug.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define SGSN_SUBSCR_MAX_RETRIES 3
#define SGSN_SUBSCR_RETRY_INTERVAL 10
#define LOGGSUPP(level, gsup, fmt, args...) \
LOGP(DGPRS, level, "GSUP(%s) " fmt, \
(gsup)->imsi, \
## args)
extern void *tall_bsc_ctx;
static int gsup_read_cb(struct gprs_gsup_client *gsupc, struct msgb *msg);
/* TODO: Some functions are specific to the SGSN, but this file is more general
* (it has gprs_* name). Either move these functions elsewhere, split them and
* move a part, or replace the gprs_ prefix by sgsn_. The applies to
* gprs_subscr_init, gsup_read_cb, and gprs_subscr_tx_gsup_message.
*/
int gprs_subscr_init(struct sgsn_instance *sgi)
{
const char *addr_str;
if (!sgi->cfg.gsup_server_addr.sin_addr.s_addr)
return 0;
addr_str = inet_ntoa(sgi->cfg.gsup_server_addr.sin_addr);
sgi->gsup_client = gprs_gsup_client_create(
addr_str, sgi->cfg.gsup_server_port,
&gsup_read_cb);
if (!sgi->gsup_client)
return -1;
return 1;
}
static int gsup_read_cb(struct gprs_gsup_client *gsupc, struct msgb *msg)
{
int rc;
rc = gprs_subscr_rx_gsup_message(msg);
msgb_free(msg);
if (rc < 0)
return -1;
return rc;
}
int gprs_subscr_purge(struct gsm_subscriber *subscr);
static struct sgsn_subscriber_data *sgsn_subscriber_data_alloc(void *ctx)
{
struct sgsn_subscriber_data *sdata;
int idx;
sdata = talloc_zero(ctx, struct sgsn_subscriber_data);
sdata->error_cause = SGSN_ERROR_CAUSE_NONE;
for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
INIT_LLIST_HEAD(&sdata->pdp_list);
return sdata;
}
struct sgsn_subscriber_pdp_data* sgsn_subscriber_pdp_data_alloc(
struct sgsn_subscriber_data *sdata)
{
struct sgsn_subscriber_pdp_data* pdata;
pdata = talloc_zero(sdata, struct sgsn_subscriber_pdp_data);
llist_add_tail(&pdata->list, &sdata->pdp_list);
return pdata;
}
struct gsm_subscriber *gprs_subscr_get_or_create(const char *imsi)
{
struct gsm_subscriber *subscr;
subscr = subscr_get_or_create(NULL, imsi);
if (!subscr)
return NULL;
if (!subscr->sgsn_data)
subscr->sgsn_data = sgsn_subscriber_data_alloc(subscr);
return subscr;
}
struct gsm_subscriber *gprs_subscr_get_by_imsi(const char *imsi)
{
return subscr_active_by_imsi(NULL, imsi);
}
void gprs_subscr_cleanup(struct gsm_subscriber *subscr)
{
if (subscr->sgsn_data->mm) {
subscr_put(subscr->sgsn_data->mm->subscr);
subscr->sgsn_data->mm->subscr = NULL;
subscr->sgsn_data->mm = NULL;
}
if (subscr->flags & GPRS_SUBSCRIBER_ENABLE_PURGE) {
gprs_subscr_purge(subscr);
subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
}
}
void gprs_subscr_cancel(struct gsm_subscriber *subscr)
{
subscr->authorized = 0;
subscr->flags |= GPRS_SUBSCRIBER_CANCELLED;
subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
gprs_subscr_update(subscr);
gprs_subscr_cleanup(subscr);
}
static int gprs_subscr_tx_gsup_message(struct gsm_subscriber *subscr,
struct gprs_gsup_message *gsup_msg)
{
struct msgb *msg = gprs_gsup_msgb_alloc();
if (strlen(gsup_msg->imsi) == 0 && subscr)
strncpy(gsup_msg->imsi, subscr->imsi, sizeof(gsup_msg->imsi) - 1);
gprs_gsup_encode(msg, gsup_msg);
LOGGSUBSCRP(LOGL_INFO, subscr,
"Sending GSUP, will send: %s\n", msgb_hexdump(msg));
if (!sgsn->gsup_client) {
msgb_free(msg);
return -ENOTSUP;
}
return gprs_gsup_client_send(sgsn->gsup_client, msg);
}
static int gprs_subscr_tx_gsup_error_reply(struct gsm_subscriber *subscr,
struct gprs_gsup_message *gsup_orig,
enum gsm48_gmm_cause cause)
{
struct gprs_gsup_message gsup_reply = {0};
strncpy(gsup_reply.imsi, gsup_orig->imsi, sizeof(gsup_reply.imsi) - 1);
gsup_reply.cause = cause;
gsup_reply.message_type =
GPRS_GSUP_TO_MSGT_ERROR(gsup_orig->message_type);
return gprs_subscr_tx_gsup_message(subscr, &gsup_reply);
}
static int gprs_subscr_handle_gsup_auth_res(struct gsm_subscriber *subscr,
struct gprs_gsup_message *gsup_msg)
{
unsigned idx;
struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
LOGGSUBSCRP(LOGL_INFO, subscr,
"Got SendAuthenticationInfoResult, num_auth_tuples = %zu\n",
gsup_msg->num_auth_tuples);
if (gsup_msg->num_auth_tuples > 0) {
memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
}
for (idx = 0; idx < gsup_msg->num_auth_tuples; idx++) {
size_t key_seq = gsup_msg->auth_tuples[idx].key_seq;
LOGGSUBSCRP(LOGL_DEBUG, subscr,
"Adding auth tuple, cksn = %zu\n", key_seq);
if (key_seq >= ARRAY_SIZE(sdata->auth_triplets)) {
LOGGSUBSCRP(LOGL_NOTICE, subscr,
"Skipping auth triplet with invalid cksn %zu\n",
key_seq);
continue;
}
sdata->auth_triplets[key_seq] = gsup_msg->auth_tuples[idx];
}
sdata->auth_triplets_updated = 1;
sdata->error_cause = SGSN_ERROR_CAUSE_NONE;
gprs_subscr_update_auth_info(subscr);
return 0;
}
static int gprs_subscr_pdp_data_clear(struct gsm_subscriber *subscr)
{
struct sgsn_subscriber_pdp_data *pdp, *pdp2;
int count = 0;
llist_for_each_entry_safe(pdp, pdp2, &subscr->sgsn_data->pdp_list, list) {
llist_del(&pdp->list);
talloc_free(pdp);
count += 1;
}
return count;
}
static struct sgsn_subscriber_pdp_data *gprs_subscr_pdp_data_get_by_id(
struct gsm_subscriber *subscr, unsigned context_id)
{
struct sgsn_subscriber_pdp_data *pdp;
llist_for_each_entry(pdp, &subscr->sgsn_data->pdp_list, list) {
if (pdp->context_id == context_id)
return pdp;
}
return NULL;
}
static void gprs_subscr_gsup_insert_data(struct gsm_subscriber *subscr,
struct gprs_gsup_message *gsup_msg)
{
struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
unsigned idx;
int rc;
if (gsup_msg->msisdn_enc) {
if (gsup_msg->msisdn_enc_len > sizeof(sdata->msisdn)) {
LOGP(DGPRS, LOGL_ERROR, "MSISDN too long (%zu)\n",
gsup_msg->msisdn_enc_len);
sdata->msisdn_len = 0;
} else {
memcpy(sdata->msisdn, gsup_msg->msisdn_enc,
gsup_msg->msisdn_enc_len);
sdata->msisdn_len = gsup_msg->msisdn_enc_len;
}
}
if (gsup_msg->pdp_info_compl) {
rc = gprs_subscr_pdp_data_clear(subscr);
if (rc > 0)
LOGP(DGPRS, LOGL_INFO, "Cleared existing PDP info\n");
}
for (idx = 0; idx < gsup_msg->num_pdp_infos; idx++) {
struct gprs_gsup_pdp_info *pdp_info = &gsup_msg->pdp_infos[idx];
size_t ctx_id = pdp_info->context_id;
struct sgsn_subscriber_pdp_data *pdp_data;
if (pdp_info->apn_enc_len >= sizeof(pdp_data->apn_str)-1) {
LOGGSUBSCRP(LOGL_ERROR, subscr,
"APN too long, context id = %zu, APN = %s\n",
ctx_id, osmo_hexdump(pdp_info->apn_enc,
pdp_info->apn_enc_len));
continue;
}
if (pdp_info->qos_enc_len > sizeof(pdp_data->qos_subscribed)) {
LOGGSUBSCRP(LOGL_ERROR, subscr,
"QoS info too long (%zu)\n",
pdp_info->qos_enc_len);
continue;
}
LOGGSUBSCRP(LOGL_INFO, subscr,
"Will set PDP info, context id = %zu, APN = %s\n",
ctx_id, osmo_hexdump(pdp_info->apn_enc, pdp_info->apn_enc_len));
/* Set PDP info [ctx_id] */
pdp_data = gprs_subscr_pdp_data_get_by_id(subscr, ctx_id);
if (!pdp_data) {
pdp_data = sgsn_subscriber_pdp_data_alloc(subscr->sgsn_data);
pdp_data->context_id = ctx_id;
}
OSMO_ASSERT(pdp_data != NULL);
pdp_data->pdp_type = pdp_info->pdp_type;
gprs_apn_to_str(pdp_data->apn_str,
pdp_info->apn_enc, pdp_info->apn_enc_len);
memcpy(pdp_data->qos_subscribed, pdp_info->qos_enc, pdp_info->qos_enc_len);
pdp_data->qos_subscribed_len = pdp_info->qos_enc_len;
}
}
static int gprs_subscr_handle_gsup_upd_loc_res(struct gsm_subscriber *subscr,
struct gprs_gsup_message *gsup_msg)
{
gprs_subscr_gsup_insert_data(subscr, gsup_msg);
subscr->authorized = 1;
subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
subscr->flags |= GPRS_SUBSCRIBER_ENABLE_PURGE;
gprs_subscr_update(subscr);
return 0;
}
static int check_cause(int cause)
{
switch (cause) {
case GMM_CAUSE_IMSI_UNKNOWN ... GMM_CAUSE_ILLEGAL_ME:
case GMM_CAUSE_GPRS_NOTALLOWED ... GMM_CAUSE_NO_GPRS_PLMN:
return EACCES;
case GMM_CAUSE_MSC_TEMP_NOTREACH ... GMM_CAUSE_CONGESTION:
return EHOSTUNREACH;
case GMM_CAUSE_SEM_INCORR_MSG ... GMM_CAUSE_PROTO_ERR_UNSPEC:
default:
return EINVAL;
}
}
static int gprs_subscr_handle_gsup_auth_err(struct gsm_subscriber *subscr,
struct gprs_gsup_message *gsup_msg)
{
unsigned idx;
struct sgsn_subscriber_data *sdata = subscr->sgsn_data;
int cause_err;
cause_err = check_cause(gsup_msg->cause);
LOGGSUBSCRP(LOGL_DEBUG, subscr,
"Send authentication info has failed with cause %d, "
"handled as: %s\n",
gsup_msg->cause, strerror(cause_err));
switch (cause_err) {
case EACCES:
LOGGSUBSCRP(LOGL_NOTICE, subscr,
"GPRS send auth info req failed, access denied, "
"GMM cause = '%s' (%d)\n",
get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
gsup_msg->cause);
/* Clear auth tuples */
memset(sdata->auth_triplets, 0, sizeof(sdata->auth_triplets));
for (idx = 0; idx < ARRAY_SIZE(sdata->auth_triplets); idx++)
sdata->auth_triplets[idx].key_seq = GSM_KEY_SEQ_INVAL;
subscr->authorized = 0;
sdata->error_cause = gsup_msg->cause;
gprs_subscr_update_auth_info(subscr);
break;
case EHOSTUNREACH:
LOGGSUBSCRP(LOGL_NOTICE, subscr,
"GPRS send auth info req failed, GMM cause = '%s' (%d)\n",
get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
gsup_msg->cause);
sdata->error_cause = gsup_msg->cause;
gprs_subscr_update_auth_info(subscr);
break;
default:
case EINVAL:
LOGGSUBSCRP(LOGL_ERROR, subscr,
"GSUP protocol remote error, GMM cause = '%s' (%d)\n",
get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
gsup_msg->cause);
break;
}
return -gsup_msg->cause;
}
static int gprs_subscr_handle_gsup_upd_loc_err(struct gsm_subscriber *subscr,
struct gprs_gsup_message *gsup_msg)
{
int cause_err;
cause_err = check_cause(gsup_msg->cause);
LOGGSUBSCRP(LOGL_DEBUG, subscr,
"Update location has failed with cause %d, handled as: %s\n",
gsup_msg->cause, strerror(cause_err));
switch (cause_err) {
case EACCES:
LOGGSUBSCRP(LOGL_NOTICE, subscr,
"GPRS update location failed, access denied, "
"GMM cause = '%s' (%d)\n",
get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
gsup_msg->cause);
subscr->authorized = 0;
subscr->sgsn_data->error_cause = gsup_msg->cause;
gprs_subscr_update_auth_info(subscr);
break;
case EHOSTUNREACH:
LOGGSUBSCRP(LOGL_NOTICE, subscr,
"GPRS update location failed, GMM cause = '%s' (%d)\n",
get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
gsup_msg->cause);
subscr->sgsn_data->error_cause = gsup_msg->cause;
gprs_subscr_update_auth_info(subscr);
break;
default:
case EINVAL:
LOGGSUBSCRP(LOGL_ERROR, subscr,
"GSUP protocol remote error, GMM cause = '%s' (%d)\n",
get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
gsup_msg->cause);
break;
}
return -gsup_msg->cause;
}
static int gprs_subscr_handle_gsup_purge_no_subscr(
struct gprs_gsup_message *gsup_msg)
{
if (GPRS_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
LOGGSUPP(LOGL_NOTICE, gsup_msg,
"Purge MS has failed with cause '%s' (%d)\n",
get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
gsup_msg->cause);
return -gsup_msg->cause;
}
LOGGSUPP(LOGL_INFO, gsup_msg, "Completing purge MS\n");
return 0;
}
static int gprs_subscr_handle_gsup_purge_res(struct gsm_subscriber *subscr,
struct gprs_gsup_message *gsup_msg)
{
LOGGSUBSCRP(LOGL_INFO, subscr, "Completing purge MS\n");
/* Force silent cancellation */
subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
gprs_subscr_cancel(subscr);
return 0;
}
static int gprs_subscr_handle_gsup_purge_err(struct gsm_subscriber *subscr,
struct gprs_gsup_message *gsup_msg)
{
LOGGSUBSCRP(LOGL_NOTICE, subscr,
"Purge MS has failed with cause '%s' (%d)\n",
get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
gsup_msg->cause);
/* In GSM 09.02, 19.1.4.4, the text and the SDL diagram imply that
* the subscriber data is not removed if the request has failed. On the
* other hand, keeping the subscriber data in either error case
* (subscriber unknown, syntactical message error, connection error)
* doesn't seem to give any advantage, since the data will be restored
* on the next Attach Request anyway.
* This approach ensures, that the subscriber record will not stick if
* an error happens.
*/
/* TODO: Check whether this behaviour is acceptable and either just
* remove this TODO-notice or change the implementation to not delete
* the subscriber data (eventually resetting the ENABLE_PURGE flag and
* restarting the expiry timer based on the cause).
*
* Subscriber Unknown: cancel subscr
* Temporary network problems: do nothing (handled by timer based retry)
* Message problems (syntax, nyi, ...): cancel subscr (retry won't help)
*/
gprs_subscr_handle_gsup_purge_res(subscr, gsup_msg);
return -gsup_msg->cause;
}
static int gprs_subscr_handle_loc_cancel_req(struct gsm_subscriber *subscr,
struct gprs_gsup_message *gsup_msg)
{
struct gprs_gsup_message gsup_reply = {0};
int is_update_procedure = !gsup_msg->cancel_type ||
gsup_msg->cancel_type == GPRS_GSUP_CANCEL_TYPE_UPDATE;
LOGGSUBSCRP(LOGL_INFO, subscr, "Cancelling MS subscriber (%s)\n",
is_update_procedure ?
"update procedure" : "subscription withdraw");
gsup_reply.message_type = GPRS_GSUP_MSGT_LOCATION_CANCEL_RESULT;
gprs_subscr_tx_gsup_message(subscr, &gsup_reply);
if (is_update_procedure)
subscr->sgsn_data->error_cause = SGSN_ERROR_CAUSE_NONE;
else
/* Since a withdraw cause is not specified, just abort the
* current attachment. The following re-attachment should then
* be rejected with a proper cause value.
*/
subscr->sgsn_data->error_cause = GMM_CAUSE_IMPL_DETACHED;
gprs_subscr_cancel(subscr);
return 0;
}
static int gprs_subscr_handle_unknown_imsi(struct gprs_gsup_message *gsup_msg)
{
if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg->message_type)) {
gprs_subscr_tx_gsup_error_reply(NULL, gsup_msg,
GMM_CAUSE_IMSI_UNKNOWN);
LOGP(DGPRS, LOGL_NOTICE,
"Unknown IMSI %s, discarding GSUP request "
"of type 0x%02x\n",
gsup_msg->imsi, gsup_msg->message_type);
} else if (GPRS_GSUP_IS_MSGT_ERROR(gsup_msg->message_type)) {
LOGP(DGPRS, LOGL_NOTICE,
"Unknown IMSI %s, discarding GSUP error "
"of type 0x%02x, cause '%s' (%d)\n",
gsup_msg->imsi, gsup_msg->message_type,
get_value_string(gsm48_gmm_cause_names, gsup_msg->cause),
gsup_msg->cause);
} else {
LOGP(DGPRS, LOGL_NOTICE,
"Unknown IMSI %s, discarding GSUP response "
"of type 0x%02x\n",
gsup_msg->imsi, gsup_msg->message_type);
}
return -GMM_CAUSE_IMSI_UNKNOWN;
}
int gprs_subscr_rx_gsup_message(struct msgb *msg)
{
uint8_t *data = msgb_l2(msg);
size_t data_len = msgb_l2len(msg);
int rc = 0;
struct gprs_gsup_message gsup_msg = {0};
struct gsm_subscriber *subscr;
rc = gprs_gsup_decode(data, data_len, &gsup_msg);
if (rc < 0) {
LOGP(DGPRS, LOGL_ERROR,
"decoding GSUP message fails with error '%s' (%d)\n",
get_value_string(gsm48_gmm_cause_names, -rc), -rc);
return rc;
}
if (!gsup_msg.imsi[0]) {
LOGP(DGPRS, LOGL_ERROR, "Missing IMSI in GSUP message\n");
if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
gprs_subscr_tx_gsup_error_reply(NULL, &gsup_msg,
GMM_CAUSE_INV_MAND_INFO);
return -GMM_CAUSE_INV_MAND_INFO;
}
if (!gsup_msg.cause && GPRS_GSUP_IS_MSGT_ERROR(gsup_msg.message_type))
gsup_msg.cause = GMM_CAUSE_NET_FAIL;
subscr = gprs_subscr_get_by_imsi(gsup_msg.imsi);
if (!subscr) {
switch (gsup_msg.message_type) {
case GPRS_GSUP_MSGT_PURGE_MS_RESULT:
case GPRS_GSUP_MSGT_PURGE_MS_ERROR:
return gprs_subscr_handle_gsup_purge_no_subscr(&gsup_msg);
default:
return gprs_subscr_handle_unknown_imsi(&gsup_msg);
}
}
LOGGSUBSCRP(LOGL_INFO, subscr,
"Received GSUP message of type 0x%02x\n", gsup_msg.message_type);
switch (gsup_msg.message_type) {
case GPRS_GSUP_MSGT_LOCATION_CANCEL_REQUEST:
rc = gprs_subscr_handle_loc_cancel_req(subscr, &gsup_msg);
break;
case GPRS_GSUP_MSGT_SEND_AUTH_INFO_RESULT:
rc = gprs_subscr_handle_gsup_auth_res(subscr, &gsup_msg);
break;
case GPRS_GSUP_MSGT_SEND_AUTH_INFO_ERROR:
rc = gprs_subscr_handle_gsup_auth_err(subscr, &gsup_msg);
break;
case GPRS_GSUP_MSGT_UPDATE_LOCATION_RESULT:
rc = gprs_subscr_handle_gsup_upd_loc_res(subscr, &gsup_msg);
break;
case GPRS_GSUP_MSGT_UPDATE_LOCATION_ERROR:
rc = gprs_subscr_handle_gsup_upd_loc_err(subscr, &gsup_msg);
break;
case GPRS_GSUP_MSGT_PURGE_MS_ERROR:
rc = gprs_subscr_handle_gsup_purge_err(subscr, &gsup_msg);
break;
case GPRS_GSUP_MSGT_PURGE_MS_RESULT:
rc = gprs_subscr_handle_gsup_purge_res(subscr, &gsup_msg);
break;
case GPRS_GSUP_MSGT_INSERT_DATA_REQUEST:
case GPRS_GSUP_MSGT_DELETE_DATA_REQUEST:
LOGGSUBSCRP(LOGL_ERROR, subscr,
"Rx GSUP message type %d not yet implemented\n",
gsup_msg.message_type);
gprs_subscr_tx_gsup_error_reply(subscr, &gsup_msg,
GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
break;
default:
LOGGSUBSCRP(LOGL_ERROR, subscr,
"Rx GSUP message type %d not valid at SGSN\n",
gsup_msg.message_type);
if (GPRS_GSUP_IS_MSGT_REQUEST(gsup_msg.message_type))
gprs_subscr_tx_gsup_error_reply(
subscr, &gsup_msg, GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL);
rc = -GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL;
break;
};
subscr_put(subscr);
return rc;
}
int gprs_subscr_purge(struct gsm_subscriber *subscr)
{
struct gprs_gsup_message gsup_msg = {0};
LOGGSUBSCRP(LOGL_INFO, subscr, "purging MS subscriber\n");
gsup_msg.message_type = GPRS_GSUP_MSGT_PURGE_MS_REQUEST;
return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
}
int gprs_subscr_query_auth_info(struct gsm_subscriber *subscr)
{
struct gprs_gsup_message gsup_msg = {0};
LOGGSUBSCRP(LOGL_INFO, subscr,
"subscriber auth info is not available\n");
gsup_msg.message_type = GPRS_GSUP_MSGT_SEND_AUTH_INFO_REQUEST;
return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
}
int gprs_subscr_location_update(struct gsm_subscriber *subscr)
{
struct gprs_gsup_message gsup_msg = {0};
LOGGSUBSCRP(LOGL_INFO, subscr,
"subscriber data is not available\n");
gsup_msg.message_type = GPRS_GSUP_MSGT_UPDATE_LOCATION_REQUEST;
return gprs_subscr_tx_gsup_message(subscr, &gsup_msg);
}
void gprs_subscr_update(struct gsm_subscriber *subscr)
{
LOGGSUBSCRP(LOGL_DEBUG, subscr, "Updating subscriber data\n");
subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
if (subscr->sgsn_data->mm)
sgsn_update_subscriber_data(subscr->sgsn_data->mm);
}
void gprs_subscr_update_auth_info(struct gsm_subscriber *subscr)
{
LOGGSUBSCRP(LOGL_DEBUG, subscr,
"Updating subscriber authentication info\n");
subscr->flags &= ~GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
subscr->flags &= ~GSM_SUBSCRIBER_FIRST_CONTACT;
if (subscr->sgsn_data->mm)
sgsn_update_subscriber_data(subscr->sgsn_data->mm);
}
struct gsm_subscriber *gprs_subscr_get_or_create_by_mmctx(struct sgsn_mm_ctx *mmctx)
{
struct gsm_subscriber *subscr = NULL;
if (mmctx->subscr)
return subscr_get(mmctx->subscr);
if (mmctx->imsi[0])
subscr = gprs_subscr_get_by_imsi(mmctx->imsi);
if (!subscr) {
subscr = gprs_subscr_get_or_create(mmctx->imsi);
subscr->flags |= GSM_SUBSCRIBER_FIRST_CONTACT;
subscr->flags &= ~GPRS_SUBSCRIBER_ENABLE_PURGE;
}
if (strcpy(subscr->equipment.imei, mmctx->imei) != 0) {
strncpy(subscr->equipment.imei, mmctx->imei, GSM_IMEI_LENGTH-1);
subscr->equipment.imei[GSM_IMEI_LENGTH-1] = 0;
}
if (subscr->lac != mmctx->ra.lac)
subscr->lac = mmctx->ra.lac;
subscr->sgsn_data->mm = mmctx;
mmctx->subscr = subscr_get(subscr);
return subscr;
}
int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx)
{
struct gsm_subscriber *subscr = NULL;
int rc;
LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber data update\n");
subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
subscr->flags |= GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING;
rc = gprs_subscr_location_update(subscr);
subscr_put(subscr);
return rc;
}
int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx)
{
struct gsm_subscriber *subscr = NULL;
int rc;
LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting subscriber authentication info\n");
subscr = gprs_subscr_get_or_create_by_mmctx(mmctx);
subscr->flags |= GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING;
rc = gprs_subscr_query_auth_info(subscr);
subscr_put(subscr);
return rc;
}

Some files were not shown because too many files have changed in this diff Show More