Compare commits

...

254 Commits

Author SHA1 Message Date
Neels Hofmeyr
6950d14c5b Merge branch 'master' into sysmocom/iu, with tweaks
Numerous manual adjustments are included to make sense on the sysmocom/iu branch:

* gsm_04_08_gprs.h has moved to libosmocore on the master branch, but
  sysmocom/iu has added some entries. Until it is clear whether to move the
  additions to libosmocore as well, keep gsm_04_08_gprs.h on sysmocom/iu with
  merely the additions.
* Thus, keep using the old gsm_04_08_gprs.[hc] from openbsc in the Makefiles,
  but only where the sysmocom/iu additions are needed.
* In openbsc's gsm_04_08_gprs.h,
  * include the libosmocore gsm_04_08_gprs.h,
  * use '#pragma once' instead of #ifndef and
  * add a TODO comment about moving the rest to libosmocore.

* Apply the addition of an osmo_auth_vector to gsm_auth_tuple: in the Iu auth
  vector hacks, use the gsm_auth_tuple.vec instead of a local struct.
  See iu_hack__get_hardcoded_auth_tuple() and gsm48_rx_gmm_att_req().

* In the si2q tests, pass NULL as ctx to gsm_network_init().

* In cscn_main.c, add a debug log that was originally added to osmo-nitb.

* openbsc/.gitignore: keep only one addition of 'writtenconfig'

Conflicts:
	openbsc/include/openbsc/gprs_sgsn.h
	openbsc/include/openbsc/gsm_04_08_gprs.h
	openbsc/src/gprs/gsm_04_08_gprs.c
	openbsc/src/libmsc/gsm_04_08.c
	openbsc/src/osmo-cscn/cscn_main.c
	openbsc/tests/gsm0408/Makefile.am
2016-05-09 00:26:01 +02:00
Daniel Willmann
cf2ca648e9 gprs: Update mm_ctx ra_id from ue_ctx 2016-05-04 19:05:05 +02:00
Daniel Willmann
62ee416d95 libiu: Keep current ra_id in ue_conn_ctx 2016-05-04 19:05:05 +02:00
Daniel Willmann
e42a2ab158 libiu: Also get routing area code if present in InitialUE Message 2016-05-04 19:05:05 +02:00
Daniel Willmann
9336cede84 libiu: Fix memory leaks on receive and transmit
The ranap_handle_* functions generate a msgb and pass it on to the receive
callback. After processing the message the msgb needs to be freed again.

iu_tx() takes a msgb and uses ranap_new_msg_dt() to generate a new msgb from
it. The old msgb needs to be freed.
2016-05-04 19:05:05 +02:00
Daniel Willmann
8c6732909b gprs: Track PMM states
For Iu mode it is important to know when the UE is in PMM-IDLE mode since the
SGSN will need to page the UE if there is data for it.
2016-05-04 19:04:10 +02:00
Neels Hofmeyr
960d28087e IuCS: upon sec mode compl, check that a sec op is pending
Safety check: discard Security Mode Complete messages when there is no
security operation pending.
2016-05-04 16:06:59 +02:00
Neels Hofmeyr
a27b295100 msc: fix: two missing security operation releases
When receiving authentication response or security mode complete messages,
actually release the security operation stored with the subscriber conn.
2016-05-04 16:06:59 +02:00
Neels Hofmeyr
9015d4db52 msc: ignore cb retval on auth/sec mode rx
Just return 0 regardless of the security callback's return value when
receiving authentication response or security mode complete messages.
2016-05-04 16:06:59 +02:00
Neels Hofmeyr
3cda077541 IuCS: properly clean up conn on release
Don't call msc_subscr_con_free() directly, instead use
gsm0408_clear_request(), which properly cleans up all pending operations
before freeing the connection.
2016-05-04 16:06:59 +02:00
Neels Hofmeyr
c3da27fa98 gsm0408_clear_request(): actually free the released conn
By having conn->in_release == 1, calling msc_release_connection() has no
effect and thus never frees the conn. So, after all pending requests have
been discarded, also discard and free the unused connection.
2016-05-04 16:06:59 +02:00
Neels Hofmeyr
bfc190e0fc gsm04_08_clear_request(): release loc with arg release=0
In gsm04_08_clear_request(), in_release == 1 anyway and
msc_release_connection() would exit immediately without any effect. Don't
confuse the reader by passing release=1 arg.
2016-05-04 16:06:59 +02:00
Neels Hofmeyr
f959ad8991 cosmetic: move subscr_conn alloc&free to gsm_04_08.c
Subscriber conn stuff doesn't really belong in gsm_subscriber.c.

(I moved because I thought it would call some static functions in gsm_04_08.c,
which ended up not being the case; anyway, it makes more sense to stay in
gsm_04_08.c.)
2016-05-04 16:04:36 +02:00
Neels Hofmeyr
f3bcdd272b msc subscr: add paging timeout
In NITB, the paging timeout would be handled from the BSC side. In IuCS, we
need to invalidate the paging request from libmsc alone, so add a paging timer
to gsm_subscriber.

Possibly, the HNB-GW should respond with a paging failure and libmsc could
trigger on that, nevertheless libmsc should not rely on a failure message to
expire pending pagings.
2016-05-04 13:23:34 +02:00
Neels Hofmeyr
1d125c902f subscr_paging_dispatch(): add assertions
Make sure that subscr and conn are valid:

* a subscr must always be present.
* on success, a conn must be present and the subscr must match the conn's
  subscr.

Also check the hooknum.
2016-05-04 13:20:11 +02:00
Neels Hofmeyr
35ebbbea7a gitignore dir for python config tests 2016-05-04 13:20:11 +02:00
Neels Hofmeyr
a95927c1de comment tweak 2016-05-04 13:20:11 +02:00
Neels Hofmeyr
03ded61060 debug log for SMS 2016-05-04 13:09:01 +02:00
Neels Hofmeyr
26d0326157 debug log tweaks for paging 2016-05-04 13:09:01 +02:00
Neels Hofmeyr
885a11b33e Revert "subscr_paging_dispatch(): use conn->subscr instead of separate param"
This reverts commit 6f4e83beb0, but note:
this is not a 1:1 revert since the subscr_paging_sec_cb() semantics have changed.

In subscr_paging_dispatch(), the separate subscr parameter is needed in cases
where paging expired and there is no conn available.

For subscr_paging_sec_cb(), a conn must always be available. Hence it avoids
any duplicity by only passing the conn and deriving the subscr from that.

Callers of subscr_paging_sec_cb() pass NULL as param, so pass conn->subscr when
calling subscr_paging_dispatch() from subscr_paging_sec_cb().
2016-05-04 13:05:36 +02:00
Neels Hofmeyr
99f2477653 cosmetic: IuCS logging 2016-05-02 19:51:12 +02:00
Neels Hofmeyr
a9791df3b9 add enum iu_event_type to string conversion 2016-05-02 19:49:58 +02:00
Neels Hofmeyr
d9202b342c comments and debug log for paging response 2016-05-02 17:05:13 +02:00
Neels Hofmeyr
c902bd4032 msc_paging_request(): remove unused parameters
The network is known from subscr; the type is not applicable after MSCSPLIT;
cbfn and data are obsoleted by explicit subscr_rx_paging_response().
2016-05-02 17:03:36 +02:00
Neels Hofmeyr
ad21c3b8e3 msc_paging_request(): make static
it is never called outside of gsm_subscriber.c
2016-05-02 17:03:36 +02:00
Neels Hofmeyr
28fdbdcd53 msc: paging: use gsm_subscriber API to add Integrity Protection for IuCS
During peliminary paging response testing, I introduced some code duplication.
Remove that and instead call the code that was there before 63b99ced83
("add preliminary paging response handling, incomplete").

By calling the gsm_subscriber API, the connection is also secured and hence
Integrity Protection is enabled for IuCS.
2016-05-02 17:03:36 +02:00
Neels Hofmeyr
903ad2e135 cosmetic: msc: handle_paging_resp() tweaks
Tweak debug logging, use paging category DPAG.

Change the order of arguments to make more sense in the causal relationship.
2016-05-02 17:03:36 +02:00
Neels Hofmeyr
04bfcdd6c2 paging: actually verify subscriber authorization
Before this, any paging response would be accepted by the CN, without
checking the database whether the subscriber is in fact authorized.

The probability that a subscriber would be able to take unauthorized action
is slim, nevertheless checking authorization status with the database should
happen before we accept a connection.
2016-05-02 17:03:36 +02:00
Neels Hofmeyr
3a9c52a5dc paging: change subscr_paging_cb() into subscr_rx_paging_response()
Remove one layer of callback indirection in paging. When a paging response
arrives, we always want to first secure the connection, thus a fixed
subscr_rx_paging_response() function is more appropriate and avoids having
to store a cbfn. The actual actions to be taken upon successful paging are
of course still in callback functions stored with each subscriber.
2016-05-02 16:30:10 +02:00
Neels Hofmeyr
c6580c5b2c Allow paging even though is_paging is false
It doesn't really hurt to see whether we have paging responses queued for
a given subscriber. Possibly a subscriber replied with a paging response
later than we assumed the paging to be valid.
2016-05-02 16:30:10 +02:00
Neels Hofmeyr
fb845bb1df cosmetic: subscr_paging_dispatch() comments/indent 2016-05-02 16:30:10 +02:00
Neels Hofmeyr
6f4e83beb0 subscr_paging_dispatch(): use conn->subscr instead of separate param 2016-05-02 16:30:10 +02:00
Neels Hofmeyr
214302b306 cosmetic: subscr_paging_dispatch() comments/indent 2016-05-02 16:30:10 +02:00
Neels Hofmeyr
defe78f1e1 add comments on MSCSPLIT and paging 2016-05-02 16:30:10 +02:00
Neels Hofmeyr
061787878c gsm_04_08 mscsplit: subscr_request_channel() -> subscr_request_conn()
Rename subscr_request_channel() to _conn() and remove the channel_type arg.
The "channel" is a term from closely tied MSC+BSC code, after separation we
shall call it a "connection", i.e. over IuCS or A.

The channel_type arg is already unused from a previous MSCSPLIT commit.
2016-05-02 16:30:10 +02:00
Neels Hofmeyr
00007897d4 gsm_04_08: factor out subscr authorization check
Add function subscr_authorized(), absorbing the guts of static
authorize_subscriber() from gsm_04_08.c, except the parts specific to Location
Updating.

subscr_authorized() is a check that is to be added to validation of a paging
response.
2016-05-02 16:30:10 +02:00
Neels Hofmeyr
5c4386c692 cscn: (re-)add SMPP initialization
Remove legacy code from the original NITB version -- the SMPP init functions
have since been refactored in 1b0e5540db.

Add SMPP initialization in the refactored version: call the alloc_init
before reading config file, and call start with the global network struct
after config is read.
2016-05-02 14:04:11 +02:00
Harald Welte
fc68c83ddb Support raw IPv4 address in RAB Assignment Response
There are different Iu dialects in terms of encoding the
transport layer address inside RAB Assignment req + resp.

Let's be liberal in what we accept, and simply use the length
as an indicator of the format.  Wireshark uses similar heuristics.
2016-05-01 15:35:59 +02:00
Harald Welte
74101106a1 RAB Assignment Response: Handle TEID changes
When the RNC confirms the RAB Assignment, it can each time indicate a
new TEID for the GTP-U endpoint on the RNC side.  We need to update our
information about the PDP context and include that in the UPDATE PDP
CONTEXT that we're sending towards the GGSN.  This is similar to
updating the RNC-side IP address of the GTP endpoint.
2016-05-01 15:35:58 +02:00
Harald Welte
db916bfd8d iu_rab_act_ps: Use GGSN-side TEI in RAB Assignment Requeset
When we send the RAB Assignment Request to the RNC, we need
to tell it the GGSN-side TEI for data, not "our" (SGSN side)
TEID.

In the RAB-Assignment.req we inform the RNC of the TEID on the GGSN
side, and in the RAB-Assignment.resp the RNC informs us of the TEID
on the RNC side.
2016-05-01 15:35:58 +02:00
Harald Welte
a54358879f Identify PDP context by RAB ID, not TEI
When receiving an RAB-Assignment response from the RNC,
we should use the RAB ID (=NSAPI) to resolve the PDP context.

We cannot use the TEID, as the TEID chosen by the RNC for this RAB has
no relationship to the TEID we were using for the RAB-Assignment
request.  TEIDs are local to each of the peer, like UDP port numbers.
2016-05-01 15:35:57 +02:00
Harald Welte
a54b47b048 libiu: Fix missing break statements in switch in cn_ranap_handle_co() 2016-05-01 15:35:56 +02:00
Harald Welte
3b922064a4 SGSN: Use PDP Context NSAPI as RAB ID
As Dieter has pointed out, the RANAP spec requires the RAB ID to be
equal to the NSAPI of the PDP context for which it is established.
2016-05-01 15:35:52 +02:00
Harald Welte
5b3fd465d1 Fix parsing of auto-generated config file
When starting with empty config file, saving it by 'write file',
and then re-starting osmo-cscn, it would complain:

Error occurred during reading below line:
 long name Osmocom Circuit-Switched Core Network

The problem is that the vty parser is configured to expect a single
token and not a list of tokens here, but we initialize the default value
with multiple words (which are treated as separate token).
2016-05-01 15:34:08 +02:00
Neels Hofmeyr
0991c684d3 debug log for paging: add/tweak 2016-04-27 00:15:26 +02:00
Neels Hofmeyr
dc4b14b269 RAB: add debug log for PS RAB assignment 2016-04-25 19:24:30 +02:00
Neels Hofmeyr
687270de3a RAB parameters: apply use_x213_nsap parameter addition
Add use_x213_nsap parameter to iu_rab_act_ps(), pass the new parameter
from two callers as 1 such that there is no functional change.
2016-04-25 19:24:30 +02:00
Neels Hofmeyr
96f88fda06 paging_signal_data: remove unused lac member 2016-04-25 19:24:30 +02:00
Neels Hofmeyr
2ae1f5b7e0 paging response: remove extraneous null check, assert conn and msg further up
In handle_paging_response(), don't check conn against NULL after using it all
the time anyway.

To ensure beyond doubt that it is actually never NULL, assert conn further up
in the call stack, i.e. in gsm0408_dispatch(), the main entry point for
receiving data from the BSC/RNC level. Also assert msg while at it.

Fixes: CID#93769
2016-04-25 19:24:30 +02:00
Neels Hofmeyr
63b99ced83 add preliminary paging response handling, incomplete
In gsm_04_08.c, add a static handle_paging_resp() to take over from the libbsc
function gsm48_handle_paging_resp(). Use the subscr->requests listing to handle
a Paging Response and call the pending cbfn.

In NITB, this used to be done via BTS, and I haven't entirely resolved yet how
exactly to rewire this in standalone libmsc. So far, this "works for me", but
is worth another visit.

Still missing: enable Integrity Protection.
2016-04-20 11:30:14 +02:00
Neels Hofmeyr
0b8e6dd2df gsm_04_08.c: fix security mode cmd: use auth tuple from MM auth 2016-04-20 11:23:00 +02:00
Neels Hofmeyr
9f2eaf8f56 cosmetic: auth tuple memcpy: rather use target's sizeof() 2016-04-20 11:23:00 +02:00
Neels Hofmeyr
afce55a4bc tweak tmp_rand[] type to avoid compiler warnings 2016-04-20 11:23:00 +02:00
Neels Hofmeyr
f3a1ca5d04 gprs_gmm.c: include openssl/rand.h against RAND_bytes() compiler warning 2016-04-20 11:23:00 +02:00
Neels Hofmeyr
c7fcdeb18e IuCS auth: generate auth tuples, factor out
Factor out hardcoded-Ki and auth tuple creation into a static function.

Add generation of fresh random bytes and generate a valid auth tuple so that
the authentication token is different for every MM Auth.
2016-04-20 11:23:00 +02:00
Neels Hofmeyr
3aa8b30bb3 cscn: enable SMS queue (by removing an '#if 0') 2016-04-20 11:22:59 +02:00
Neels Hofmeyr
208250558f cscn: enable 'subscriber' vty commands for libmsc
This involves removing the openbsc_vty_print_statistics() from
vty_interface_layer3.c, as this would link across the MSC/BSC border.
2016-04-20 11:22:59 +02:00
Neels Hofmeyr
bdb3f26668 cn_ranap_handle_co: add error rc and logging for PR Outcome 2016-04-20 11:22:59 +02:00
Neels Hofmeyr
69d3c26e43 cosmetic: debug and error logging, comment tweaks 2016-04-20 11:22:59 +02:00
Neels Hofmeyr
3f18cfce85 cscn: don't redefine talloc_asn1_ctx from iu.c 2016-04-20 11:22:59 +02:00
Neels Hofmeyr
658d1c3e14 IuCS: more detailed debug log upon IuCS rx 2016-04-20 11:22:59 +02:00
Neels Hofmeyr
6d1df9ad96 Add Iu paging
Add iu_page_cs() and iu_page_ps() API, also add to libiudummy for linking in
tests.

Implement msc_paging_request() by calling iu_page_cs().
2016-04-20 11:22:59 +02:00
Neels Hofmeyr
9bc1ddc849 iu.c: add registry of RNC-Ids in LACs
Introduce struct gsm_rnc, stored in a global list, static to iu.c.
(This list is not part of gsm_network so that the code can be
used from both MSC and GPRS code, i.e. both for CS and PS.)

Parse RANAP Global RNC Id, add GSM flags to build for gsm48_mcc_mnc_from_bcd()
to decode the PLMN Id.

Upon every Initial UE message, record/verify RNC Id and LAC for that
connection. In case of mismatch, so far just log an error.
2016-04-20 11:22:59 +02:00
Neels Hofmeyr
90e2c751e9 iu.c: introduce talloc_iu_ctx
Introduce talloc_iu_ctx, setup during iu_init() as child of the talloc_ctx
passed in by the caller.

Allocate ue_conn_ctx from talloc_iu_ctx, used to be from NULL.

Allocate osmo_sua_user and talloc_asn1_ctx from talloc_iu_ctx, used to be from
the ctx passed in by iu_init() caller.
2016-04-19 22:51:38 +02:00
Neels Hofmeyr
15f6c9f1e8 cosmetic: comment, whitespace 2016-04-19 22:27:32 +02:00
Neels Hofmeyr
5d5a25bc5a iu.h: add iu_link_del() 2016-04-19 22:24:47 +02:00
Neels Hofmeyr
95c9f29634 Iu RANAP event: add IU_EVENT_LINK_INVALIDATED
See in-code comment...
2016-04-19 22:11:39 +02:00
Daniel Willmann
30753e4a28 libmsc: Pass KeyStatus to iu_tx_sec_mode_cmd 2016-04-19 20:05:55 +02:00
Daniel Willmann
8fe0feb21b gprs: Activate RABs from RoutingArea update request as well 2016-04-19 20:05:18 +02:00
Daniel Willmann
444a516f18 gprs: Keep track of key negotiation and set the key status flag in sec_mod_cmd 2016-04-19 20:04:00 +02:00
Daniel Willmann
0f3bce4aef gprs: Change auth key for every new Iu connection 2016-04-12 12:11:59 +02:00
Neels Hofmeyr
edafdc14f3 cscn: record and use LAC on incoming InitialUE msg
Add lac argument to gsm0408_rcvmsg_iucs(), to record the LAC in newly
allocated gsm_subscriber_connections.

In effect, fix the LAC sent to UE during Location Updating Accept message.
Before, 0 was stored as LAC and sent to the UE, regardless of the actual
LAC in use.
2016-04-11 20:45:32 +02:00
Neels Hofmeyr
54fc3a1318 remove subscr_conn_allocate_iu() from public header
It is only used statically in iu.c
2016-04-11 20:37:12 +02:00
Neels Hofmeyr
baefda5d64 add osmo-cscn.cfg example
Include a cscn section with subscriber-create-on-demand even though that is
the default.
2016-04-11 20:37:12 +02:00
Neels Hofmeyr
8dfe9690c5 iu.c: check return value of ranap_parse_lai() 2016-04-11 20:37:12 +02:00
Daniel Willmann
fafb074268 sgsn: Reset mm ctx state in service request and after authorization 2016-04-08 18:04:04 +02:00
Daniel Willmann
a3dfdcb308 sgsn: Don't send the pdp context accept every time the RAB activates 2016-04-08 18:04:04 +02:00
Daniel Willmann
bae2594424 gprs: Save integrity protection status inside ue ctx, not mm ctx 2016-04-08 18:04:04 +02:00
Daniel Willmann
5e007d9445 gprs: Use different RAB IDs for activation 2016-04-08 12:14:56 +02:00
Daniel Willmann
42024336fe sgsn: Pass RAB ID to iu_rab_act_ps() function 2016-04-08 12:11:35 +02:00
Neels Hofmeyr
bb81326719 vty l3 help: fix typo 'comamnds'; fix english s/his// 2016-04-05 12:06:35 +02:00
Neels Hofmeyr
276192d27c cosmetic: comments, debug log, msgb alloc name 2016-03-31 16:15:18 +02:00
Neels Hofmeyr
c4b9b4edbb mscsplit: rewire MSC gsm0808_submit_dtap() to msc_tx_dtap() 2016-03-31 16:15:18 +02:00
Neels Hofmeyr
b70dfa610d Merge branch 'master' into sysmocom/iu
Conflicts:
	openbsc/src/libmsc/auth.c
	openbsc/src/libmsc/gsm_04_08.c
	openbsc/src/osmo-bsc/osmo_bsc_vty.c
	openbsc/tests/Makefile.am
2016-03-31 16:14:13 +02:00
Neels Hofmeyr
4b940126a3 comments about incomplete MM ciphering 2016-03-22 19:55:45 +01:00
Neels Hofmeyr
debb0e3868 cscn: implement integrity protection
Upon authentication response, initiate integrity protection for Iu by sending a
Security Mode Command (IK), with hardcoded auth tuple so far.

Implement RANAP event handling to receive Security Mode Complete message,
adding stubs for the other events; in new files osmo-cscn/iucs_ranap.[hc] to
keep RANAP dependencies separate, and particularly out of libmsc.

Upon receiving Security Mode Complete, call the security operation callback
(conn->sec_operation->cb) to complete the Location Update.

Introduce enum integrity_protection_state constants to indicate integrity
protection, record in gsm_subscriber_conn.iu.integrity_protection.

Make subscr_conn_lookup_iu() non-static and declare in iu_cs.h to be able to
call from iucs_ranap.c's Security Mode Complete event.

Implement dummy iu_tx_sec_mode_cmd() to allow tests to build without RANAP
dependencies.

In cscn_main.c, call iucs_rx_ranap_event(), to populate the struct gsm_network
struct with cscn_network explicitly (don't share cscn_network across
compilation scopes because it's ugly).
2016-03-22 19:54:09 +01:00
Neels Hofmeyr
d025a3cfbb in gsm8_rx_mm_auth_resp(): call sec_operation.cb() instead of finish_lu() directly 2016-03-22 19:53:36 +01:00
Neels Hofmeyr
4b3b13e10c fix various compiler warnings
sgsn_libgtp.c: missing include, for asn1str_to_u32()

iu_cs.c: missing include, for subscr_name()

osmo_bsc_vty.c: int/pointer conversions
(note: this was discussed on the list to be solved by passing a pointer
instead. Until then...)

iudummy.c: opaque struct declarations
2016-03-22 19:28:06 +01:00
Neels Hofmeyr
fa48a98e71 gsm0408_authorize(): remove unused msgb arg, make non-static
Prepares for calling from IuCS RANAP events.
2016-03-22 01:13:07 +01:00
Neels Hofmeyr
9fd87ecd11 iu_tx_sec_mode_cmd(): add send_ck flag parameter
In this way the caller can distinguish between sending an IK or an IK+CK
Security Mode Command.
2016-03-22 01:13:07 +01:00
Neels Hofmeyr
8e5c63f032 cosmetic: whitespace, comment, rename static func rx_iu_event() 2016-03-22 01:12:26 +01:00
Neels Hofmeyr
2cd36e87ae fix build: match Iu event cb enum argument type from declaration 2016-03-22 01:07:20 +01:00
Neels Hofmeyr
0bc6c11cbf debug log fixes
gprs_gmm.c: remove extraneous debug print arg.
iu_cs.c: increment should not be in debug statement.

Fixes at least one coverity warning.
2016-03-21 11:56:28 +01:00
Neels Hofmeyr
182adecb98 debug: log list of subscribers upon lookup 2016-03-18 15:57:42 +01:00
Neels Hofmeyr
3d0a500f2d iu.c: log conn_id on outgoing messages 2016-03-18 15:57:42 +01:00
Neels Hofmeyr
a5c9cea22c logging: add DSUA to default_categories[] 2016-03-18 15:57:42 +01:00
Neels Hofmeyr
f45dc35321 logging: add DRANAP to default_categories 2016-03-18 15:57:42 +01:00
Neels Hofmeyr
2f6c4b6479 IuCS: fix logical flip in same_ue_conn() 2016-03-18 15:57:42 +01:00
Neels Hofmeyr
2385074cba fix build: iu.h: remove iu_rab_act_ps()'s rab_id parameter
Error was introduced in d04db9d907
'libiu: Replace RAB assignment response callback with a general one'

For iu_rab_act_ps(), the rab_id parameter was added in iu.h but not in the
implementation, nor for the callers. Make the iu.h signature match the
implementation, again.
2016-03-18 15:57:42 +01:00
Daniel Willmann
d8b0b61ca8 gprs_gmm: Call gsm48_gmm_authorize from RA upd request
In Iu mode the RA upd request can be called from a new Iu connection so we
might need to reauthenticate the connection as well as turn on integrity
protection.
2016-03-18 14:08:14 +01:00
Daniel Willmann
19f0735752 cscn: Follow libiu move to generic event handler 2016-03-18 14:00:03 +01:00
Daniel Willmann
ffd9968d3a libiu: Change gprs_transp_upd_key to be useful for CS as well
gprs_transp_upd_key only sends a security mode command which is needed for CS
as well so change it.

Make sure it is called after the UE is authenticated in Iu mode.
2016-03-18 13:58:20 +01:00
Daniel Willmann
deb227b98e gprs_gmm: Fix RA UPD handling for IU mode 2016-03-16 18:39:52 +01:00
Daniel Willmann
5e611021b0 Move event callback to gprs_gmm 2016-03-16 18:38:58 +01:00
Daniel Willmann
d04db9d907 libiu: Replace RAB assignment response callback with a general one
The new iu event callback will now be called for RAB assignment response, IU
release and security mode complete
2016-03-16 10:35:09 +01:00
Neels Hofmeyr
3c94c2c597 bsc_scan_msc_msg: check protocol discriminator
The function assumed an MM protocol discriminator without verifying it.
2016-03-15 13:14:56 +01:00
Neels Hofmeyr
372a3bd346 04.08: apply new transaction id inline functions
libosmocore recently added inline functions to relieve callers from applying
bitmasks and bit shifts to access the transaction id of a GSM 04.08 header.
Apply these functions.
2016-03-15 13:14:19 +01:00
Neels Hofmeyr
51bf76ef47 04.08: apply new bitmask functions, fix bitmask use
Replace hardcoded protocol discriminator and message type bitmasks with
function calls recently introduced in libosmocore.

Note that the release 98 bitmasks slightly differ from the release 99 bitmasks.
This patch uses the "default" gsm48_hdr_msg_type invocation, thus it depends on
libosmocore whether 98 or 99 bitmasks are used.

In some places, use of the bitmask was erratic. Fix these implicitly by
employing the bitmask functions:

 * silent_call.c: silent_call_reroute(): add missing bitmask for MM.
 * bsc_msg_filter.c: bsc_msg_filter_initial(): RR vs. MM messages.
 * osmo_bsc_filter.c: bsc_find_msc() and bsc_scan_bts_msg(): RR vs. MM
   messages.
 * bsc_nat_rewrite.c: bsc_nat_rewrite_msg(): SMS vs. CC messages.
 * bsc_ussd.c: no bitmask is applicable for the message types used here.
 * gb_proxy.c: gbproxy_imsi_acquisition(): missing bit mask for pdisc.

In gprs_gb_parse.c: gprs_gb_parse_dtap(), add a log notice for unexpected
message types.
2016-03-15 13:14:17 +01:00
Neels Hofmeyr
aa60582036 cosmetic: comments 2016-03-15 13:13:15 +01:00
Neels Hofmeyr
6b2623d944 cscn: fix VTY port: don't use SGSN's port number 2016-03-14 23:58:23 +01:00
Neels Hofmeyr
8b1272a6d3 msc: allow only authentication without ciphering
So far the code did only auth+ciph or none. Add case handling for only
authentication without ciphering (basically just fill in the blanks).
2016-03-14 23:58:23 +01:00
Neels Hofmeyr
080921a551 HACK: hardcode subscriber auth tuple for IuCS 2016-03-14 23:58:23 +01:00
Neels Hofmeyr
8e7f4c6f21 cosmetic 2016-03-14 23:58:23 +01:00
Neels Hofmeyr
4a9b871de5 Adjust authentication logic for Iu, move a log notice
Depending on conn->via_iface, fail upon missing auth for 3G.

Move the log notice saying "skipping auth" to gsm48_secure_channel() where
conn->via_iface is actually known.
2016-03-14 23:58:23 +01:00
Neels Hofmeyr
93f6fa5a81 spread a few debug logs around authentication 2016-03-14 23:58:23 +01:00
Neels Hofmeyr
f1777ee843 fix confusing typo in constant (THAN -> THEN) 2016-03-14 23:58:23 +01:00
Neels Hofmeyr
9e8e0e6a29 Remove unused auth code and add comment
As commented in the code, the GSM_SECURITY_AUTH_FAILED path is never invoked by
the gsm48_secure_channel() function as it is today.

Note that the upcoming Iu auth will probably add a GSM_SECURITY_AUTH_FAILED
status. In that case, sending a LU Reject immediately may be desirable, but
arguably a bit of timeout could make life harder for auth attackers.

The code removed by this patch doesn't send out a LU Reject ever, since a call
to release_loc_updating_req() only releases the connection. To reject, a call
to gsm0408_loc_upd_rej() would be necessary, as seen in loc_upd_rej_cb().

And finally, if _gsm0408_authorize_sec_cb() doesn't do anything about anything,
the same loc_upd_rej_cb() will be run by a timeout and send a LU Reject
properly (as commented in the code).
2016-03-14 23:58:23 +01:00
Neels Hofmeyr
cf3d2a1fad fix build: add xsc to osmo-bsc and tests/bsc-nat 2016-03-04 15:36:59 +01:00
Neels Hofmeyr
e4baf402cb move two gsm0480_send_*() to xsc as gsm0480_gen_*()
Have two separate gsm0480_send_ussdNotify() and gsm0480_send_releaseComplete()
for each of libbsc and libmsc. Move their core into libxsc as generator
functions returning a msgb.

Add src/libbsc/gsm_04_80_utils.c (note, not 04_08) to implement the libbsc
side of it.

The code is identical, but the linked structs and functions differ in each
case. There could be a common source file built for both, but I decided against
it, for more clarity I hope.
2016-03-04 15:34:18 +01:00
Neels Hofmeyr
53d782fc38 fix two minor Makefile.am errors 2016-03-04 15:27:48 +01:00
Neels Hofmeyr
33a343858d move sms_next_rp_msg_ref() to libxsc, for gsm0408test
Also change the signature to avoid using gsm_subscriber_connection, which
has different members in libbsc and libmsc.
2016-03-04 14:58:09 +01:00
Neels Hofmeyr
15b1fce69c rename nitb vty config to cscn, move to cscn_vty.c 2016-03-04 14:58:09 +01:00
Neels Hofmeyr
2f8117d214 disable code trying to reach across BSC/MSC bounds, make build pass
Disable ipacc_rtp_direct, Osmo SMPP TLVs, Ctrl interface and channel_test.
These need to be reimplemented with proper separation of libs.

Add some tall_* pointers the linker requires for osmo-cscn.
2016-03-04 14:58:09 +01:00
Neels Hofmeyr
8927bb46d5 libmsc: stubify paging (A-/Iu-interfaces need to reimplement this) 2016-03-04 14:57:59 +01:00
Neels Hofmeyr
d52b1c4342 add libmsc/a_iface.c for A-interface stubs (so far only mock) 2016-03-04 14:57:09 +01:00
Neels Hofmeyr
5d9004bc9b gsm_subscriber_connection: further split between BSC and MSC
Move some Iu/A members into the MSC #ifdef.

Have separate allocate and free functions for the two scopes.
2016-03-04 14:57:09 +01:00
Neels Hofmeyr
a4198d1922 create libxsc and move some code, never link libbsc and libmsc
libbsc and libmsc have conflicting definitions of gsm_subscriber_connection
and do no longer belong together anyway.

Create libxsc, meaning 'lib[bm]sc', to hold all code used by both libmsc
and libbsc, and make sure gsm_subscriber_connection isn't used there.

In various binaries and tests, do not link libbsc and libmsc.

(Note: this commit was reshaped out of a large wip chunk, it may not
compile properly without the subsequent commits)
2016-03-04 14:57:09 +01:00
Neels Hofmeyr
544a203f67 Remove osmo-nitb, cannot link libbsc with libmsc anymore 2016-03-03 16:19:12 +01:00
Neels Hofmeyr
b40df4c09e cscn: apply vty bind addr configuration 2016-03-03 16:19:12 +01:00
Neels Hofmeyr
5c1c0bad89 debug: set almost everything to LOGL_DEBUG for easier dev 2016-03-03 16:19:12 +01:00
Neels Hofmeyr
1e361301d1 cscn_main.c: fix ctrl init
Include control_vty.h so that ctrl_vty_get_bind_addr() is properly declared.
Add ctrl iface vty commands.
2016-03-03 16:19:12 +01:00
Neels Hofmeyr
9e8322ca0c wip: exclude more bsc stuff from gsm_subscriber_conn 2016-03-03 16:19:12 +01:00
Neels Hofmeyr
9bd121b75b cscn: minor dbg log tweak 2016-03-03 16:19:12 +01:00
Neels Hofmeyr
fa029f08c2 cscn: apply socket path / bind addr changes after rebase
After rebasing onto 1b0e5540db, some changes need to be applied to
cscn_main.c, originally a copy of bsc_hack.c before the rebase. On master,
configurable MNCC socket path and Control interface bind address were added.
2016-03-03 16:19:12 +01:00
Neels Hofmeyr
db9c064dd4 osmo-bsc: half-fix tz override to allow compilation
As described in a comment, for MSCSPLIT the tz data has been moved to network
level. To allow compiling osmo-bsc on the sysmocom-iu branch, move tz up to
network level in osmo-bsc as well.

This could be done better for osmo-bsc, rather easily too, still allowing
per-BTS timezone settings. But I'm trying to focus on IuCS and would like to
come back to this later.
2016-03-03 16:19:12 +01:00
Daniel Willmann
a0da2dbe9e WIP: gprs_gmm: Get mm ctx from RA update in Iu mode
Iu mode doesn't have tlli, so look up according to p-tmsi
2016-03-03 16:19:12 +01:00
Daniel Willmann
7df5705251 WIP: Try and activate RABs after service request 2016-03-03 16:19:12 +01:00
Daniel Willmann
da7424cc54 gprs_gmm: Log service request if not receieved from Iu mode 2016-03-03 16:19:11 +01:00
Daniel Willmann
8146cfa782 gprs_gmm: Send gmm_service_accept from gsm48_gmm_authorize() 2016-03-03 16:19:11 +01:00
Daniel Willmann
330898afb7 gprs: Update ue ctx from msg
In case a Iu connection is reconnected we need to update the ue ctx
2016-03-03 16:19:11 +01:00
Daniel Willmann
77544a65b5 sgsn_test: Fix mmctx llme and tlli struct names after merge 2016-03-03 16:19:11 +01:00
Daniel Willmann
4e5ddfa91a gprs_gmm: Fix mmctx tlli member rename after merge 2016-03-03 16:19:11 +01:00
Daniel Willmann
cba441f3de gprs: Handle GMM service request (Iu mode only)
Iu mode has a GMM service request message which a UE in PMM-IDLE mode
can use to switch back to PMM-CONNECTED mode.
2016-03-03 16:19:11 +01:00
Daniel Willmann
3acbc817f6 osmo-bsc: Pass gsmnet to bsc_vty_init() 2016-03-03 16:19:11 +01:00
Neels Hofmeyr
bcb98b1754 libmsc/smpp: disable lchan access for now
To make the IuCS build work, disable the BSC-land access from MSC's SMPP code.
Some way shall be found to make the Osmocom vendor-specific SMPP TLVs work over
the A-interface (after the MSCSPLIT), but we're concentrating on IuCS for now.
2016-03-03 16:19:11 +01:00
Daniel Willmann
2a7426d7cb libmsc: Don't use bts field of gsm_subscriber_connection
Use gsm_subscriber_connection does not have a bts field if building as
libmsc. Use network directly.
2016-03-03 16:19:11 +01:00
Daniel Willmann
b9bb2a4f54 sgsn: fix use of opaque RANAP_RAB_SetupOrModifiedItemIEs_s decl 2016-03-03 16:19:11 +01:00
Neels Hofmeyr
098c14800f cscn: fix use of opaque RANAP_RAB_SetupOrModifiedItemIEs_s decl 2016-03-03 16:19:11 +01:00
Neels Hofmeyr
a46c651a4a iu.h: fix opaque declaration of RANAP_RAB_SetupOrModifiedItemIEs_s
struct RANAP_RAB_SetupOrModifiedItemIEs_s; may be declared, but not the
corresponding typedef. It leads to a redefinition error in our coverity
build.
2016-03-03 16:19:11 +01:00
Daniel Willmann
4cc1f72cb7 Revert "iu.c: avoid warning by declaring ranap_free_rab_setupormodifieditemies()"
There should be no need to silence this warning, the ranap_free_*
functions are declared in libranap headers. In any case this will only
obscure any real issue. Maybe osmo-iuh was not rebuilt completely
(including generation of the c files from the python script).

This reverts commit 05ae5b1245f95bf765b42e49af7b2596e013f0a0.
2016-03-03 16:19:11 +01:00
Daniel Willmann
4f143e52b6 libiu: Use custom setupormodifieditemies function
The one generated by the python script doesn't really do what we want.
Instead of futzing around with the script again just write our own
version.
2016-03-03 16:19:11 +01:00
Daniel Willmann
e3407f8884 libiu: Indicate in log where we don't handle a specific message 2016-03-03 16:19:11 +01:00
Daniel Willmann
7d1b6b1c79 libui: Don't assume gsm_network and gsm_subscriber_conncetion in libiu
The sgsn uses other data structs so don't require them inside libiu.
Instead keep a private list of ue contexts and iterate through that.

This commit reverts the libui changes of commit
d03faa4bacd4d2a8b9155faf5219a948b73f481c
2016-03-03 16:19:11 +01:00
Neels Hofmeyr
656d7cd0b4 iu.c: avoid warning by declaring ranap_free_rab_setupormodifieditemies() 2016-03-03 16:19:11 +01:00
Neels Hofmeyr
553d2a8ceb add tests/libiudummy 2016-03-03 16:19:11 +01:00
Neels Hofmeyr
23f22b1183 msc: define extern iu_tx() 2016-03-03 16:19:11 +01:00
Neels Hofmeyr
090aabe052 gsm0408_rcvmsg_iucs: remove unused link_id arg. 2016-03-03 16:19:11 +01:00
Neels Hofmeyr
be37fbd85d msc: implicitly link to iu_tx, don't have callbacks.
This is more akin to the way openbsc do, as well as less code.
2016-03-03 16:19:11 +01:00
Daniel Willmann
3cc0836b1a gprs/sgsn: Use RAB assignment response cb in PDP context activation 2016-03-03 16:19:11 +01:00
Daniel Willmann
8cd32937da osmo-cscn: Add dummy function for RAB assignment response 2016-03-03 16:19:11 +01:00
Daniel Willmann
377a9f5dea libiu: Add support for RAB assignment response callback 2016-03-03 16:19:11 +01:00
Daniel Willmann
b8df4d5318 sgsn_libgtp: Update rab (de)act function names to libui version 2016-03-03 16:19:11 +01:00
Daniel Willmann
daa0652d3f sgsn_test: Make sgsn_test compile again after libui change 2016-03-03 16:19:11 +01:00
Daniel Willmann
f7436b22b3 sgsn_iu/libgtp: Update pdp context with new IP address after RAB assign
In the IU case the RNC and ggsn communicate directly on the user plane.
Since the IP address of the RNC is not known in our case (it sits behind
the hnbgw) we need to update the PDP context with the new IP address
after receiving the RAB assignment response (which includes the IP
address).
2016-03-03 16:19:11 +01:00
Daniel Willmann
711333c113 sgsn_iu: Parse the RAB assignemnt response and get pdp ctx form it
The RAB assignment response includes the gtp teid that we sent along in
the assignment request. Retrieve the correct pdp context from there and
activate it.
2016-03-03 16:19:10 +01:00
Daniel Willmann
91f04dfe3a sgsn: Add a function to return the pdp ctx for an mm ctx and tei 2016-03-03 16:19:10 +01:00
Daniel Willmann
4371ff8cce sgsn: Get gtp ip and teid from pdp context in gprs_iu_rab_act() 2016-03-03 16:19:10 +01:00
Daniel Willmann
92223cc32e gprs_gmm: Apply the auth hack only for UTRAN_Iu RAN type
Try to limit the effect 3G support has on the remaining code base. The
sgsn test still fails, but at a later test.
2016-03-03 16:19:10 +01:00
Daniel Willmann
2f5cc8abe0 tests/sgsn: Fix compilation of sgsn_test
The sgsn test still fails, but at least it is compiling again..
2016-03-03 16:19:10 +01:00
Daniel Willmann
ba47b525ff sgsn_libgtp: Use the address provided by the GGSN for RAB activation 2016-03-03 16:19:10 +01:00
Daniel Willmann
cf1707af7f gprs: Fix some misleading comments 2016-03-03 16:19:10 +01:00
Daniel Willmann
d6d0d8b86f WIP: Wait for radio bearer before sending pdp context accept 2016-03-03 16:19:10 +01:00
Daniel Willmann
38137e84f7 HACK: ranap_decode_rab_setupormodifieditemies crashes so disable it 2016-03-03 16:19:10 +01:00
Daniel Willmann
82724653e7 sgsn_iu: RABAssignment response is an Outcome, not a Successful one 2016-03-03 16:19:10 +01:00
Daniel Willmann
da8d9bc355 gprs_gmm: Fix bit mask when determining update/attach type
Bit 4 is reserved in 3GPP TS 04.08 so exclude it from the type.

In 3GPP TS 24.008 it indicates if a follow-on request is pending by the
MS, but only in Iu mode. According to the spec it is not required to
react to that request with a follow-on proceed so this field can be
ignored for now.

See 3GPP TS 24.008 Ch. 4.4:
"Unless it has specific permission from the network (follow-on proceed)
the mobile station side should await the release of the RR connection
used for a MM specific procedure before a new MM specific procedure or
MM connection establishment is started."

as well as Ch. 4.4.4.6:
"If the network wishes to prolong the RR connection to allow the mobile
station to initiate MM connection establishment (for example if the
mobile station has indicated in the LOCATION UPDATING REQUEST that it
has a follow-on request pending) the network shall send "follow on
proceed" in the LOCATION UPDATING ACCEPT and start timer T3255."
2016-03-03 16:19:10 +01:00
Neels Hofmeyr
c59e52a6aa doc: rename nitb graph to bsc, add msc graph
NITB is already gone from this branch. We may even resurrect it, but I prefer
to name the realms 'libmsc' and 'libbsc', hence the nitb graph is the BSC graph
now. Also add a libmsc graph.
2016-03-03 16:19:10 +01:00
Neels Hofmeyr
24c4af1d82 doc: add lists to nitb graph 2016-03-03 16:19:10 +01:00
Neels Hofmeyr
f918920d65 cscn: use iu_tx for msc_ifaces.iu_cs. some #include cosmetics. 2016-03-03 16:19:10 +01:00
Neels Hofmeyr
292f1ce533 mscsplit: fix compilation and comments. move msc_api.h. 2016-03-03 16:19:10 +01:00
Neels Hofmeyr
23e7f28c5c mscsplit: getting grips on header scopes 2016-03-03 16:19:10 +01:00
Neels Hofmeyr
243c7cb044 msc: clarify msc_api and msc_ifaces scopes 2016-03-03 16:19:10 +01:00
Neels Hofmeyr
cf2591f6fc rename IFACE_IUCS to IFACE_IU 2016-03-03 16:19:10 +01:00
Neels Hofmeyr
6a2d8985bf cscn: rename msc_api 2016-03-03 16:19:10 +01:00
Neels Hofmeyr
c6794eed1d cscn: some file moves/renames 2016-03-03 16:19:10 +01:00
Neels Hofmeyr
7a70a4f52a cscn wip: direct dtap responses to IuCS 2016-03-03 16:19:10 +01:00
Neels Hofmeyr
c6172a320b cscn: fix missing network backpointer 2016-03-03 16:19:10 +01:00
Neels Hofmeyr
5280ed558c cscn: own talloc root and gsm_network instance; misc.
Heading towards a sovereign CSCN.
2016-03-03 16:19:10 +01:00
Neels Hofmeyr
b36b910366 mscsplit: exclude some more vty nodes 2016-03-03 16:19:10 +01:00
Neels Hofmeyr
b47e52c958 cosmetic: remove unused extern. 2016-03-03 16:19:10 +01:00
Neels Hofmeyr
267f6c7e0d introduce vty CSCN_NODE, cosmetically. 2016-03-03 16:19:10 +01:00
Neels Hofmeyr
5e47b1a1d3 mscplit: try to clarify root talloc ctx and global gsm_network.
The aim is to allow osmo-cscn to pass its own root talloc context and
global gsm_network struct instance cleanly. This may stir up some old and
dusty globals, but I hope it's for the better, since not all is a BSC.

To ensure that a global gsm_network pointer for the bsc_vty is set, have it as
argument to bsc_vty_init(). The vty configuration commands are added only after
bsc_vty_init(), which are needed to configure the network struct. So split up
the bsc_bootstrap_network() function into bsc_network_init() to allocate a
gsm_struct, and bsc_network_configure() to read the config file once the vty
commands are in place. In this way, no global bsc_gsmnet pointer is needed for
the bsc vty. The atomic super glue is dissolved and osmo-cscn will be allowed
to have a different name for it.

Admitted, it's still called the bsc_vty, but a split thereof is probably coming
soon, because the CSCN doesn't want any of the BSC nor BTS specific vty
commands.
2016-03-03 16:19:09 +01:00
Neels Hofmeyr
b9e5403ef4 mscsplit: remove bts and lchan pointers from libmsc
The diff between this and master will probably need a lot of review and fixes.
The current state does compile, but I expect pretty much everything to be
broken now. Future development will reinstate proper functionality piecemeal.

The first goal is to get basic signalling to work, then SMS. The voice control
(RTP) is completely disabled now (see "#if BEFORE_MSCSPLIT") and will be fixed
last AFAICT.
2016-03-03 16:19:09 +01:00
Neels Hofmeyr
b6769b99de cosmetics: link_id=42, s/Iu-CS/IuCS, debug logs.
Until I get the proper link id from the SUA SAP, make sure we recognise it
as hardcoded by setting it to 42.
2016-03-03 16:19:09 +01:00
Neels Hofmeyr
39daffd7a5 cscn: allocate IuCS conn, properly return rc. 2016-03-03 16:19:09 +01:00
Neels Hofmeyr
71d1e17e5e cscn: call msc_compl_l3() from subscr_conn_allocate_iu()
Pubish msc_compl_l3() decl in new file libmsc/msc_api.h (but see comment).

Call msc_compl_l3() when establishing a subscriber connection for IuCS.

Remove bts from subscr_conn_allocate_iu() signature, use network, link_id and
conn_id instead.

Move subscr_conn_allocate_iu() to the top of the file, because it semantically
belongs before subscr_conn_lookup_iu().
2016-03-03 16:19:09 +01:00
Neels Hofmeyr
2c9e65051c cscn: default to osmo-cscn.cfg, not opencscn.cfg 2016-03-03 16:19:09 +01:00
Neels Hofmeyr
a2ce4aa615 cscn: move gsm0408_rcvmsg_iucs() decl to proper place.
Add noinst-header iu_cs.h and move the gsm0408_rcvmsg_iucs() declaration
there.
2016-03-03 16:19:09 +01:00
Neels Hofmeyr
ee1541d504 put Iu-common and Iu-CS stuff in proper places
Add libiu to contain the parts used by both Iu-CS (in osmo-cscn) and Iu-PS (in
gprs) into libiu. It's rather thin and may make sense to move to osmo-iuh
altogether, eventually.

iu.c is half moved to libiu/, and half to osmo-cscn/iu_cs.c.
2016-03-03 16:19:09 +01:00
Neels Hofmeyr
9dcae17866 wip 2016-03-03 16:19:09 +01:00
Neels Hofmeyr
c2c5176328 todo / #if 0 2016-03-03 16:19:09 +01:00
Neels Hofmeyr
a2c182df6d minor fixes 2016-03-03 16:19:09 +01:00
Neels Hofmeyr
070f673b12 func declaration, comments 2016-03-03 16:19:09 +01:00
Neels Hofmeyr
e2a10dbe35 fix: it's called msgb.dst. 2016-03-03 16:19:09 +01:00
Neels Hofmeyr
bf30ec26e5 wip 2016-03-03 16:19:09 +01:00
Neels Hofmeyr
dcbc852125 Indicate A-interface for new A subscr-conn. 2016-03-03 16:19:09 +01:00
Neels Hofmeyr
48e091ea2b Add some Iu-CS functions (in the wrong place though, wip) 2016-03-03 16:19:09 +01:00
Neels Hofmeyr
712074cb17 cosmetic: a rename, comments.
Rename conn_ctx_list -> ue_conn_ctx_list.
Indicate Iu-CS 'siblings' for a couple of functions.
Tweak/add comments.
2016-03-03 16:19:09 +01:00
Neels Hofmeyr
a34aedf7f9 Add Iu-CS indicator to struct gsm_subscriber_connection.
Introduce enum interface_type and gsm_subscriber_connection.via_iface to
distinguish between A-interface and Iu-CS-interface connections.

Add gsm_subscriber_connection.iu.link_id and iu.conn_id.
2016-03-03 16:19:09 +01:00
Neels Hofmeyr
2e5c13129d log level: DIUCS = debug 2016-03-03 16:19:09 +01:00
Neels Hofmeyr
da5b3fcd32 wip (reminders to self, whitespace) 2016-03-03 16:19:09 +01:00
Neels Hofmeyr
5291ee5c16 make osmo-cscn compile and receive first Iu-CS buf (and log it only) 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
5773987881 iu_init: add addr and port args 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
836b904e77 add DIUCS debug id 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
444d50b77f various small fixes 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
b3b8ccfa54 sai arg back to pointer 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
231aa60ce4 some fixes 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
8b713f817d generalize rab_act for ps and cs 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
ce3b41fdb6 move struct ue_conn_ctx to header 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
0f93bb80e4 sgsn_iu -> iu 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
477a054c2c sai arg 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
52ddce4378 iu_common 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
2945fd4611 rename sgsn_iu.c to iu.c.
That code seems to be usable for the CS side, as well. A more general name
is applicable. todo: move out of gprs even.
2016-03-03 16:19:08 +01:00
Neels Hofmeyr
2449c0ce58 tweak ..rcvmsg_iu()'s sai arg.
It was a uint16_t*, but is passed as a uint16_t, and never used anyway, yet.
2016-03-03 16:19:08 +01:00
Neels Hofmeyr
5d145b5477 iu_common wip 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
45b13244f0 gitignore 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
cb91aa7e6c cscn 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
7ef6d9893f asn_debug 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
6aeee0a0d9 cosmetic 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
17d061bd8e typo 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
ef3548c0a1 wip 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
add0953692 cscn: adjust header comment. 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
ca3977c8fe Add osmo-cscn, as a copy of osmo-nitb.
CSCN means "Circuit Switched Core Network" (-in-the-box) and will become a
NITB-without-BSC, so that it talks Iu-cs to the HNBGW and talks 'A' to an
external BSC.

Copying NITB is debatable: on the one hand, we've agreed on the name Osmo-CSCN
for the end result (without internal BSC). On the other hand, I will probably
add Iu-cs into the NITB code incrementally, in such a way that theoretically,
both Iu-cs and the internal BSC functionality could be used at the same time.
So Osmo-CSCN will be a NITB plus Iu-cs for a while. Instead of adding to NITB,
I prefer to work on a copy, so that the original NITB remains more or less
unchanged.

Only a later step will clearly distinguish CSCN from NITB: when the BSC part is
split off for the benefit of a proper A-interface, and CSCN talks to an
external BSC.
2016-03-03 16:19:08 +01:00
Neels Hofmeyr
a234287d09 doc: add call graphs from MSC to BSC or HNB-GW (wip) 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
8440c9f04b disable some sgsn_tests to pass the status quo.
while working on this, I need to see whether I break any more things.
So remove some noise temporarily.
2016-03-03 16:19:08 +01:00
Neels Hofmeyr
2cb732aeb9 sgsn_test build 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
a7551e033e sgsn_test: apply addition of gb member 2016-03-03 16:19:08 +01:00
Neels Hofmeyr
08ed1d73f2 fix sgsn_mm_ctx_cleanup_free: TLLI unass. after sgsn_mm_ctx_free.
The comment says so and it was moved above sgsn_mm_ctx_free in a commit
marked as ugly hack.
2016-03-03 16:19:07 +01:00
Neels Hofmeyr
af9bfac58d fix ranap_handle_co_dt, failed to pass struct pointer 2016-03-03 16:19:07 +01:00
Harald Welte
ac9951e54a gsm_04_08.c: Don't set msg->lchan nor msg->dst
the BSC-side of the API behind gsm0808_submit_dtap() is doing
this resolving again anyway.  So let's avoid doing it twice, and avoid
having more dependency of the MSC down into the lchan details.
2016-03-03 16:19:07 +01:00
Harald Welte
75cdeaf1e3 gsm_04_11.c/04_08.c: s/lchan/conn/ where we don't use lchan for years 2016-03-03 16:19:07 +01:00
Harald Welte
41f8f047bc remove dead code from Makefile.am 2016-03-03 16:19:07 +01:00
Harald Welte
195d2dc724 migrate WIP osmo-iuh hack to use system-installed libosm-ranap.so
this means we no longer try to link to hard-coded files outside of the
openbsc.git repository.
2016-03-03 16:19:07 +01:00
Harald Welte
315abfd46b WIP: Really ugly hacks to get up to (and including) PDP CTX ACT 2016-03-03 16:19:07 +01:00
Harald Welte
648b9db47f add sgsn_iu.c that was missed in large WIP commit 2016-03-03 16:19:07 +01:00
Harald Welte
8291623054 rtp_proxy.c: Ensure msgb_alloc is large enough for largest AMR frame
In AMR 12.2 (mode 7), the actual RTP payload is 33 bytes.  Howeerver,
as we store the length of the (dynamically-sized) AMR payload in the
first byte, our buffer needs at least 33+1 byte in size.
2016-03-03 16:19:07 +01:00
Harald Welte
5331cf8dbd subscr_name(): Handle case for subscr == NULL
subscr_name() was called from several places:
* either without a check for subscr being NULL, which for example
  was causing a segfault if we hand-over a channel before identifying the
  subscriber
* or with an explicit NULL check and the ternary operator (?).

We now simplify the code by checking for the NULL Subscriber in subscr_name()
itself.
2016-03-03 16:19:07 +01:00
Harald Welte
cf8e56cd1e WIP 2016-03-03 16:19:07 +01:00
Harald Welte
e157174447 gprs_gmm.c: Preform LLME operations only if we have one
In case the GMM message did not arrive over a Gb interface, there is no
LLME (and thus the associated pointer is NULL).  Don't try to perform
operations on a NULL LLME.
2016-03-03 16:19:07 +01:00
Harald Welte
493534bf56 gprs_gmm.c: Make TLLI handling specific to Gb interface
Soem of the operations we perform in the GMM layer are specific to the
GPRS/EDGE radio access network and its Gb interface.  Let's make them
conditional to that in preparation of supporting an Iu interface.
2016-03-03 16:19:07 +01:00
Harald Welte
342f59d92e gprs_gmm.c: Don't try to de-reference NULL mmctx
There was a comment in the code that certain GMM messages require a
valid mmctx pointer.  However, nothing actually checked if that pointer
was in fact non-NULL.  We plainly crashed if a MS would send us the
wrong message in the wrong state.
2016-03-03 16:19:07 +01:00
Harald Welte
aefb0c45e9 rename gsm0408_gprs_rcvmsg() to gsm0408_gprs_rcvmsg_gb()
This is the entry point for GMM from Gb.  We will create a new one
for Iu, so let's be explicit rather than implicit.
2016-03-03 16:19:07 +01:00
Harald Welte
692f31446e prepare sgsn_mm_ctx for Gb and Iu mode (UMTS)
Let's explicitly mark those sgsn_mm_ctx members that apply for Gb mode
and (upcoming) Iu mode, respectively.
2016-03-03 16:19:07 +01:00
Neels Hofmeyr
2cde90e904 Fix two rc values in gsm0408_dispatch()
I do hope the unimplemented/unknown messages did not return 0 intentionally.
2016-03-03 16:19:07 +01:00
Neels Hofmeyr
f6672ab8b0 move subscriber conns list into struct gsm_network.
Replace the global sub_connections llist with gsm_network.subscr_conns.
Initialize and apply where applicable. Remove bsc_api_sub_connections().
2016-03-03 16:19:07 +01:00
118 changed files with 5203 additions and 1724 deletions

2
openbsc/.gitignore vendored
View File

@@ -55,6 +55,7 @@ src/gprs/osmo-sgsn
src/gprs/osmo-gbproxy
src/gprs/osmo-gtphub
src/osmo-bsc_nat/osmo-bsc_nat
src/osmo-cscn/osmo-cscn
#tests
tests/testsuite.dir
@@ -88,7 +89,6 @@ tests/package.m4
tests/testsuite
tests/testsuite.log
src/openbsc.cfg*
writtenconfig/
gtphub_restart_count

View File

@@ -28,6 +28,9 @@ 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)
PKG_CHECK_MODULES(LIBCRYPTO, libcrypto >= 0.9.5)
PKG_CHECK_MODULES(LIBASN1C, libasn1c)
PKG_CHECK_MODULES(LIBOSMORANAP, libosmo-ranap)
PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran)
# Enabke/disable the NAT?
AC_ARG_ENABLE([nat], [AS_HELP_STRING([--enable-nat], [Build the BSC NAT. Requires SCCP])],
@@ -47,7 +50,7 @@ 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?
# Enable/disable smpp support in the cscn?
AC_ARG_ENABLE([smpp], [AS_HELP_STRING([--enable-smpp], [Build the SMPP interface])],
[osmo_ac_build_smpp="$enableval"],[osmo_ac_build_smpp="no"])
if test "$osmo_ac_build_smpp" = "yes" ; then
@@ -191,7 +194,9 @@ AC_OUTPUT(
src/libmgcp/Makefile
src/libcommon/Makefile
src/libfilter/Makefile
src/osmo-nitb/Makefile
src/libiu/Makefile
src/libxsc/Makefile
src/osmo-cscn/Makefile
src/osmo-bsc/Makefile
src/osmo-bsc_nat/Makefile
src/osmo-bsc_mgcp/Makefile
@@ -200,6 +205,7 @@ AC_OUTPUT(
src/gprs/Makefile
tests/Makefile
tests/atlocal
tests/libiudummy/Makefile
tests/gsm0408/Makefile
tests/db/Makefile
tests/channel/Makefile

View File

@@ -0,0 +1,608 @@
gprs_iu_tx
-- WORK IN PROGRESS --
This is an incomplete collection of call graphs between MSC and Osmo-BSC,
partly including Osmo-BTS. These traces helped understanding the separation of
the BSC part from Osmo-NITB. The aim: obtain a clearly separated "A" interface
towards the BSC, and have an Iu-CS interface to operate with HNB-GW and hNodeB.
The working title for the result is Osmo-CSCN (Circuit Switched Core Network),
combining an MSC with various other core network components, but without the
BSC parts.
Some Specs and Overview
0408: Radio interface
0411: PP-SMS on Radio interface
0802: A Interface MSC<->BSS (BSS = BSC + BTS)
0804: A Interface L1 MSC<->BSS
0806: A Interface L2 MSC<->BSS
0808: A Interface L3 MSC<->BSS
0808: Figure 1: A MSC<->BSS
0820: RA (Rate Adaption) MSC<->BSS
0851,0852: A-bis general BSC<->BTS
1221: A-bis NM BSC<->BTS
1201: Figure 9: A-bis BSC<->BTS
MS <-> BTS <-> BSC <-> MSC <-> cn
| | | | |
|<-------0408=DTAP----->| |
|<-------0411---------->| |
| | |<--0808>| |
| | |<BSSMAP>| |
| | | | |
| Abis | A |
MS <-> hNodeB <-> HNB-GW <-> MSC <-> cn
| | | | |
|<-0408->|<--Iu--->|<-Iu-cs->| |
|<-0411->| | | |
| | | | |
Entry/Exit points
Osmo-BSC <--A--> MSC or Osmo-CSCN
format: BSSAP/SCCP (where BSSAP = DTAP + BSSMAP)
Osmo-BSC
read from MSC: sccp_system_incoming_ctx()
write to MSC: sccp_connection_write() <-- osmo-bsc/osmo_bsc_sccp.c:bsc_queue_for_msc()
MSC:
third party
Osmo-CSCN:
read: does not exist yet
write: does not exist yet
HNB-GW <--Iu-CS--> Osmo-CSCN
format: CC+MM/RANAP/SUA
HNB-GW:
read: does not exist yet
write: does not exist yet
Osmo-CSCN:
read: does not exist yet
write: does not exist yet
Osmo-BTS <-Abis-> Osmo-BSC
Osmo-BSC:
read: libbsc/abis_rsl.c:abis_rsl_rcvmsg(msg)
write: libosmo-abis/src/e1_input.c:abis_sendmsg() (e1inp_sign_link*)msg->dst;
Osmo-BTS <-Abis-> Osmo-NITB
Osmo-NITB:
read:
osmo_signal_dispatch():
from on_dso_load_token() libmsc/token_auth.c
SS_SUBSCR: token_subscr_cb() libmsc/token_auth.c
SS_SMS: token_sms_cb() libmsc/token_auth.c
from subscr_sig_cb() libmsc/rrlp.c
SS_SUBSCR: subscr_sig_cb() libmsc/rrlp.c
SS_PAGING: paging_sig_cb() libmsc/rrlp.c
from on_dso_load_ho_dec() libbsc/handover_decision.c
SS_LCHAN: ho_dec_sig_cb() libbsc/handover_decision.c
from e1inp_init() libosmo-abis/src/e1_input.c
SS_L_GLOBAL: e1i_sig_cb() libosmo-abis/src/e1_input.c
bts_model_bs11_init();
bts_model_rbs2k_init();
bts_model_nanobts_init();
bts_model_nokia_site_init();
bts_model_sysmobts_init();
bsc_bootstrap_network():
osmo_signal_register_handler(SS_NM, nm_sig_cb, NULL);
osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL);
Call Trees
- A Interface
Osmo-BSC sends to MSC:
sccp_connection_write(conn->sccp, msg);
^ bsc_queue_for_msc()
^
| osmo-bsc/osmo_bsc_api.c:
| bsc_clear_request()
| queue_msg_or_return() osmo-bsc/osmo_bsc_api.c
| ^ bsc_sapi_n_reject()
| | ^send_sapi_reject()
| | ^ gsm0808_submit_dtap() libbsc/bsc_api.c
| | | ^ gsm48_conn_sendmsg() libmsc/gsm_04_08.c
| | | | ^ gsm48_cc_tx_notify_ss() libmsc/gsm_04_08.c
| | | | | mm_tx_identity_req() libmsc/gsm_04_08.c
| | | | | gsm48_tx_mm_info() libmsc/gsm_04_08.c
| | | | | gsm48_tx_mm_auth_req()
| | | | | gsm48_send_rr_app_info()
| | | | | gsm48_cc_tx_status()
| | | | | gsm48_tx_simple()
| | | | | ^ gsm48_tx_mm_auth_rej()
| | | | | gsm48_cc_tx_setup()
| | | | | gsm48_cc_tx_call_proc()
| | | | | gsm48_cc_tx_alerting()
| | | | | gsm48_cc_tx_progress()
| | | | | gsm48_cc_tx_connect()
| | | | | gsm48_cc_tx_connect_ack()
| | | | | gsm48_cc_tx_disconnect()
| | | | | gsm48_cc_tx_release()
| | | | | gsm48_cc_tx_release_compl()
| | | | | gsm48_cc_tx_facility()
| | | | | gsm48_cc_tx_hold_ack()
| | | | | gsm48_cc_tx_hold_rej()
| | | | | gsm48_cc_tx_retrieve_ack()
| | | | | gsm48_cc_tx_retrieve_rej()
| | | | | gsm48_cc_tx_start_dtmf_ack()
| | | | | gsm48_cc_tx_start_dtmf_rej()
| | | | | gsm48_cc_tx_stop_dtmf_ack()
| | | | | gsm48_cc_tx_modify()
| | | | | gsm48_cc_tx_modify_complete()
| | | | | gsm48_cc_tx_modify_reject()
| | | | | gsm48_cc_tx_notify()
| | | | | gsm48_cc_tx_userinfo()
| | | |
| | | | gsm0480_send_ussd_response() libmsc/gsm_04_80.c
| | | | gsm0480_send_ussd_reject() libmsc/gsm_04_80.c
| | | | gsm0480_send_ussdNotify() libmsc/gsm_04_80.c
| | | | ^ bsc_send_ussd_no_srv() osmo-bsc/osmo_bsc_api.c
| | | | gsm0480_send_releaseComplete() libmsc/gsm_04_80.c
| | | | ^ bsc_send_ussd_no_srv() osmo-bsc/osmo_bsc_api.c
| | | |
| | | | gsm411_sendmsg() libmsc/gsm_04_11.c
| | | |
| | | | bsc_maybe_lu_reject() osmo-bsc/osmo_bsc_api.c
| | | | ^ complete_layer3()
| | | | | bsc_dtap()
| | | |
| | | | dtap_rcvmsg() osmo-bsc/osmo_bsc_bssap.c
| | | |
| | | | gsm48_tx_mm_serv_ack() libbsc/gsm_04_08_utils.c
| | | | ^ _gsm48_rx_mm_serv_req_sec_cb()
| | | | | bsc_send_ussd_no_srv() osmo-bsc/osmo_bsc_api.c
| | | |
| | | | gsm48_tx_mm_serv_rej() libbsc/gsm_04_08_utils.c
| | |
| | | bsc_rll_req.cb = rll_ind_cb() from rll_establish() from gsm0808_submit_dtap()
| | | ^ complete_rllr() libbsc/bsc_rll.c
| | | | ^ timer_cb() libbsc/bsc_rll.c
| | | | | rll_indication() libbsc/bsc_rll.c
| | | | | rll_lchan_signal() libbsc/bsc_rll.c
| |
| | bsc_cipher_mode_compl()
| | ^ bsc_api.cipher_mode_compl()
| | | dispatch_dtap() (2)
| | | with GSM48_MT_RR_CIPH_M_COMPL
| |
| | bsc_dtap()
| | ^ cb from osmo-bsc/osmo_bsc_api.c
| | bsc_api.dtap()
| | ^ libbsc/bsc_api.c:
| | | dispatch_dtap() (2)
| | | case GSM48_MT_RR_APP_INFO
| | | case unknown 04.08 RR
| |
| | bsc_assign_compl()
| | ^ osmo-bsc/osmo_bsc_api.c
| | bsc_api.assign_compl()
| | ^ libbsc/bsc_api.c:
| | | dispatch_dtap() (2)
| | | case GSM48_MT_RR_CHAN_MODE_MODIF_ACK
| | | handle_ass_compl()
| | | ^ dispatch_dtap() (2)
| | | | case GSM48_MT_RR_ASS_COMPL
| |
| | bsc_assign_fail()
| |
| | bsc_cm_update()
|
| osmo-bsc/osmo_bsc_bssap.c:
| bssmap_handle_clear_command()
| bssmap_handle_cipher_mode()
| bssmap_handle_assignm_req()
|
Osmo-BSC receives from MSC:
sccp_system_incoming_ctx() (libosmo-sccp)
| L2 type:
v SCCP_MSG_TYPE_CR: _sccp_handle_connection_request(msgb, ctx);
SCCP_MSG_TYPE_RLSD: _sccp_handle_connection_released(msgb);
SCCP_MSG_TYPE_CREF: _sccp_handle_connection_refused(msgb);
SCCP_MSG_TYPE_CC: _sccp_handle_connection_confirm(msgb);
SCCP_MSG_TYPE_RLC: _sccp_handle_connection_release_complete(msgb);
SCCP_MSG_TYPE_DT1: _sccp_handle_connection_dt1(msgb);
Note: a dt1 target entry was created during one of:
- bsc_open_connection() (SCCP connections are established by the BSC, exclusively)
sccp_connection_connect()
_sccp_send_connection_request()
llist_add_tail(&connection->list, &sccp_connections);
- sccp_system_incoming_ctx()
SCCP_MSG_TYPE_CR:
_sccp_handle_connection_request(struct msgb *msgb, void *ctx)
cb->accept_cb() = msc_sccp_accept()
SCCP_MSG_TYPE_UDT: _sccp_handle_read(msgb) --read_cb--> osmo-bsc/osmo_bsc_sccp.c:msc_sccp_read()
msc_sccp_read()
| bsc_handle_udt() ./openbsc/openbsc/src/osmo-bsc/osmo_bsc_bssap.c:494
v bssmap_rcvmsg_udt() ./openbsc/openbsc/src/osmo-bsc/osmo_bsc_bssap.c:387
gsm0808_bssmap_name() ./libosmocore/src/gsm/gsm0808.c:535
bssmap_handle_reset_ack() ./openbsc/openbsc/src/osmo-bsc/osmo_bsc_bssap.c:91
LOGP()
bssmap_handle_paging() ./openbsc/openbsc/src/osmo-bsc/osmo_bsc_bssap.c:99
GSM0808_IE_IMSI
GSM0808_IE_CELL_IDENTIFIER_LIST
GSM0808_IE_TMSI
CELL_IDENT_LAC
CELL_IDENT_BSS
GSM0808_IE_CHANNEL_NEEDED
GSM0808_IE_EMLPP_PRIORITY
subscr_get_or_create() ./openbsc/openbsc/src/libcommon/gsm_subscriber_base.c:101
subscr_group
LOGL_INFO
bsc_grace_paging_request() ./openbsc/openbsc/src/osmo-bsc/osmo_bsc_grace.c:87
normal_paging() ./openbsc/openbsc/src/osmo-bsc/osmo_bsc_grace.c:37
if (msc->core_lac != -1)
paging_request_bts() ./openbsc/openbsc/src/libbsc/paging.c:307
trx_is_usable() ./openbsc/openbsc/src/libbsc/chan_alloc.c:49
if is_ipaccess_bts() and nm_is_running(): 0
else: 1
paging_init_if_needed() ./openbsc/openbsc/src/libbsc/paging.c:224
LAUNCH TIMER:
bts->paging.work_timer.cb = paging_worker;
paging_worker() ./openbsc/openbsc/src/libbsc/paging.c:217
paging_handle_pending_requests() ./openbsc/openbsc/src/libbsc/paging.c:169 (R):
paging_give_credit() ./openbsc/openbsc/src/libbsc/paging.c:107 (R):
recurse paging_handle_pending_requests()
can_send_pag_req() ./openbsc/openbsc/src/libbsc/paging.c:116
page_ms() ./openbsc/openbsc/src/libbsc/paging.c:69
gsm0808_page() ./openbsc/openbsc/src/libbsc/bsc_api.c:415
rsl_paging_cmd() ./openbsc/openbsc/src/libbsc/abis_rsl.c:751
abis_rsl_dchan_hdr
RSL_MT_PAGING_CMD
RSL_CHAN_PCH_AGCH
init_dchan_hdr() ./openbsc/openbsc/src/libbsc/abis_rsl.c:99
mdisc_by_msgtype() ./openbsc/openbsc/src/libbsc/abis_rsl.c:80
ABIS_RSL_MDISC_RLL
ABIS_RSL_MDISC_TRX
ABIS_RSL_MDISC_COM_CHAN
ABIS_RSL_MDISC_DED_CHAN
ABIS_RSL_MDISC_LOC
RSL_IE_CHAN_NR
RSL_IE_PAGING_GROUP
RSL_IE_MS_IDENTITY
RSL_IE_CHAN_NEEDED
abis_rsl_sendmsg() ./libosmo-abis/src/e1_input.c:258
_paging_request() ./openbsc/openbsc/src/libbsc/paging.c:279
llist_add_tail(&req->entry, &bts_entry->pending_requests);
paging_schedule_if_needed() ./openbsc/openbsc/src/libbsc/paging.c:96
if (msc->core_lac == -1)
paging_request()
gsm_bts_by_lac() ./openbsc/openbsc/src/libcommon/gsm_data.c:135
paging_request_bts() ./openbsc/openbsc/src/libbsc/paging.c:307
(see above)
if err
paging_request_stop()
(see below)
locked_paging() ./openbsc/openbsc/src/osmo-bsc/osmo_bsc_grace.c:54
paging_request_bts() ./openbsc/openbsc/src/libbsc/paging.c:307
(see above)
- A-bis Interface
Osmo-BSC to BTS:
abis_sendmsg()
^
| libosmo-abis/src/e1_input.c:abis_rsl_sendmsg()
| ^
| | libbsc/abis_rsl.c: 23 callers
| | rsl_bcch_info()
| | rsl_sacch_filling()
| | rsl_sacch_info_modify()
| | rsl_chan_bs_power_ctrl()
| | rsl_chan_ms_power_ctrl()
| | rsl_chan_activate_lchan()
| | rsl_chan_mode_modify_req()
| | rsl_encryption_cmd()
| | rsl_deact_sacch()
| | rsl_rf_chan_release()
| | rsl_paging_cmd()
| | rsl_imm_assign_cmd()
| | rsl_siemens_mrpci()
| | rsl_data_request()
| | rsl_establish_request()
| | rsl_release_request()
| | rsl_ipacc_crcx()
| | rsl_ipacc_mdcx()
| | rsl_ipacc_pdch_activate()
| | rsl_sms_cb_command()
| | rsl_nokia_si_begin()
| | rsl_nokia_si_end()
| | rsl_bs_power_control()
|
| libbsc/bts_nokia_site.c:nokia_abis_nm_queue_send_next()
|
| libbsc/abis_nm.c:_abis_nm_sendmsg()
| ^ abis_nm_sendmsg()
| | abis_nm_sendmsg_direct()
|
| osmo-bts/src/common/abis.c:abis_oml_sendmsg()
| osmo-bts/src/common/abis.c:abis_bts_rsl_sendmsg()
libbsc/e1_config.c:bts_isdn_e1inp_line_ops.sign_link =
libbsc/e1_config.c:bts_isdn_sign_link(struct msgb *msg)
case E1INP_SIGN_RSL:
libbsc/abis_rsl.c:abis_rsl_rcvmsg(msg) (1)
case E1INP_SIGN_OML:
ret = bts->model->oml_rcvmsg(msg);
libbsc/bts_ipaccess_nanobts.c:ipaccess_e1inp_line_ops.sign_link =
ipaccess_sign_link(struct msgb *msg)
case E1INP_SIGN_RSL:
libbsc/abis_rsl.c:abis_rsl_rcvmsg(msg) (1)
case E1INP_SIGN_OML:
libbsc/abis_nm.c:abis_nm_rcvmsg(msg);
(1)
libbsc/abis_rsl.c:abis_rsl_rcvmsg(msg)
case ABIS_RSL_MDISC_RLL:
libbsc/abis_rsl.c:abis_rsl_rx_rll(msg)
case DATA_IND, EST_IND:
libbsc/bsc_api.c:gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id)
msg->lchan->ts->trx->bts->network->bsc_api;
if (lchan->conn)
libbsc/bsc_api.c:dispatch_dtap() (2)
else
lchan->conn = subscr_con_allocate(msg->lchan);
rc = api->compl_l3(lchan->conn, msg, 0); (3)
case ABIS_RSL_MDISC_DED_CHAN:
rc = abis_rsl_rx_dchan(msg);
case ABIS_RSL_MDISC_COM_CHAN:
rc = abis_rsl_rx_cchan(msg);
case ABIS_RSL_MDISC_TRX:
rc = abis_rsl_rx_trx(msg);
case ABIS_RSL_MDISC_IPACCESS:
rc = abis_rsl_rx_ipacc(msg);
break;
case ABIS_RSL_MDISC_LOC:
LOGP(DRSL, LOGL_NOTICE, "unimplemented RSL msg disc 0x%02x\n",
(2)
libbsc/bsc_api.c:dispatch_dtap()
struct bsc_api *api = msg->lchan->ts->trx->bts->network->bsc_api;
default:
if (api->dtap)
api->dtap(conn, link_id, msg); (5)
case GSM48_PDISC_RR:
case GSM48_MT_RR_HANDO_COMPL:
handle_rr_ho_compl(msg);
case GSM48_MT_RR_HANDO_FAIL:
handle_rr_ho_fail(msg);
case GSM48_MT_RR_CIPH_M_COMPL:
if (api->cipher_mode_compl)
api->cipher_mode_compl(conn, msg, (4)
conn->lchan->encr.alg_id);
case GSM48_MT_RR_ASS_COMPL:
handle_ass_compl(conn, msg);
case GSM48_MT_RR_ASS_FAIL:
handle_ass_fail(conn, msg);
case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
rc = gsm48_rx_rr_modif_ack(msg);
if (rc < 0) {
api->assign_fail(conn, GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE)
else
api->assign_compl()
case GSM48_MT_RR_CLSM_CHG:
handle_classmark_chg(conn, msg);
case GSM48_MT_RR_APP_INFO:
if (api->dtap)
api->dtap(conn, link_id, msg); (5)
default:
if (api->dtap)
api->dtap(conn, link_id, msg); (5)
case GSM48_MT_RR_GPRS_SUSP_REQ:
DEBUGP(DRR, "GRPS SUSPEND REQUEST\n");
case GSM48_MT_RR_STATUS:
LOGP(DRR, LOGL_NOTICE, "RR STATUS (cause: %s)\n",
case GSM48_MT_RR_MEAS_REP:
LOGP(DMEAS, LOGL_ERROR, "DIRECT GSM48 MEASUREMENT REPORT ?!? ");
(3)[0]
msc_bsc_api().compl_l3 =
libmsc/osmo_msc.c: msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg,
libmsc/gsm0408.c: gsm0408_dispatch() (6)
(3)[1]
osmo_bsc_api().compl_l3 =
osmo-bsc/osmo_bsc_api.c:bsc_compl_l3()
msc = bsc_find_msc(conn, msg);
complete_layer3(conn, msg, msc)
bsc_filter_initial(msc->network->bsc_data, msc, conn, msg,
&imsi, &con_type, &lu_cause);
bsc_create_new_connection(conn, msc, send_ping);
sccp->state_cb = msc_outgoing_sccp_state()
sccp->data_cb = msc_outgoing_sccp_data()
bsc_con->send_ping = send_ping()
bsc_con->sccp_it_timeout.cb = sccp_it_timeout()
bsc_con->sccp_cc_timeout.cb = sccp_cc_timeout()
bsc_scan_bts_msg(conn, msg); (7)
resp = gsm0808_create_layer3(msg, network_code, country_code, lac, ci);
(5)[0]
msc_bsc_api().dtap =
libmsc/osmo_msc.c: msc_dtap(conn, link_id, msg)
gsm0408_dispatch(conn, msg) (6)
(5)[1]
osmo_bsc_api().dtap =
osmo-bsc/osmo_bsc_api.c: bsc_dtap(conn, link_id, msg)
if (handle_cc_setup(conn, msg) >= 1) return;
if (bsc_filter_data(conn, msg, &lu_cause) < 0)
bsc_maybe_lu_reject()
return;
bsc_scan_bts_msg(conn, msg); (7)
resp = gsm0808_create_dtap(msg, link_id);
queue_msg_or_return(resp);
(7)
bsc_scan_bts_msg() <osmo-bsc/osmo_bsc_filter.c:212>:
if GSM48_PDISC_MM, GSM48_MT_MM_LOC_UPD_REQUEST
handle_lu_request() <osmo-bsc/osmo_bsc_filter.c:29>:
gsm48_generate_lai()
if GSM48_PDISC_RR, GSM48_MT_RR_PAG_RESP
handle_page_resp() <osmo-bsc/osmo_bsc_filter.c:97>:
extract_sub() <osmo-bsc/osmo_bsc_filter.c:57>
paging_request_stop() <libbsc/paging.c:390>:
log_set_context()
_paging_request_stop() <libbsc/paging.c:359>:
paging_init_if_needed() <libbsc/paging.c:224>:
paging_worker() <libbsc/paging.c:217>:
paging_handle_pending_requests() <libbsc/paging.c:169> (R):
cb()
paging_give_credit() <libbsc/paging.c:107> (R):
paging_handle_pending_requests() <libbsc/paging.c:169> (recursive: see 37)
can_send_pag_req() <libbsc/paging.c:116>:
page_ms() <libbsc/paging.c:69>:
gsm0808_page() <libbsc/bsc_api.c:415>:
rsl_paging_cmd() <libbsc/abis_rsl.c:751>:
abis_rsl_dchan_hdr = RSL_IE_CHAN_NR
mdisc_by_msgtype() <libbsc/abis_rsl.c:80>:
ABIS_RSL_MDISC_RLL
ABIS_RSL_MDISC_TRX
ABIS_RSL_MDISC_COM_CHAN
ABIS_RSL_MDISC_DED_CHAN
ABIS_RSL_MDISC_LOC
msgb_tv_put(msg, RSL_IE_PAGING_GROUP, paging_group);
msgb_tlv_put(msg, RSL_IE_MS_IDENTITY, len-2, ms_ident+2);
msgb_tv_put(msg, RSL_IE_CHAN_NEEDED, chan_needed);
rsl_link
abis_rsl_sendmsg()
cbfn() (8)
paging_remove_request() <libbsc/paging.c:60>:
subscr_put() <libcommon/gsm_subscriber_base.c:89>
subscr_put() <libcommon/gsm_subscriber_base.c:89>
(8)[0]
libmsc/gsm_04_08.c:mncc_tx_to_cc()
req->cbfn =
libmsc/gsm_04_08.c:setup_trig_pag_evt
(8)[1]
libmsc/gsm_04_11.c:gsm411_send_sms_subscr()
req->cbfn =
libmsc/gsm_04_11.c:paging_cb_send_sms
(9)
bsc_scan_msc_msg() ./osmo-bsc/osmo_bsc_filter.c:330
gsm48_hdr
send_welcome_ussd() ./osmo-bsc/osmo_bsc_filter.c:229
LOGP()
DMSC
LOGL_DEBUG
ussd_welcome_txt
BSS_SEND_USSD
GSM48_MT_MM_INFO
bsc_patch_mm_info() ./osmo-bsc/osmo_bsc_filter.c:255
uint8_t
tzbsd
dst
tlv_parse()
gsm48_mm_att_tlvdef
override
hr
mn
TLVP_PRESENT()
GSM48_IE_UTC
LOGP()
DMSC
LOGL_DEBUG
TLVP_VAL()
GSM48_IE_NET_TIME_TZ
GSM48_IE_NET_DST
(6)
libmsc/gsm0408.c: gsm0408_dispatch() (MSC rx from BSC)
if (silent_call_reroute(conn, msg))
return silent_call_rx(conn, msg);
case gsm48_pdisc_cc:
rc = gsm0408_rcv_cc(conn, msg);
case gsm48_pdisc_mm:
rc = gsm0408_rcv_mm(conn, msg);
case gsm48_pdisc_rr:
rc = gsm0408_rcv_rr(conn, msg);
case gsm48_pdisc_sms:
rc = gsm0411_rcv_sms(conn, msg);
case gsm48_pdisc_nc_ss:
rc = handle_rcv_ussd(conn, msg);
case gsm48_pdisc_mm_gprs:
case gsm48_pdisc_sm_gprs:
logp(drll, logl_notice, "unimplemented "
msc_bsc_api().assign_compl =
msc_assign_compl()
nothing
(4)[0]
libmsc/osmo_msc.c:msc_bsc_api().cipher_mode_compl =
msc_ciph_m_compl(conn, msg, alg_id)
conn->sec_operation->cb(GSM_HOOK_RR_SECURITY, GSM_SECURITY_SUCCEEDED,
NULL, conn, conn->sec_operation->cb_data)
release_security_operation(conn);
msc_release_connection(conn)
bsc_api.c:gsm0808_clear(conn)
libbsc/handover_logic.c:bsc_clear_handover(conn, 1)
libbsc/chan_alloc.c:lchan_release(ho->new_lchan, 0, RSL_REL_LOCAL_END);
libbsc/chan_alloc.c:lchan_release(conn->secondary_lchan, 0, RSL_REL_LOCAL_END),
(conn->lchan, 1, RSL_REL_NORMAL)
bsc_api.c:subscr_con_free(conn)
libcommon/gsm_subscriber_base.c:subscr_put(conn->subscr);
(4)[1]
osmo-bsc/osmo_bsc_api.c:osmo_bsc_api().cipher_mode_compl =
bsc_cipher_mode_compl()
queue_msg_or_return() osmo-bsc/osmo_bsc_api.c
bsc_queue_for_msc()
libbsc/abis_nm.c:abis_nm_rcvmsg(msg);
case ABIS_OM_MDISC_FOM:
rc = abis_nm_rcvmsg_fom(msg);
case ABIS_OM_MDISC_MANUF:
rc = abis_nm_rcvmsg_manuf(msg);
case ABIS_OM_MDISC_MMI:
case ABIS_OM_MDISC_TRAU:
LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",

View File

@@ -0,0 +1,36 @@
!
! OsmoCSCN configuration saved from vty
!
line vty
no login
!
network
network country code 1
mobile network code 1
short name OsmoCSCN
long name OsmoCSCN
auth policy closed
location updating reject cause 13
encryption a5 0
rrlp mode none
mm info 1
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 t3141 0
cscn
subscriber-create-on-demand

View File

@@ -1,5 +1,7 @@
digraph G {
net [label="gsm_network"]
subconns [label="subscr_conns"]
btslist [label="bts_list"]
bts [label="gsm_bts"]
trx [label="gsm_bts_trx"]
ts [label="gsm_bts_trx_ts"]
@@ -9,7 +11,8 @@ digraph G {
sccpcon [label="osmo_bsc_sccp_con"]
subgrp [label="gsm_subscriber_group"]
net -> bts
net -> btslist
btslist -> bts [label="llist"]
bts -> trx
trx -> ts
ts -> lchan
@@ -21,6 +24,8 @@ digraph G {
lchan -> subcon
net -> subconns
subconns -> subcon [label="llist"]
subcon -> sub
subcon -> sccpcon
subcon -> lchan

View File

@@ -0,0 +1,15 @@
digraph G {
net [label="gsm_network"]
subconns [label="subscr_conns"]
sub [label="gsm_subscriber"]
subcon [label="gsm_subscriber_conn"]
subgrp [label="gsm_subscriber_group"]
net -> subconns
subconns -> subcon [label="llist"]
subcon -> sub
subcon -> net
sub -> subgrp
subgrp -> net
}

View File

@@ -8,7 +8,7 @@ noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \
vty.h socket.h e1_config.h trau_upqueue.h token_auth.h \
handover_decision.h rrlp.h \
crc24.h gprs_llc.h gprs_gmm.h \
gb_proxy.h gprs_sgsn.h sgsn.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 \
@@ -18,7 +18,9 @@ noinst_HEADERS = abis_nm.h abis_rsl.h db.h gsm_04_08.h gsm_data.h \
gprs_gb_parse.h smpp.h meas_feed.h \
gprs_gsup_client.h bsc_msg_filter.h \
oap.h oap_messages.h \
gtphub.h
gtphub.h \
msc_api.h msc_ifaces.h iu.h iu_cs.h \
xsc.h
openbsc_HEADERS = gsm_04_08.h meas_rep.h bsc_api.h
openbscdir = $(includedir)/openbsc

View File

@@ -52,6 +52,4 @@ 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

@@ -1,11 +1,14 @@
#ifndef _BSS_H_
#define _BSS_H_
#include <openbsc/xsc.h>
struct gsm_network;
struct msgb;
/* start and stop network */
extern int bsc_bootstrap_network(int (*mncc_recv)(struct gsm_network *, struct msgb *), const char *cfg_file);
extern int bsc_network_init(mncc_recv_cb_t mncc_recv);
extern int bsc_network_configure(const char *cfg_file);
extern int bsc_shutdown_net(struct gsm_network *net);
/* register all supported BTS */

View File

@@ -34,6 +34,9 @@ enum {
DSMPP,
DFILTER,
DGTPHUB,
DSUA,
DRANAP,
DIUCS,
Debug_LastEntry,
};

View File

@@ -10,7 +10,9 @@ int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,
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_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme);
int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id,
uint16_t *sai);
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);

View File

@@ -23,7 +23,7 @@ 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 {
enum gprs_gmm_state {
GMM_DEREGISTERED, /* 4.1.3.3.1.1 */
GMM_COMMON_PROC_INIT, /* 4.1.3.3.1.2 */
GMM_REGISTERED_NORMAL, /* 4.1.3.3.2.1 */
@@ -31,6 +31,16 @@ enum gprs_mm_state {
GMM_DEREGISTERED_INIT, /* 4.1.3.3.1.4 */
};
/* TS 23.060 6.1.1 and 6.1.2 Mobility management states A/Gb and Iu mode */
enum gprs_pmm_state {
PMM_DETACHED,
PMM_CONNECTED,
PMM_IDLE,
MM_IDLE = PMM_DETACHED,
MM_READY = PMM_CONNECTED,
MM_STANDBY = PMM_IDLE,
};
enum gprs_mm_ctr {
GMM_CTR_PKTS_SIG_IN,
GMM_CTR_PKTS_SIG_OUT,
@@ -92,13 +102,32 @@ struct sgsn_ggsn_lookup {
uint8_t ti;
};
enum sgsn_ran_type {
/* GPRS/EDGE via Gb */
MM_CTX_T_GERAN_Gb,
/* UMTS via Iu */
MM_CTX_T_UTRAN_Iu,
/* GPRS/EDGE via Iu */
MM_CTX_T_GERAN_Iu,
};
struct service_info {
uint8_t type;
uint16_t pdp_status;
};
struct ue_conn_ctx;
/* According to TS 03.60, Table 5: SGSN MM and PDP Contexts */
/* Extended by 3GPP TS 23.060, Table 6: SGSN MM and PDP Contexts */
struct sgsn_mm_ctx {
struct llist_head list;
enum sgsn_ran_type ran_type;
char imsi[GSM23003_IMSI_MAX_DIGITS+1];
enum gprs_mm_state mm_state;
enum gprs_gmm_state mm_state;
enum gprs_pmm_state pmm_state;
uint32_t p_tmsi;
uint32_t p_tmsi_old; /* old P-TMSI before new is confirmed */
uint32_t p_tmsi_sig;
@@ -106,10 +135,32 @@ struct sgsn_mm_ctx {
/* Opt: Software Version Numbber / TS 23.195 */
char msisdn[GSM_EXTENSION_LENGTH];
struct gprs_ra_id ra;
uint16_t cell_id;
uint32_t cell_id_age;
uint16_t sac; /* Iu: Service Area Code */
uint32_t sac_age;/* Iu: Service Area Code age */
struct {
uint16_t cell_id; /* Gb only */
uint32_t cell_id_age; /* Gb only */
uint8_t radio_prio_sms;
/* Additional bits not present in the GSM TS */
uint16_t nsei;
uint16_t bvci;
struct gprs_llc_llme *llme;
uint32_t tlli;
uint32_t tlli_new;
} gb;
struct {
int new_key;
uint16_t sac; /* Iu: Service Area Code */
uint32_t sac_age; /* Iu: Service Area Code age */
/* CSG ID */
/* CSG Membership */
/* Access Mode */
/* Seelected CN Operator ID (TS 23.251) */
/* CSG Subscription Data */
/* LIPA Allowed */
/* Voice Support Match Indicator */
struct ue_conn_ctx *ue_ctx;
struct service_info service;
} iu;
/* VLR number */
uint32_t new_sgsn_addr;
/* Authentication Triplet */
@@ -118,30 +169,38 @@ struct sgsn_mm_ctx {
/* Iu: CK, IK, KSI */
/* CKSN */
enum gprs_ciph_algo ciph_algo;
struct {
uint8_t len;
uint8_t buf[50]; /* GSM 04.08 10.5.5.12a, extended in TS 24.008 */
} ms_radio_access_capa;
/* Supported Codecs (SRVCC) */
struct {
uint8_t len;
uint8_t buf[8]; /* GSM 04.08 10.5.5.12, extended in TS 24.008 */
} ms_network_capa;
/* UE Netowrk Capability (E-UTRAN) */
uint16_t drx_parms;
/* Active Time value for PSM */
int mnrg; /* MS reported to HLR? */
int ngaf; /* MS reported to MSC/VLR? */
int ppf; /* paging for GPRS + non-GPRS? */
/* Subscribed Charging Characteristics */
/* Trace Reference */
/* Trace Type */
/* Trigger ID */
/* OMC Identity */
/* SMS Parameters */
int recovery;
uint8_t radio_prio_sms;
/* Access Restriction */
/* GPRS CSI (CAMEL) */
/* MG-CSI (CAMEL) */
/* Subscribed UE-AMBR */
/* UE-AMBR */
/* APN Subscribed */
struct llist_head pdp_list;
/* Additional bits not present in the GSM TS */
struct gprs_llc_llme *llme;
uint32_t tlli;
uint32_t tlli_new;
uint16_t nsei;
uint16_t bvci;
struct rate_ctr_group *ctrg;
struct osmo_timer_list timer;
unsigned int T; /* Txxxx number */
@@ -176,6 +235,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli,
const struct gprs_ra_id *raid);
struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t tmsi);
struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi);
struct sgsn_mm_ctx *sgsn_mm_ctx_by_ue_ctx(const void *uectx);
/* look-up by matching TLLI and P-TMSI (think twice before using this) */
struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli_and_ptmsi(uint32_t tlli,
@@ -184,6 +244,8 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli_and_ptmsi(uint32_t tlli,
/* Allocate a new SGSN MM context */
struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli,
const struct gprs_ra_id *raid);
struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx);
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,

View File

@@ -77,6 +77,8 @@ int decode_bcd_number(char *output, int output_len, const uint8_t *bcd_lv,
int send_siemens_mrpci(struct gsm_lchan *lchan, uint8_t *classmark2_lv);
int gsm48_extract_mi(uint8_t *classmark2, int length, char *mi_string, uint8_t *mi_type);
int gsm48_paging_extract_mi(struct gsm48_pag_resp *pag, int length, char *mi_string, uint8_t *mi_type);
/* TODO MSCSPLIT remove gsm48_handle_paging_resp() */
int gsm48_handle_paging_resp(struct gsm_subscriber_connection *conn, struct msgb *msg, struct gsm_subscriber *subscr);
int gsm48_lchan_modify(struct gsm_lchan *lchan, uint8_t lchan_mode);

View File

@@ -0,0 +1,21 @@
#pragma once
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
/* TODO: Move this to osmocom/gsm/protocol/gsm_04_08_gprs.h ? */
/* Table 10.4 in 3GPP TS 24.008 (successor to 04.08) */
#define GSM48_MT_GMM_SERVICE_REQ 0x0c
#define GSM48_MT_GMM_SERVICE_ACK 0x0d
#define GSM48_MT_GMM_SERVICE_REJ 0x0e
/* 3GPP 24.008 / Chapter 10.5.5.20 / Table 10.5.153a */
enum gsm48_gmm_service_type {
GPRS_SERVICE_T_SIGNALLING = 0x00,
GPRS_SERVICE_T_DATA = 0x01,
GPRS_SERVICE_T_PAGING_RESP = 0x02,
GPRS_SERVICE_T_MBMS_MC_SERV = 0x03,
GPRS_SERVICE_T_MBMS_BC_SERV = 0x04,
};
extern const struct value_string *gprs_service_t_strs;

View File

@@ -38,5 +38,5 @@ 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);
uint8_t sms_next_rp_msg_ref(uint8_t *next_rp_ref);
#endif

View File

@@ -14,6 +14,9 @@ int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
const struct msgb *msg,
const struct ussd_request *request);
struct msgb *gsm0480_gen_ussdNotify(int level, const char *text);
struct msgb *gsm0480_gen_releaseComplete(void);
int gsm0480_send_ussdNotify(struct gsm_subscriber_connection *conn, int level, const char *text);
int gsm0480_send_releaseComplete(struct gsm_subscriber_connection *conn);

View File

@@ -8,6 +8,7 @@
#include <osmocom/crypt/auth.h>
#include <openbsc/rest_octets.h>
#include <openbsc/xsc.h>
/** annotations for msgb ownership */
#define __uses
@@ -97,7 +98,19 @@ struct neigh_meas_proc {
uint8_t last_seen_nr;
};
/* the per subscriber data for lchan */
enum interface_type {
IFACE_UNKNOWN = -1,
IFACE_A = 0, /* A-interface for 2G */
IFACE_IU = 1 /* Iu-interface for UMTS aka 3G (IuCS or IuPS) */
};
enum integrity_protection_state {
INTEGRITY_PROTECTION_NONE = 0,
INTEGRITY_PROTECTION_IK = 1,
INTEGRITY_PROTECTION_IK_CK = 2,
};
/* mobile subscriber data */
struct gsm_subscriber_connection {
struct llist_head entry;
@@ -124,18 +137,40 @@ struct gsm_subscriber_connection {
int mncc_rtp_create_pending;
int mncc_rtp_connect_pending;
/* bsc structures */
struct osmo_bsc_sccp_con *sccp_con;
/* back pointers */
struct gsm_network *network;
/* The BSC used to be an integral part of OsmoNITB. In OsmoCSCN, the
* BSC and/or RNC is a separate entity, and no back pointers to the bts
* and lchan structures are available. To facilitate separation of the
* code paths, I'm explicitly excluding the unavailable structures from
* the build. Once separated, this split may become unnecessary. */
#if COMPILING_LIBMSC
int in_release;
uint16_t lac;
struct gsm_encr encr;
/* 2G or 3G? See enum interface_type */
int via_iface;
/* which Iu-CS connection, if any. */
struct {
struct ue_conn_ctx *ue_ctx;
int integrity_protection;
} iu;
#else
struct gsm_bts *bts;
struct gsm_lchan *lchan;
struct gsm_lchan *ho_lchan;
struct gsm_bts *bts;
/* bsc structures */
struct osmo_bsc_sccp_con *sccp_con;
/* for assignment handling */
struct osmo_timer_list T10;
struct gsm_lchan *secondary_lchan;
#endif
};
@@ -207,7 +242,20 @@ enum gsm_auth_policy {
#define GSM_T3113_DEFAULT 60
#define GSM_T3122_DEFAULT 10
struct gsm_tz {
int override; /* if 0, use system's time zone instead. */
int hr; /* hour */
int mn; /* minute */
int dst; /* daylight savings */
};
struct gsm_network {
/* TODO MSCSPLIT the gsm_network struct is basically a kitchen sink for
* global settings and variables, "madly" mixing BSC and MSC stuff. Split
* this in e.g. struct osmo_bsc and struct osmo_msc, with the things
* these have in common, like country and network code, put in yet
* separate structs and placed as members in osmo_bsc and osmo_msc. */
/* global parameters */
uint16_t country_code;
uint16_t network_code;
@@ -290,6 +338,19 @@ struct gsm_network {
/* control interface */
struct ctrl_handle *ctrl;
/* all active subscriber connections. */
struct llist_head subscr_conns;
/* if override is nonzero, this timezone data is used for all MM
* contexts. */
/* TODO: in OsmoNITB, tz-override used to be BTS-specific. To enable
* BTS|RNC specific timezone overrides for multi-tz networks in
* OsmoCSCN, this should be tied to the location area code (LAC). */
struct gsm_tz tz;
/* Periodic location update default value */
uint8_t t3212;
};
struct osmo_esme;
@@ -336,13 +397,12 @@ struct gsm_sms {
char text[SMS_TEXT_SIZE];
};
struct gsm_network *gsm_network_init(uint16_t country_code, uint16_t network_code,
int (*mncc_recv)(struct gsm_network *, struct msgb *));
int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type);
struct gsm_network *gsm_network_init(void *ctx,
uint16_t country_code,
uint16_t network_code,
mncc_recv_cb_t mncc_recv);
/* 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);
int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type);
enum gsm_bts_type parse_btstype(const char *arg);
const char *btstype2str(enum gsm_bts_type type);
@@ -426,13 +486,15 @@ 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);
struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan);
int gsm_btsmodel_set_feature(struct gsm_bts_model *model, enum gsm_bts_features feat);
int gsm_bts_model_register(struct gsm_bts_model *model);
struct gsm_subscriber_connection *subscr_con_allocate(struct gsm_lchan *lchan);
void subscr_con_free(struct gsm_subscriber_connection *conn);
struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_lchan *lchan);
void bsc_subscr_con_free(struct gsm_subscriber_connection *conn);
struct gsm_subscriber_connection *msc_subscr_con_allocate(struct gsm_network *network);
void msc_subscr_con_free(struct gsm_subscriber_connection *conn);
struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net,
enum gsm_bts_type type,

View File

@@ -24,6 +24,8 @@
#include <osmocom/gsm/lapdm.h>
#endif
#include <openbsc/xsc.h>
struct osmo_bsc_data;
struct osmo_bsc_sccp_con;
@@ -100,7 +102,6 @@ struct gsm_abis_mo {
struct gsm_bts *bts;
};
#define MAX_A5_KEY_LEN (128/8)
#define A38_XOR_MIN_KEY_LEN 12
#define A38_XOR_MAX_KEY_LEN 16
#define A38_COMP128_KEY_LEN 16
@@ -202,11 +203,7 @@ struct gsm_lchan {
uint8_t bs_power;
uint8_t ms_power;
/* Encryption information */
struct {
uint8_t alg_id;
uint8_t key_len;
uint8_t key[MAX_A5_KEY_LEN];
} encr;
struct gsm_encr encr;
/* AMR bits */
uint8_t mr_ms_lv[7];
@@ -351,7 +348,7 @@ struct gsm_bts_trx_ts {
struct gsm_lchan lchan[TS_MAX_LCHAN];
};
/* One TRX in a BTS */
/* One TRX (transceiver) in a BTS */
struct gsm_bts_trx {
/* list header in bts->trx_list */
struct llist_head list;
@@ -609,14 +606,6 @@ struct gsm_bts {
/* buffers where we put the pre-computed SI */
sysinfo_buf_t si_buf[_MAX_SYSINFO_TYPE];
/* TimeZone hours, mins, and bts specific */
struct {
int hr;
int mn;
int override;
int dst;
} tz;
/* ip.accesss Unit ID's have Site/BTS/TRX layout */
union {
struct {

View File

@@ -1,6 +1,8 @@
#ifndef _GSM_SUBSCR_H
#define _GSM_SUBSCR_H
#include <stdbool.h>
#include "gsm_data.h"
#include <osmocom/core/linuxlist.h>
#include <osmocom/gsm/protocol/gsm_23_003.h>
@@ -68,6 +70,7 @@ struct gsm_subscriber {
/* pending requests */
int is_paging;
struct osmo_timer_list paging_timeout;
struct llist_head requests;
/* GPRS/SGSN related fields */
@@ -87,6 +90,20 @@ enum gsm_subscriber_update_reason {
GSM_SUBSCRIBER_UPDATE_EQUIPMENT,
};
/*
* Struct for pending channel requests. This is managed in the
* llist_head requests of each subscriber. The reference counting
* should work in such a way that a subscriber with a pending request
* remains in memory.
*/
struct subscr_request {
struct llist_head entry;
/* the callback data */
gsm_cbfn *cbfn;
void *param;
};
struct gsm_subscriber *subscr_get(struct gsm_subscriber *subscr);
struct gsm_subscriber *subscr_put(struct gsm_subscriber *subscr);
struct gsm_subscriber *subscr_create_subscriber(struct gsm_subscriber_group *sgrp,
@@ -101,7 +118,8 @@ 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_subscriber_group *sgrp,
const char *imsi);
int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason);
int subscr_update(struct gsm_network *network, struct gsm_subscriber *s,
uint16_t lac, int reason);
struct gsm_subscriber *subscr_active_by_tmsi(struct gsm_subscriber_group *sgrp,
uint32_t tmsi);
struct gsm_subscriber *subscr_active_by_imsi(struct gsm_subscriber_group *sgrp,
@@ -112,14 +130,18 @@ char *subscr_name(struct gsm_subscriber *subscr);
int subscr_purge_inactive(struct gsm_subscriber_group *sgrp);
void subscr_update_from_db(struct gsm_subscriber *subscr);
void subscr_expire(struct gsm_subscriber_group *sgrp);
int subscr_update_expire_lu(struct gsm_subscriber *subscr, struct gsm_bts *bts);
int subscr_update_expire_lu(struct gsm_network *network, struct gsm_subscriber *subscr);
bool subscr_authorized(struct gsm_subscriber *subsc);
/*
* Paging handling with authentication
*/
struct subscr_request *subscr_request_channel(struct gsm_subscriber *subscr,
int type, gsm_cbfn *cbfn, void *param);
struct subscr_request *subscr_request_conn(struct gsm_subscriber *subscr,
gsm_cbfn *cbfn, void *param);
void subscr_remove_request(struct subscr_request *req);
int subscr_rx_paging_response(struct msgb *msg,
struct gsm_subscriber_connection *conn);
/* internal */
struct gsm_subscriber *subscr_alloc(void);

View File

@@ -0,0 +1,61 @@
#pragma once
#include <stdbool.h>
struct sgsn_pdp_ctx;
struct msgb;
struct gprs_ra_id;
struct RANAP_RAB_SetupOrModifiedItemIEs_s;
struct RANAP_GlobalRNC_ID;
struct ue_conn_ctx {
struct llist_head list;
struct osmo_sua_link *link;
uint32_t conn_id;
int integrity_active;
struct gprs_ra_id ra_id;
};
enum iu_event_type {
IU_EVENT_RAB_ASSIGN,
IU_EVENT_SECURITY_MODE_COMPLETE,
IU_EVENT_IU_RELEASE, /* An actual Iu Release message was received */
IU_EVENT_LINK_INVALIDATED, /* A SUA link was lost or closed down */
/* FIXME: maybe IU_EVENT_IU_RELEASE and IU_EVENT_LINK_INVALIDATED
* should be combined to one generic event that simply means the
* ue_conn_ctx should no longer be used, for whatever reason. */
};
extern const struct value_string iu_event_type_names[];
static inline const char *iu_event_type_str(enum iu_event_type e)
{
return get_value_string(iu_event_type_names, e);
}
/* Implementations of iu_recv_cb_t shall find the ue_conn_ctx in msg->dst. */
typedef int (* iu_recv_cb_t )(struct msgb *msg, struct gprs_ra_id *ra_id,
/* TODO "gprs_" in generic CS+PS domain ^ */
uint16_t *sai);
typedef int (* iu_event_cb_t )(struct ue_conn_ctx *ue_ctx,
enum iu_event_type type, void *data);
typedef int (* iu_rab_ass_resp_cb_t )(struct ue_conn_ctx *ue_ctx, uint8_t rab_id,
struct RANAP_RAB_SetupOrModifiedItemIEs_s *setup_ies);
int iu_init(void *ctx, const char *listen_addr, uint16_t listen_port,
iu_recv_cb_t iu_recv_cb, iu_event_cb_t iu_event_cb);
void iu_link_del(struct osmo_sua_link *link);
int iu_tx(struct msgb *msg, uint8_t sapi);
int iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac);
int iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac);
int iu_rab_act_cs(struct ue_conn_ctx *ue_ctx, uint32_t rtp_ip, uint16_t rtp_port);
int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp, bool use_x213_nsap);
int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id);
int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp,
int send_ck, int new_key);

View File

@@ -0,0 +1,7 @@
#pragma once
int gsm0408_rcvmsg_iucs(struct gsm_network *network, struct msgb *msg,
uint16_t *lac);
struct gsm_subscriber_connection *subscr_conn_lookup_iu(struct gsm_network *network,
struct ue_conn_ctx *ue);

View File

@@ -0,0 +1,29 @@
#pragma once
/* These functions receive or send MM|CC|... messages from/to the BSC|RNC
* direction, while they are not concerned with which particular external
* interface is actually involved (A or IuCS).
*
* For the interface specific decisions see msc_iface.[hc]
*/
/* MSCSPLIT WIP: this will gradually replace the role that the bsc_api.h had in
* OsmoNITB. Actually, osmo_msc.[hc] has the same role as this file, but having
* separate files helps me to keep track of how far I've gotten yet. */
#include <stdint.h>
struct gsm_subscriber_connection;
struct msgb;
enum {
MSC_CONN_ACCEPT = 0,
MSC_CONN_REJECT = 1,
};
/* receive a Level 3 Complete message and return MSC_CONN_ACCEPT or
* MSC_CONN_REJECT */
int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg,
uint16_t chosen_channel);
/* TODO: is chosen_channel BSC land == NITB legacy? */

View File

@@ -0,0 +1,40 @@
#pragma once
#include <osmocom/core/msgb.h>
#include <openbsc/gsm_data.h>
/* These are the interfaces of the MSC layer towards (from?) the BSC and RNC,
* i.e. in the direction towards the mobile device (MS aka UE).
*
* 2G will use the A-interface,
* 3G aka UMTS will use the Iu-interface (for the MSC, it's IuCS).
*
* To allow linking parts of the MSC code without having to include entire
* infrastructures of external libraries, the core transmitting and receiving
* functions are left unimplemented. For example, a unit test does not need to
* link against external ASN1 libraries if it is never going to encode actual
* outgoing messages. It is up to each building scope to implement real world
* functions or to plug mere dummy implementations.
*
* For example, msc_tx_dtap(conn, msg), depending on conn->via_iface, will call
* either iu_tx() or a_tx() [note: at time of writing, the A-interface is not
* yet implemented]. When you try to link against libmsc, you will find that
* the compiler complains about an undefined reference to iu_tx(). If you,
* however, link against libiu as well as the osmo-iuh libs (etc.), iu_tx() is
* available. A unit test may instead simply implement a dummy iu_tx() function
* and not link against osmo-iuh.
*/
/* Each main linkage must implement this function (see comment above). */
extern int iu_tx(struct msgb *msg, uint8_t sapi);
/* So far this is a dummy implemented in libmsc/a_iface.c. When A-interface
* gets implemented, it should be in a separate lib (like libiu), this function
* should move there, and the following comment should remain here: "
* Each main linkage must implement this function (see comment above).
* " */
extern int a_tx(struct msgb *msg);
int msc_tx_dtap(struct gsm_subscriber_connection *conn,
struct msgb *msg);

View File

@@ -142,7 +142,6 @@ struct gsm_subscriber;
struct paging_signal_data {
struct gsm_subscriber *subscr;
struct gsm_bts *bts;
int paging_result;

View File

@@ -32,18 +32,22 @@ enum bsc_vty_node {
TRUNK_NODE,
PGROUP_NODE,
MNCC_INT_NODE,
NITB_NODE,
BSC_NODE,
SMPP_NODE,
SMPP_ESME_NODE,
GTPHUB_NODE,
CSCN_NODE,
};
extern int bsc_vty_is_config_node(struct vty *vty, int node);
extern void bsc_replace_string(void *ctx, char **dst, const char *newstr);
struct log_info;
int bsc_vty_init(const struct log_info *cat);
int bsc_vty_init(const struct log_info *cat, struct gsm_network *network);
int bsc_vty_init_extra(void);
void cscn_vty_init(void);
struct gsm_network *gsmnet_from_vty(struct vty *vty);
#endif

View File

@@ -0,0 +1,23 @@
#pragma once
#include <stdint.h>
struct msgb;
struct gsm_network;
struct log_info;
struct ctrl_handle;
typedef int (*mncc_recv_cb_t)(struct gsm_network *, struct msgb *);
#define MAX_A5_KEY_LEN (128/8)
struct gsm_encr {
uint8_t alg_id;
uint8_t key_len;
uint8_t key[MAX_A5_KEY_LEN];
};
extern struct gsm_network *vty_global_gsm_network;
int xsc_vty_init(struct gsm_network *network);

View File

@@ -2,7 +2,7 @@ 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 libfilter osmo-nitb osmo-bsc_mgcp utils ipaccess gprs
SUBDIRS = libcommon libmgcp libbsc libiu libmsc libtrau libfilter libxsc osmo-cscn osmo-bsc_mgcp utils ipaccess gprs
# Conditional modules
if BUILD_NAT

View File

@@ -2,9 +2,11 @@ AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CFLAGS=-Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOCTRL_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) $(LIBOSMOGB_CFLAGS) $(COVERAGE_CFLAGS) \
$(LIBCARES_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBGTP_CFLAGS)
$(LIBCARES_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBGTP_CFLAGS) \
$(LIBASN1C_CFLAGS) $(LIBOSMOSIGTRAN_CFLAGS) $(LIBOSMORANAP_CFLAGS)
OSMO_LIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) \
$(LIBOSMOCTRL_LIBS) $(LIBOSMOGB_LIBS)
$(LIBOSMOCTRL_LIBS) $(LIBOSMOGB_LIBS) -ltalloc -lm
noinst_HEADERS = gprs_sndcp.h
@@ -16,6 +18,8 @@ bin_PROGRAMS += osmo-sgsn osmo-gtphub
endif
endif
IUHDIR = $(top_srcdir)/../../osmo-iuh
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
@@ -27,12 +31,15 @@ osmo_sgsn_SOURCES = gprs_gmm.c gprs_sgsn.c gprs_sndcp.c gprs_sndcp_vty.c \
gprs_llc.c gprs_llc_parse.c gprs_llc_vty.c crc24.c \
sgsn_ctrl.c sgsn_auth.c gprs_subscriber.c \
gprs_utils.c gprs_gsup_client.c \
sgsn_cdr.c sgsn_ares.c \
gsm_04_08_gprs.c sgsn_cdr.c sgsn_ares.c \
oap.c oap_messages.c
osmo_sgsn_LDADD = \
$(top_builddir)/src/libcommon/libcommon.a \
$(top_builddir)/src/libiu/libiu.a \
-lgtp $(OSMO_LIBS) $(LIBOSMOABIS_LIBS) $(LIBCARES_LIBS) \
$(LIBCRYPTO_LIBS) -lrt
$(LIBCRYPTO_LIBS) -lrt \
$(LIBOSMOSIGTRAN_LIBS) $(LIBOSMORANAP_LIBS) $(LIBASN1C_LIBS)
osmo_gtphub_SOURCES = gtphub_main.c gtphub.c gtphub_sock.c gtphub_ares.c \
gtphub_vty.c sgsn_ares.c gprs_utils.c

View File

@@ -31,6 +31,8 @@
#include <arpa/inet.h>
#include <netdb.h>
#include <openssl/rand.h>
#include <openbsc/db.h>
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/tlv.h>
@@ -38,15 +40,17 @@
#include <osmocom/core/signal.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/crypt/auth.h>
#include <osmocom/gsm/apn.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/ranap/ranap_ies_defs.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/gsm_04_08_gprs.h>
#include <openbsc/paging.h>
#include <openbsc/transaction.h>
#include <openbsc/gprs_llc.h>
@@ -55,6 +59,7 @@
#include <openbsc/gprs_utils.h>
#include <openbsc/sgsn.h>
#include <openbsc/signal.h>
#include <openbsc/iu.h>
#include <pdp.h>
@@ -95,6 +100,46 @@ static const struct tlv_definition gsm48_sm_att_tlvdef = {
static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx);
int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies);
int sgsn_ranap_iu_event(struct ue_conn_ctx *ctx, enum iu_event_type type, void *data)
{
struct sgsn_mm_ctx *mm;
int rc = -1;
mm = sgsn_mm_ctx_by_ue_ctx(ctx);
if (!mm) {
LOGP(DRANAP, LOGL_NOTICE, "Cannot find mm ctx for IU event %i!\n", type);
return rc;
}
switch (type) {
case IU_EVENT_RAB_ASSIGN:
rc = sgsn_ranap_rab_ass_resp(mm, (RANAP_RAB_SetupOrModifiedItemIEs_t *)data);
break;
case IU_EVENT_IU_RELEASE:
/* fall thru */
case IU_EVENT_LINK_INVALIDATED:
/* Clean up ue_conn_ctx here */
LOGMMCTXP(LOGL_INFO, mm, "IU release for imsi %s\n", mm->imsi);
if (mm->pmm_state == PMM_CONNECTED)
mm->pmm_state = PMM_IDLE;
rc = 0;
break;
case IU_EVENT_SECURITY_MODE_COMPLETE:
/* Continue authentication here */
mm->iu.ue_ctx->integrity_active = 1;
rc = gsm48_gmm_authorize(mm);
break;
default:
LOGP(DRANAP, LOGL_NOTICE, "Unknown event received: %i\n", type);
rc = -1;
break;
}
return rc;
}
/* Our implementation, should be kept in SGSN */
static void mmctx_timer_cb(void *_mm);
@@ -135,6 +180,9 @@ static int gsm48_gmm_sendmsg(struct msgb *msg, int command,
if (mm)
rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PKTS_SIG_OUT]);
if (msg->dst)
return iu_tx(msg, GPRS_SAPI_GMM);
/* caller needs to provide TLLI, BVCI and NSEI */
return gprs_llc_tx_ui(msg, GPRS_SAPI_GMM, command, mm);
}
@@ -146,21 +194,24 @@ static void gmm_copy_id(struct msgb *msg, const struct msgb *old)
msgb_tlli(msg) = msgb_tlli(old);
msgb_bvci(msg) = msgb_bvci(old);
msgb_nsei(msg) = msgb_nsei(old);
msg->dst = old->dst;
}
/* Store BVCI/NSEI in MM context */
static void msgid2mmctx(struct sgsn_mm_ctx *mm, const struct msgb *msg)
{
mm->bvci = msgb_bvci(msg);
mm->nsei = msgb_nsei(msg);
mm->gb.bvci = msgb_bvci(msg);
mm->gb.nsei = msgb_nsei(msg);
mm->iu.ue_ctx = msg->dst;
}
/* Store BVCI/NSEI in MM context */
static void mmctx2msgid(struct msgb *msg, const struct sgsn_mm_ctx *mm)
{
msgb_tlli(msg) = mm->tlli;
msgb_bvci(msg) = mm->bvci;
msgb_nsei(msg) = mm->nsei;
msgb_tlli(msg) = mm->gb.tlli;
msgb_bvci(msg) = mm->gb.bvci;
msgb_nsei(msg) = mm->gb.nsei;
msg->dst = mm->iu.ue_ctx;
}
static void mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx, const char *log_text)
@@ -169,6 +220,7 @@ static void mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx, const char *log_text)
/* Mark MM state as deregistered */
ctx->mm_state = GMM_DEREGISTERED;
ctx->pmm_state = PMM_DETACHED;
sgsn_mm_ctx_cleanup_free(ctx);
}
@@ -524,10 +576,15 @@ static int gsm48_rx_gmm_auth_ciph_resp(struct sgsn_mm_ctx *ctx,
ctx->is_authenticated = 1;
if (ctx->ran_type == MM_CTX_T_UTRAN_Iu)
ctx->iu.new_key = 1;
/* FIXME: enable LLC cipheirng */
/* Check if we can let the mobile station enter */
return gsm48_gmm_authorize(ctx);
rc = gsm48_gmm_authorize(ctx);
return rc;
}
static void extract_subscr_msisdn(struct sgsn_mm_ctx *ctx)
@@ -599,9 +656,72 @@ static void extract_subscr_hlr(struct sgsn_mm_ctx *ctx)
strncpy(&ctx->hlr[0], called.number, sizeof(ctx->hlr) - 1);
}
/* Chapter 9.4.21: Service accept */
static int gsm48_tx_gmm_service_ack(struct sgsn_mm_ctx *mm)
{
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE ACK");
struct gsm48_hdr *gh;
LOGMMCTXP(LOGL_INFO, mm, "<- GPRS SERVICE ACCEPT (P-TMSI=0x%08x)\n", mm->p_tmsi);
mmctx2msgid(msg, mm);
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
gh->proto_discr = GSM48_PDISC_MM_GPRS;
gh->msg_type = GSM48_MT_GMM_SERVICE_ACK;
/* Optional: PDP context status */
/* Optional: MBMS context status */
return gsm48_gmm_sendmsg(msg, 0, mm);
}
/* Chapter 9.4.22: Service reject */
static int _tx_gmm_service_rej(struct msgb *msg, uint8_t gmm_cause,
const struct sgsn_mm_ctx *mm)
{
struct gsm48_hdr *gh;
LOGMMCTXP(LOGL_NOTICE, mm, "<- GPRS SERVICE REJECT: %s\n",
get_value_string(gsm48_gmm_cause_names, gmm_cause));
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
gh->proto_discr = GSM48_PDISC_MM_GPRS;
gh->msg_type = GSM48_MT_GMM_SERVICE_REJ;
gh->data[0] = gmm_cause;
return gsm48_gmm_sendmsg(msg, 0, NULL);
}
static int gsm48_tx_gmm_service_rej_oldmsg(const struct msgb *old_msg,
uint8_t gmm_cause)
{
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE REJ OLD");
gmm_copy_id(msg, old_msg);
return _tx_gmm_service_rej(msg, gmm_cause, NULL);
}
static int gsm48_tx_gmm_service_rej(struct sgsn_mm_ctx *mm,
uint8_t gmm_cause)
{
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERVICE REJ");
mmctx2msgid(msg, mm);
return _tx_gmm_service_rej(msg, gmm_cause, mm);
}
static int gsm48_tx_gmm_ra_upd_ack(struct sgsn_mm_ctx *mm);
void activate_pdp_rabs(struct sgsn_mm_ctx *ctx)
{
/* Send RAB activation requests for all PDP contexts */
struct sgsn_pdp_ctx *pdp;
llist_for_each_entry(pdp, &ctx->pdp_list, list) {
iu_rab_act_ps(pdp->nsapi, pdp, 1);
}
}
/* Check if we can already authorize a subscriber */
static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
{
int rc;
#ifndef PTMSI_ALLOC
struct sgsn_signal_data sig_data;
#endif
@@ -656,6 +776,11 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
}
/* The MS is authorized */
if (ctx->ran_type == MM_CTX_T_UTRAN_Iu && !ctx->iu.ue_ctx->integrity_active) {
rc = iu_tx_sec_mode_cmd(ctx->iu.ue_ctx, &ctx->auth_triplet, 0, ctx->iu.new_key);
ctx->iu.new_key = 0;
return rc;
}
switch (ctx->pending_req) {
case 0:
@@ -663,6 +788,7 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
"no pending request, authorization completed\n");
break;
case GSM48_MT_GMM_ATTACH_REQ:
ctx->pending_req = 0;
extract_subscr_msisdn(ctx);
extract_subscr_hlr(ctx);
@@ -678,6 +804,22 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx)
#endif
return gsm48_tx_gmm_att_ack(ctx);
case GSM48_MT_GMM_SERVICE_REQ:
/* TODO: PMM State transition */
ctx->pending_req = 0;
ctx->pmm_state = PMM_CONNECTED;
rc = gsm48_tx_gmm_service_ack(ctx);
if (ctx->iu.service.type == 1) {
activate_pdp_rabs(ctx);
}
return rc;
case GSM48_MT_GMM_RA_UPD_REQ:
ctx->pending_req = 0;
/* Send RA UPDATE ACCEPT */
return gsm48_tx_gmm_ra_upd_ack(ctx);
default:
LOGMMCTXP(LOGL_ERROR, ctx,
"only Attach Request is supported yet, "
@@ -834,7 +976,7 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
uint32_t tmsi;
char mi_string[GSM48_MI_SIZE];
struct gprs_ra_id ra_id;
uint16_t cid;
uint16_t cid = 0;
enum gsm48_gmm_cause reject_cause;
int rc;
@@ -844,7 +986,8 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
* with a foreign TLLI (P-TMSI that was allocated to the MS before),
* or with random TLLI. */
cid = bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
if (!msg->dst)
cid = bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
/* MS network capability 10.5.5.12 */
msnc_len = *cur++;
@@ -853,8 +996,10 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
goto err_inval;
cur += msnc_len;
/* TODO: In iu mode - handle follow-on request */
/* aTTACH Type 10.5.5.2 */
att_type = *cur++ & 0x0f;
att_type = *cur++ & 0x07;
/* DRX parameter 10.5.5.6 */
drx_par = *cur++ << 8;
@@ -896,7 +1041,10 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
#if 0
return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_IMSI_UNKNOWN);
#else
ctx = sgsn_mm_ctx_alloc(0, &ra_id);
if (msg->dst)
ctx = sgsn_mm_ctx_alloc_iu(msg->dst);
else
ctx = sgsn_mm_ctx_alloc(0, &ra_id);
if (!ctx) {
reject_cause = GMM_CAUSE_NET_FAIL;
goto rejected;
@@ -904,8 +1052,10 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
strncpy(ctx->imsi, mi_string, sizeof(ctx->imsi) - 1);
#endif
}
ctx->tlli = msgb_tlli(msg);
ctx->llme = llme;
if (ctx->ran_type == MM_CTX_T_GERAN_Gb) {
ctx->gb.tlli = msgb_tlli(msg);
ctx->gb.llme = llme;
}
msgid2mmctx(ctx, msg);
break;
case GSM_MI_TYPE_TMSI:
@@ -917,11 +1067,16 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
if (!ctx) {
/* Allocate a context as most of our code expects one.
* Context will not have an IMSI ultil ID RESP is received */
ctx = sgsn_mm_ctx_alloc(msgb_tlli(msg), &ra_id);
if (msg->dst)
ctx = sgsn_mm_ctx_alloc_iu(msg->dst);
else
ctx = sgsn_mm_ctx_alloc(msgb_tlli(msg), &ra_id);
ctx->p_tmsi = tmsi;
}
ctx->tlli = msgb_tlli(msg);
ctx->llme = llme;
if (ctx->ran_type == MM_CTX_T_GERAN_Gb) {
ctx->gb.tlli = msgb_tlli(msg);
ctx->gb.llme = llme;
}
msgid2mmctx(ctx, msg);
break;
default:
@@ -932,7 +1087,32 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
}
/* Update MM Context with currient RA and Cell ID */
ctx->ra = ra_id;
ctx->cell_id = cid;
if (ctx->ran_type == MM_CTX_T_GERAN_Gb)
ctx->gb.cell_id = cid;
else if (ctx->ran_type == MM_CTX_T_UTRAN_Iu) {
unsigned char tmp_rand[16];
/* Ki 000102030405060708090a0b0c0d0e0f */
struct osmo_sub_auth_data auth = {
.type = OSMO_AUTH_TYPE_GSM,
.algo = OSMO_AUTH_ALG_COMP128v1,
.u.gsm.ki = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x0e, 0x0f
},
};
//ctx->iu.sac = sac;
/* XXX: Hack to make 3G auth work with special SIM card */
ctx->auth_state = SGSN_AUTH_AUTHENTICATE;
RAND_bytes(tmp_rand, 16);
memset(&ctx->auth_triplet.vec, 0, sizeof(ctx->auth_triplet.vec));
osmo_auth_gen_vec(&ctx->auth_triplet.vec, &auth, tmp_rand);
ctx->auth_triplet.key_seq = 0;
}
/* Update MM Context with other data */
ctx->drx_parms = drx_par;
ctx->ms_radio_access_capa.len = ms_ra_acc_cap_len;
@@ -950,13 +1130,16 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,
}
ctx->mm_state = GMM_COMMON_PROC_INIT;
#endif
/* Even if there is no P-TMSI allocated, the MS will switch from
* foreign TLLI to local TLLI */
ctx->tlli_new = gprs_tmsi2tlli(ctx->p_tmsi, TLLI_LOCAL);
/* Inform LLC layer about new TLLI but keep old active */
gprs_llgmm_assign(ctx->llme, ctx->tlli, ctx->tlli_new,
GPRS_ALGO_GEA0, NULL);
if (ctx->ran_type == MM_CTX_T_GERAN_Gb) {
/* Even if there is no P-TMSI allocated, the MS will
* switch from foreign TLLI to local TLLI */
ctx->gb.tlli_new = gprs_tmsi2tlli(ctx->p_tmsi, TLLI_LOCAL);
/* Inform LLC layer about new TLLI but keep old active */
gprs_llgmm_assign(ctx->gb.llme, ctx->gb.tlli, ctx->gb.tlli_new,
GPRS_ALGO_GEA0, NULL);
}
ctx->pending_req = GSM48_MT_GMM_ATTACH_REQ;
return gsm48_gmm_authorize(ctx);
@@ -1131,8 +1314,10 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
enum gsm48_gmm_cause reject_cause;
int rc;
/* TODO: In iu mode - handle follow-on request */
/* Update Type 10.5.5.18 */
upd_type = *cur++ & 0x0f;
upd_type = *cur++ & 0x07;
LOGP(DMM, LOGL_INFO, "-> GMM RA UPDATE REQUEST type=\"%s\"\n",
get_value_string(gprs_upd_t_strs, upd_type));
@@ -1165,6 +1350,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
break;
}
#warning "Differentiate look-up between Iu and Gb"
if (!mmctx) {
/* BSSGP doesn't give us an mmctx */
@@ -1174,7 +1360,24 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
* is an optimization to avoid the RA reject (impl detached)
* below, which will cause a new attach cycle. */
/* Look-up the MM context based on old RA-ID and TLLI */
mmctx = sgsn_mm_ctx_by_tlli_and_ptmsi(msgb_tlli(msg), &old_ra_id);
if (!msg->dst) {
mmctx = sgsn_mm_ctx_by_tlli_and_ptmsi(msgb_tlli(msg), &old_ra_id);
} else if (TLVP_PRESENT(&tp, GSM48_IE_GMM_ALLOC_PTMSI)) {
/* In Iu mode search only for ptmsi */
char mi_string[GSM48_MI_SIZE];
uint8_t mi_len = TLVP_LEN(&tp, GSM48_IE_GMM_ALLOC_PTMSI);
uint8_t *mi = TLVP_VAL(&tp, GSM48_IE_GMM_ALLOC_PTMSI);
uint8_t mi_type = *mi & GSM_MI_TYPE_MASK;
uint32_t tmsi;
gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
if (mi_type == GSM_MI_TYPE_TMSI) {
memcpy(&tmsi, mi+1, 4);
tmsi = ntohl(tmsi);
mmctx = sgsn_mm_ctx_by_ptmsi(tmsi);
}
}
if (mmctx) {
LOGMMCTXP(LOGL_INFO, mmctx,
"Looked up by matching TLLI and P_TMSI. "
@@ -1182,7 +1385,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
"TLLI: %08x (%08x), RA: %d-%d-%d-%d\n",
msgb_tlli(msg),
mmctx->p_tmsi, mmctx->p_tmsi_old,
mmctx->tlli, mmctx->tlli_new,
mmctx->gb.tlli, mmctx->gb.tlli_new,
mmctx->ra.mcc, mmctx->ra.mnc,
mmctx->ra.lac, mmctx->ra.rac);
@@ -1200,10 +1403,12 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
}
if (!mmctx) {
/* send a XID reset to re-set all LLC sequence numbers
* in the MS */
LOGMMCTXP(LOGL_NOTICE, mmctx, "LLC XID RESET\n");
gprs_llgmm_reset(llme);
if (llme) {
/* send a XID reset to re-set all LLC sequence numbers
* in the MS */
LOGMMCTXP(LOGL_NOTICE, mmctx, "LLC XID RESET\n");
gprs_llgmm_reset(llme);
}
/* The MS has to perform GPRS attach */
/* Device is still IMSI attached for CS but initiate GPRS ATTACH,
* see GSM 04.08, 4.7.5.1.4 and G.6 */
@@ -1217,9 +1422,12 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
/* Update the MM context with the new RA-ID */
bssgp_parse_cell_id(&mmctx->ra, msgb_bcid(msg));
/* Update the MM context with the new (i.e. foreign) TLLI */
mmctx->tlli = msgb_tlli(msg);
#warning "how to obtain RA_ID in Iu case?"
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
bssgp_parse_cell_id(&mmctx->ra, msgb_bcid(msg));
/* Update the MM context with the new (i.e. foreign) TLLI */
mmctx->gb.tlli = msgb_tlli(msg);
}
/* FIXME: Update the MM context with the MS radio acc capabilities */
/* FIXME: Update the MM context with the MS network capabilities */
@@ -1244,13 +1452,16 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
sig_data.mm = mmctx;
osmo_signal_dispatch(SS_SGSN, S_SGSN_UPDATE, &sig_data);
#endif
/* Even if there is no P-TMSI allocated, the MS will switch from
* foreign TLLI to local TLLI */
mmctx->tlli_new = gprs_tmsi2tlli(mmctx->p_tmsi, TLLI_LOCAL);
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
/* Even if there is no P-TMSI allocated, the MS will switch from
* foreign TLLI to local TLLI */
mmctx->gb.tlli_new = gprs_tmsi2tlli(mmctx->p_tmsi, TLLI_LOCAL);
/* Inform LLC layer about new TLLI but keep old active */
gprs_llgmm_assign(mmctx->llme, mmctx->tlli, mmctx->tlli_new,
GPRS_ALGO_GEA0, NULL);
/* Inform LLC layer about new TLLI but keep old active */
gprs_llgmm_assign(mmctx->gb.llme, mmctx->gb.tlli,
mmctx->gb.tlli_new, GPRS_ALGO_GEA0,
NULL);
}
/* Look at PDP Context Status IE and see if MS's view of
* activated/deactivated NSAPIs agrees with our view */
@@ -1259,8 +1470,9 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
process_ms_ctx_status(mmctx, pdp_status);
}
mmctx->pending_req = GSM48_MT_GMM_RA_UPD_REQ;
/* Send RA UPDATE ACCEPT */
return gsm48_tx_gmm_ra_upd_ack(mmctx);
return gsm48_gmm_authorize(mmctx);
rejected:
/* Send RA UPDATE REJECT */
@@ -1270,14 +1482,126 @@ rejected:
rc = gsm48_tx_gmm_ra_upd_rej(msg, reject_cause);
if (mmctx)
mm_ctx_cleanup_free(mmctx, "GPRS RA UPDATE REJ");
else
/* TLLI unassignment */
gprs_llgmm_assign(llme, llme->tlli, 0xffffffff, GPRS_ALGO_GEA0,
NULL);
else {
if (llme) {
/* TLLI unassignment */
gprs_llgmm_assign(llme, llme->tlli, 0xffffffff,
GPRS_ALGO_GEA0, NULL);
}
}
return rc;
}
/* 3GPP TS 24.008 Section 9.4.20 Service request */
static int gsm48_rx_gmm_service_req(struct sgsn_mm_ctx *ctx, struct msgb *msg)
{
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
uint8_t *cur = gh->data, *mi;
uint8_t ciph_seq_nr, service_type, mi_len, mi_type;
uint32_t tmsi;
struct tlv_parsed tp;
char mi_string[GSM48_MI_SIZE];
uint16_t cid = 0;
enum gsm48_gmm_cause reject_cause;
int rc;
LOGMMCTXP(LOGL_INFO, ctx, "-> GMM SERVICE REQUEST ");
/* This message is only valid in Iu mode */
if (!msg->dst) {
LOGPC(DMM, LOGL_INFO, "Invalid if not in Iu mode\n");
return -1;
}
/* Skip Ciphering key sequence number 10.5.1.2 */
ciph_seq_nr = *cur & 0x07;
/* Service type 10.5.5.20 */
service_type = (*cur++ >> 4) & 0x07;
/* Mobile Identity (P-TMSI or IMSI) 10.5.1.4 */
mi_len = *cur++;
mi = cur;
if (mi_len > 8)
goto err_inval;
mi_type = *mi & GSM_MI_TYPE_MASK;
cur += mi_len;
gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
DEBUGPC(DMM, "MI(%s) type=\"%s\" ", mi_string,
get_value_string(gprs_service_t_strs, service_type));
LOGPC(DMM, LOGL_INFO, "\n");
/* Optional: PDP context status, MBMS context status, Uplink data status, Device properties */
tlv_parse(&tp, &gsm48_gmm_att_tlvdef, cur, (msg->data + msg->len) - cur, 0, 0);
switch (mi_type) {
case GSM_MI_TYPE_IMSI:
/* Try to find MM context based on IMSI */
if (!ctx)
ctx = sgsn_mm_ctx_by_imsi(mi_string);
if (!ctx) {
/* FIXME: We need to have a context for service request? */
reject_cause = GMM_CAUSE_NET_FAIL;
goto rejected;
}
msgid2mmctx(ctx, msg);
break;
case GSM_MI_TYPE_TMSI:
memcpy(&tmsi, mi+1, 4);
tmsi = ntohl(tmsi);
/* Try to find MM context based on P-TMSI */
if (!ctx)
ctx = sgsn_mm_ctx_by_ptmsi(tmsi);
if (!ctx) {
/* FIXME: We need to have a context for service request? */
reject_cause = GMM_CAUSE_NET_FAIL;
goto rejected;
}
msgid2mmctx(ctx, msg);
break;
default:
LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting SERVICE REQUEST with "
"MI type %s\n", gsm48_mi_type_name(mi_type));
reject_cause = GMM_CAUSE_MS_ID_NOT_DERIVED;
goto rejected;
}
ctx->mm_state = GMM_COMMON_PROC_INIT;
ctx->iu.service.type = service_type;
/* TODO: Handle those only in case of accept? */
/* Look at PDP Context Status IE and see if MS's view of
* activated/deactivated NSAPIs agrees with our view */
if (TLVP_PRESENT(&tp, GSM48_IE_GMM_PDP_CTX_STATUS)) {
const uint8_t *pdp_status = TLVP_VAL(&tp, GSM48_IE_GMM_PDP_CTX_STATUS);
process_ms_ctx_status(ctx, pdp_status);
}
ctx->pending_req = GSM48_MT_GMM_SERVICE_REQ;
return gsm48_gmm_authorize(ctx);
err_inval:
LOGPC(DMM, LOGL_INFO, "\n");
reject_cause = GMM_CAUSE_SEM_INCORR_MSG;
rejected:
/* Send SERVICE REJECT */
LOGMMCTXP(LOGL_NOTICE, ctx,
"Rejecting Service Request with cause '%s' (%d)\n",
get_value_string(gsm48_gmm_cause_names, reject_cause), reject_cause);
rc = gsm48_tx_gmm_service_rej_oldmsg(msg, reject_cause);
return rc;
}
static int gsm48_rx_gmm_status(struct sgsn_mm_ctx *mmctx, struct msgb *msg)
{
struct gsm48_hdr *gh = msgb_l3(msg);
@@ -1298,7 +1622,7 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
/* MMCTX can be NULL when called */
if (!mmctx &&
if (llme && !mmctx &&
gh->msg_type != GSM48_MT_GMM_ATTACH_REQ &&
gh->msg_type != GSM48_MT_GMM_RA_UPD_REQ) {
LOGP(DMM, LOGL_NOTICE, "Cannot handle GMM for unknown MM CTX\n");
@@ -1346,7 +1670,20 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
case GSM48_MT_GMM_ATTACH_REQ:
rc = gsm48_rx_gmm_att_req(mmctx, msg, llme);
break;
case GSM48_MT_GMM_SERVICE_REQ:
rc = gsm48_rx_gmm_service_req(mmctx, msg);
break;
default:
break;
}
/* For all the following types mmctx can not be NULL */
if (!mmctx) {
/* FIXME: return some error? */
return -1;
}
switch (gh->msg_type) {
case GSM48_MT_GMM_ID_RESP:
rc = gsm48_rx_gmm_id_resp(mmctx, msg);
break;
@@ -1368,11 +1705,15 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
mmctx->t3350_mode = GMM_T3350_MODE_NONE;
mmctx->p_tmsi_old = 0;
mmctx->pending_req = 0;
/* Unassign the old TLLI */
mmctx->tlli = mmctx->tlli_new;
gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new,
GPRS_ALGO_GEA0, NULL);
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
/* Unassign the old TLLI */
mmctx->gb.tlli = mmctx->gb.tlli_new;
gprs_llgmm_assign(mmctx->gb.llme, 0xffffffff,
mmctx->gb.tlli_new,
GPRS_ALGO_GEA0, NULL);
}
mmctx->mm_state = GMM_REGISTERED_NORMAL;
mmctx->pmm_state = PMM_CONNECTED;
rc = 0;
memset(&sig_data, 0, sizeof(sig_data));
@@ -1386,11 +1727,15 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
mmctx->t3350_mode = GMM_T3350_MODE_NONE;
mmctx->p_tmsi_old = 0;
mmctx->pending_req = 0;
/* Unassign the old TLLI */
mmctx->tlli = mmctx->tlli_new;
gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new,
GPRS_ALGO_GEA0, NULL);
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
/* Unassign the old TLLI */
mmctx->gb.tlli = mmctx->gb.tlli_new;
gprs_llgmm_assign(mmctx->gb.llme, 0xffffffff, mmctx->gb.tlli_new,
GPRS_ALGO_GEA0, NULL);
}
mmctx->mm_state = GMM_REGISTERED_NORMAL;
mmctx->pmm_state = PMM_CONNECTED;
activate_pdp_rabs(mmctx);
rc = 0;
memset(&sig_data, 0, sizeof(sig_data));
@@ -1403,9 +1748,11 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg,
mmctx->t3350_mode = GMM_T3350_MODE_NONE;
mmctx->p_tmsi_old = 0;
mmctx->pending_req = 0;
/* Unassign the old TLLI */
mmctx->tlli = mmctx->tlli_new;
//gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new, GPRS_ALGO_GEA0, NULL);
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb) {
/* Unassign the old TLLI */
mmctx->gb.tlli = mmctx->gb.tlli_new;
//gprs_llgmm_assign(mmctx->gb.llme, 0xffffffff, mmctx->gb.tlli_new, GPRS_ALGO_GEA0, NULL);
}
rc = 0;
break;
case GSM48_MT_GMM_AUTH_CIPH_RESP:
@@ -2077,7 +2424,8 @@ int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg)
int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx)
{
int rc;
gprs_llgmm_reset(mmctx->llme);
if (mmctx->ran_type == MM_CTX_T_GERAN_Gb)
gprs_llgmm_reset(mmctx->gb.llme);
rc = gsm48_tx_gmm_detach_req(
mmctx, GPRS_DET_T_MT_REATT_REQ, GMM_CAUSE_IMPL_DETACHED);
@@ -2087,8 +2435,50 @@ int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx)
return rc;
}
/* Main entry point for incoming 04.08 GPRS messages */
int gsm0408_gprs_rcvmsg(struct msgb *msg, struct gprs_llc_llme *llme)
/* Main entry point for incoming 04.08 GPRS messages from Iu */
int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id,
uint16_t *sai)
{
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
uint8_t pdisc = gsm48_hdr_pdisc(gh);
struct sgsn_mm_ctx *mmctx;
int rc = -EINVAL;
DEBUGP(DMM, "grps_rcvmsg_iu(%s)\n", osmo_hexdump(msgb_gmmh(msg), msgb_l3len(msg)));
mmctx = sgsn_mm_ctx_by_ue_ctx(msg->dst);
if (mmctx) {
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
if (ra_id)
memcpy(&mmctx->ra, ra_id, sizeof(mmctx->ra));
//if (sai)
//mmctx->iu.sai = *sai;
}
/* MMCTX can be NULL */
switch (pdisc) {
case GSM48_PDISC_MM_GPRS:
rc = gsm0408_rcv_gmm(mmctx, msg, NULL);
break;
case GSM48_PDISC_SM_GPRS:
rc = gsm0408_rcv_gsm(mmctx, msg, NULL);
break;
default:
LOGMMCTXP(LOGL_NOTICE, mmctx,
"Unknown GSM 04.08 discriminator 0x%02x: %s\n",
pdisc, osmo_hexdump((uint8_t *)gh, msgb_l3len(msg)));
/* FIXME: return status message */
break;
}
/* MMCTX can be invalid */
return rc;
}
/* Main entry point for incoming 04.08 GPRS messages from Gb */
int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme)
{
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg);
uint8_t pdisc = gsm48_hdr_pdisc(gh);
@@ -2101,7 +2491,7 @@ int gsm0408_gprs_rcvmsg(struct msgb *msg, struct gprs_llc_llme *llme)
if (mmctx) {
msgid2mmctx(mmctx, msg);
rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]);
mmctx->llme = llme;
mmctx->gb.llme = llme;
}
/* MMCTX can be NULL */

View File

@@ -56,8 +56,8 @@ static int _bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx)
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);
OSMO_ASSERT(msgb_tlli(msg) == mmctx->gb.llme->tlli
|| msgb_tlli(msg) == mmctx->gb.llme->old_tlli);
}
memcpy(&dup.qos_profile, qos_profile_default,
sizeof(qos_profile_default));
@@ -663,7 +663,7 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv)
switch (llhp.sapi) {
case GPRS_SAPI_GMM:
/* send LL_UNITDATA_IND to GMM */
rc = gsm0408_gprs_rcvmsg(msg, lle->llme);
rc = gsm0408_gprs_rcvmsg_gb(msg, lle->llme);
break;
case GPRS_SAPI_SNDCP3:
case GPRS_SAPI_SNDCP5:

View File

@@ -39,6 +39,9 @@
#include <openbsc/gprs_utils.h>
#include <openbsc/signal.h>
#include "openbsc/gprs_llc.h"
#include <openbsc/iu.h>
#include <pdp.h>
#include <time.h>
@@ -90,6 +93,19 @@ static const struct rate_ctr_group_desc pdpctx_ctrg_desc = {
.class_id = OSMO_STATS_CLASS_SUBSCRIBER,
};
/* look-up a SGSN MM context based on TLLI + RAI */
struct sgsn_mm_ctx *sgsn_mm_ctx_by_ue_ctx(const void *uectx)
{
struct sgsn_mm_ctx *ctx;
llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
if (ctx->ran_type == MM_CTX_T_UTRAN_Iu && uectx == ctx->iu.ue_ctx)
return ctx;
}
return NULL;
}
/* 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)
@@ -97,7 +113,7 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli,
struct sgsn_mm_ctx *ctx;
llist_for_each_entry(ctx, &sgsn_mm_ctxts, list) {
if ((tlli == ctx->tlli || tlli == ctx->tlli_new) &&
if ((tlli == ctx->gb.tlli || tlli == ctx->gb.tlli_new) &&
gprs_ra_id_equals(raid, &ctx->ra))
return ctx;
}
@@ -165,7 +181,8 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli,
return NULL;
memcpy(&ctx->ra, raid, sizeof(ctx->ra));
ctx->tlli = tlli;
ctx->ran_type = MM_CTX_T_GERAN_Gb;
ctx->gb.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);
@@ -176,6 +193,34 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli,
return ctx;
}
/* Allocate a new SGSN MM context */
struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx)
{
struct sgsn_mm_ctx *ctx;
ctx = talloc_zero(tall_bsc_ctx, struct sgsn_mm_ctx);
if (!ctx)
return NULL;
ctx->ran_type = MM_CTX_T_UTRAN_Iu;
ctx->iu.ue_ctx = uectx;
ctx->iu.new_key = 1;
ctx->mm_state = GMM_DEREGISTERED;
ctx->pmm_state = PMM_DETACHED;
ctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL;
ctx->ctrg = rate_ctr_group_alloc(ctx, &mmctx_ctrg_desc, 0);
/* Need to get RAID from IU conn */
ctx->ra = ctx->iu.ue_ctx->ra_id;
INIT_LLIST_HEAD(&ctx->pdp_list);
llist_add(&ctx->list, &sgsn_mm_ctxts);
return ctx;
}
/* this is a hard _free_ function, it doesn't clean up the PDP contexts
* in libgtp! */
static void sgsn_mm_ctx_free(struct sgsn_mm_ctx *mm)
@@ -196,10 +241,11 @@ static void sgsn_mm_ctx_free(struct sgsn_mm_ctx *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 gprs_llc_llme *llme = mm->gb.llme;
uint32_t tlli = mm->gb.tlli;
struct sgsn_pdp_ctx *pdp, *pdp2;
struct sgsn_signal_data sig_data;
enum sgsn_ran_type ran_type;
/* Forget about ongoing look-ups */
if (mm->ggsn_lookup) {
@@ -233,11 +279,15 @@ void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *mm)
subscr_put(subscr);
}
ran_type = mm->ran_type;
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);
if (ran_type == MM_CTX_T_GERAN_Gb) {
/* TLLI unassignment, must be called after sgsn_mm_ctx_free */
gprs_llgmm_assign(llme, tlli, 0xffffffff, GPRS_ALGO_GEA0, NULL);
}
}
@@ -290,7 +340,6 @@ struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm,
return pdp;
}
#include <pdp.h>
/*
* 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
@@ -307,8 +356,10 @@ void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp)
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);
if (pdp->mm->ran_type == MM_CTX_T_GERAN_Gb) {
/* Force the deactivation of the SNDCP layer */
sndcp_sm_deactivate_ind(&pdp->mm->gb.llme->lle[pdp->sapi], pdp->nsapi);
}
memset(&sig_data, 0, sizeof(sig_data));
sig_data.pdp = pdp;
@@ -751,7 +802,7 @@ 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) {
if (llme == mmctx->gb.llme) {
gsm0408_gprs_access_cancelled(mmctx, SGSN_ERROR_CAUSE_NONE);
return;
}

View File

@@ -0,0 +1,37 @@
/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2010 by On-Waves
* (C) 2014-2015 by Sysmocom s.f.m.c. GmbH
*
* 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/>.
*
*/
/* TODO: Move this to osmocom/gsm/protocol/gsm_04_08_gprs.h ? */
#include <openbsc/gsm_04_08_gprs.h>
#include <osmocom/core/utils.h>
const struct value_string gprs_service_t_strs_[] = {
{ GPRS_SERVICE_T_SIGNALLING, "signalling" },
{ GPRS_SERVICE_T_DATA, "data" },
{ GPRS_SERVICE_T_PAGING_RESP, "paging response" },
{ GPRS_SERVICE_T_MBMS_MC_SERV, "MBMS multicast service" },
{ GPRS_SERVICE_T_MBMS_BC_SERV, "MBMS broadcast service" },
{ 0, NULL }
};
const struct value_string *gprs_service_t_strs = gprs_service_t_strs_;

View File

@@ -1,14 +1,38 @@
!
! Osmocom SGSN (0.9.0.474-0ede2) configuration saved from vty
! OsmoSGSN (0.15.0.145-a710-dirty) configuration saved from vty
!!
!
log stderr
logging filter all 1
logging color 1
logging print category 0
logging timestamp 0
logging level all everything
logging level mm debug
logging level pag notice
logging level meas notice
logging level ref notice
logging level gprs debug
logging level ns info
logging level bssgp debug
logging level llc debug
logging level sndcp debug
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
logging level lctrl notice
logging level lgtp notice
logging level lstats notice
!
stats interval 5
!
line vty
no login
!
sgsn
gtp local-ip 192.168.100.11
ggsn 0 remote-ip 192.168.100.239
ggsn 0 gtp-version 1
ns
timer tns-block 3
timer tns-block-retries 3
@@ -17,7 +41,30 @@ ns
timer tns-test 30
timer tns-alive 3
timer tns-alive-retries 10
encapsulation udp local-ip 192.168.100.11
encapsulation udp local-ip 192.168.0.51
encapsulation udp local-port 23000
encapsulation framerelay-gre enabled 0
bssgp
sgsn
gtp local-ip 127.0.0.2
ggsn 0 remote-ip 192.168.0.51
ggsn 0 gtp-version 1
auth-policy closed
gsup oap-id 0
imsi-acl add 262032312854076
imsi-acl add 262778026147135
! apn * ggsn 0
no cdr filename
cdr interval 600
timer t3312 600
timer t3322 6
timer t3350 6
timer t3360 6
timer t3370 6
timer t3313 30
timer t3314 44
timer t3316 44
timer t3385 8
timer t3386 8
timer t3395 8
timer t3397 8

View File

@@ -94,7 +94,7 @@ static void cdr_log_mm(struct sgsn_instance *inst, const char *ev,
mmctx->imsi,
mmctx->imei,
mmctx->msisdn,
mmctx->cell_id,
mmctx->gb.cell_id,
mmctx->ra.lac,
mmctx->hlr,
ev);
@@ -179,7 +179,7 @@ static void cdr_log_pdp(struct sgsn_instance *inst, const char *ev,
pdp->mm ? pdp->mm->imsi : "N/A",
pdp->mm ? pdp->mm->imei : "N/A",
pdp->mm ? pdp->mm->msisdn : "N/A",
pdp->mm ? pdp->mm->cell_id : -1,
pdp->mm ? pdp->mm->gb.cell_id : -1,
pdp->mm ? pdp->mm->ra.lac : -1,
pdp->mm ? pdp->mm->hlr : "N/A",
ev,

View File

@@ -37,6 +37,7 @@
#include <osmocom/core/talloc.h>
#include <osmocom/core/select.h>
#include <osmocom/core/rate_ctr.h>
#include <osmocom/crypt/auth.h>
#include <osmocom/gprs/gprs_bssgp.h>
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
@@ -47,6 +48,11 @@
#include <openbsc/gprs_sgsn.h>
#include <openbsc/gprs_gmm.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/iu.h>
#include <osmocom/ranap/ranap_ies_defs.h>
#include <asn1c/asn1helpers.h>
#include <gtp.h>
#include <pdp.h>
@@ -218,7 +224,10 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
memcpy(pdp->gsnlc.v, &sgsn->cfg.gtp_listenaddr.sin_addr,
sizeof(sgsn->cfg.gtp_listenaddr.sin_addr));
/* SGSN address for user plane */
/* SGSN address for user plane
* Default to the control plane addr for now. If we are connected to a
* hnbgw via IuPS we'll need to send a PDP context update with the
* correct IP address after the RAB Assignment is complete */
pdp->gsnlu.l = sizeof(sgsn->cfg.gtp_listenaddr.sin_addr);
memcpy(pdp->gsnlu.v, &sgsn->cfg.gtp_listenaddr.sin_addr,
sizeof(sgsn->cfg.gtp_listenaddr.sin_addr));
@@ -239,7 +248,7 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn,
pdp->userloc_given = 1;
pdp->userloc.l = 8;
pdp->userloc.v[0] = 0; /* CGI for GERAN */
bssgp_create_cell_id(&pdp->userloc.v[1], &mmctx->ra, mmctx->cell_id);
bssgp_create_cell_id(&pdp->userloc.v[1], &mmctx->ra, mmctx->gb.cell_id);
/* include the IMEI(SV) */
pdp->imeisv_given = 1;
@@ -304,6 +313,19 @@ static const struct cause_map gtp2sm_cause_map[] = {
{ 0, 0 }
};
static int send_act_pdp_cont_acc(struct sgsn_pdp_ctx *pctx)
{
struct sgsn_signal_data sig_data;
/* Inform others about it */
memset(&sig_data, 0, sizeof(sig_data));
sig_data.pdp = pctx;
osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_ACT, &sig_data);
/* Send PDP CTX ACT to MS */
return gsm48_tx_gsm_act_pdp_acc(pctx);
}
/* The GGSN has confirmed the creation of a PDP Context */
static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
{
@@ -340,16 +362,17 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
goto reject;
}
/* Activate the SNDCP layer */
sndcp_sm_activate_ind(&pctx->mm->llme->lle[pctx->sapi], pctx->nsapi);
if (pctx->mm->ran_type == MM_CTX_T_GERAN_Gb) {
/* Activate the SNDCP layer */
sndcp_sm_activate_ind(&pctx->mm->gb.llme->lle[pctx->sapi], pctx->nsapi);
/* Inform others about it */
memset(&sig_data, 0, sizeof(sig_data));
sig_data.pdp = pctx;
osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_ACT, &sig_data);
/* Send PDP CTX ACT to MS */
return gsm48_tx_gsm_act_pdp_acc(pctx);
return send_act_pdp_cont_acc(pctx);
} else {
/* Activate a radio bearer */
iu_rab_act_ps(pdp->nsapi, pctx, 1);
return 0;
}
reject:
/*
@@ -372,6 +395,70 @@ reject:
return EOF;
}
/* Callback for RAB assignment response */
int sgsn_ranap_rab_ass_resp(struct sgsn_mm_ctx *ctx, RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies)
{
uint8_t rab_id;
bool require_pdp_update = false;
struct sgsn_pdp_ctx *pdp = NULL;
RANAP_RAB_SetupOrModifiedItem_t *item = &setup_ies->raB_SetupOrModifiedItem;
rab_id = item->rAB_ID.buf[0];
pdp = sgsn_pdp_ctx_by_nsapi(ctx, rab_id);
if (!pdp) {
LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Response for unknown RAB/NSAPI=%u\n", rab_id);
return -1;
}
if (item->transportLayerAddress) {
LOGPC(DRANAP, LOGL_INFO, " Setup: (%u/%s)", rab_id, osmo_hexdump(item->transportLayerAddress->buf,
item->transportLayerAddress->size));
switch (item->transportLayerAddress->size) {
case 7:
/* It must be IPv4 inside a X213 NSAP */
memcpy(pdp->lib->gsnlu.v, &item->transportLayerAddress->buf[3], 4);
break;
case 4:
/* It must be a raw IPv4 address */
memcpy(pdp->lib->gsnlu.v, item->transportLayerAddress->buf, 4);
break;
case 16:
/* TODO: It must be a raw IPv6 address */
case 19:
/* TODO: It must be IPv6 inside a X213 NSAP */
default:
LOGP(DRANAP, LOGL_ERROR, "RAB Assignment Resp: Unknown "
"transport layer address size %u\n",
item->transportLayerAddress->size);
return -1;
}
require_pdp_update = true;
}
/* The TEI on the RNC side might have changed, too */
if (item->iuTransportAssociation &&
item->iuTransportAssociation->present == RANAP_IuTransportAssociation_PR_gTP_TEI &&
item->iuTransportAssociation->choice.gTP_TEI.buf &&
item->iuTransportAssociation->choice.gTP_TEI.size >= 4) {
uint32_t tei = osmo_load32be(item->iuTransportAssociation->choice.gTP_TEI.buf);
LOGP(DRANAP, LOGL_DEBUG, "Updating TEID on RNC side from 0x%08x to 0x%08x\n",
pdp->lib->teid_own, tei);
pdp->lib->teid_own = tei;
require_pdp_update = true;
}
if (require_pdp_update)
gtp_update_context(pdp->ggsn->gsn, pdp->lib, pdp, &pdp->lib->hisaddr0);
if (pdp->state != PDP_STATE_CR_CONF) {
send_act_pdp_cont_acc(pdp);
pdp->state = PDP_STATE_CR_CONF;
}
return 0;
}
/* Confirmation of a PDP Context Delete */
static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
{
@@ -387,8 +474,13 @@ static int delete_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
osmo_signal_dispatch(SS_SGSN, S_SGSN_PDP_DEACT, &sig_data);
if (pctx->mm) {
/* Deactivate the SNDCP layer */
sndcp_sm_deactivate_ind(&pctx->mm->llme->lle[pctx->sapi], pctx->nsapi);
if (pctx->mm->ran_type == MM_CTX_T_GERAN_Gb) {
/* Deactivate the SNDCP layer */
sndcp_sm_deactivate_ind(&pctx->mm->gb.llme->lle[pctx->sapi], pctx->nsapi);
} else {
/* Dectivate a radio bearer */
iu_rab_deact(pctx->mm->iu.ue_ctx, 1);
}
/* Confirm deactivation of PDP context to MS */
rc = gsm48_tx_gsm_deact_pdp_acc(pctx);
@@ -521,9 +613,9 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
ud = msgb_put(msg, len);
memcpy(ud, packet, len);
msgb_tlli(msg) = mm->tlli;
msgb_bvci(msg) = mm->bvci;
msgb_nsei(msg) = mm->nsei;
msgb_tlli(msg) = mm->gb.tlli;
msgb_bvci(msg) = mm->gb.bvci;
msgb_nsei(msg) = mm->gb.nsei;
switch (mm->mm_state) {
case GMM_REGISTERED_SUSPENDED:
@@ -531,12 +623,12 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
memset(&pinfo, 0, sizeof(pinfo));
pinfo.mode = BSSGP_PAGING_PS;
pinfo.scope = BSSGP_PAGING_BVCI;
pinfo.bvci = mm->bvci;
pinfo.bvci = mm->gb.bvci;
pinfo.imsi = mm->imsi;
pinfo.ptmsi = &mm->p_tmsi;
pinfo.drx_params = mm->drx_parms;
pinfo.qos[0] = 0; // FIXME
bssgp_tx_paging(mm->nsei, 0, &pinfo);
bssgp_tx_paging(mm->gb.nsei, 0, &pinfo);
rate_ctr_inc(&mm->ctrg->ctr[GMM_CTR_PAGING_PS]);
/* FIXME: queue the packet we received from GTP */
break;
@@ -544,7 +636,7 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
break;
default:
LOGP(DGPRS, LOGL_ERROR, "GTP DATA IND for TLLI %08X in state "
"%u\n", mm->tlli, mm->mm_state);
"%u\n", mm->gb.tlli, mm->mm_state);
msgb_free(msg);
return -1;
}
@@ -557,7 +649,7 @@ static int cb_data_ind(struct pdp_t *lib, void *packet, unsigned int len)
/* It is easier to have a global count */
pdp->cdr_bytes_out += len;
return sndcp_unitdata_req(msg, &mm->llme->lle[pdp->sapi],
return sndcp_unitdata_req(msg, &mm->gb.llme->lle[pdp->sapi],
pdp->nsapi, mm);
}

View File

@@ -55,6 +55,8 @@
#include <openbsc/sgsn.h>
#include <openbsc/gprs_llc.h>
#include <openbsc/gprs_gmm.h>
#include <openbsc/iu.h>
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/ports.h>
@@ -232,6 +234,8 @@ static void handle_options(int argc, char **argv)
}
}
extern int asn_debug;
/* default categories */
static struct log_info_cat gprs_categories[] = {
[DMM] = {
@@ -281,6 +285,16 @@ static struct log_info_cat gprs_categories[] = {
.description = "GPRS Sub-Network Dependent Control Protocol (SNDCP)",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DSUA] = {
.name = "DSUA",
.description = "SCCP User Adaptation (SUA)",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DRANAP] = {
.name = "DRANAP",
.description = "RAN Application Part (RANAP)",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
};
static const struct log_info gprs_log_info = {
@@ -289,6 +303,9 @@ static const struct log_info gprs_log_info = {
.num_cat = ARRAY_SIZE(gprs_categories),
};
int asn_debug;
int sgsn_ranap_iu_event(struct ue_conn_ctx *ctx, enum iu_event_type type, void *data);
int main(int argc, char **argv)
{
@@ -404,6 +421,9 @@ int main(int argc, char **argv)
}
}
asn_debug = 0;
iu_init(tall_bsc_ctx, "127.0.0.2", 14001, gsm0408_gprs_rcvmsg_iu, sgsn_ranap_iu_event);
if (daemonize) {
rc = osmo_daemonize();
if (rc < 0) {

View File

@@ -431,12 +431,12 @@ static void vty_dump_mmctx(struct vty *vty, const char *pfx,
vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s",
pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE);
vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s HLR: %s",
pfx, mm->msisdn, mm->tlli, mm->hlr, VTY_NEWLINE);
pfx, mm->msisdn, mm->gb.tlli, mm->hlr, VTY_NEWLINE);
vty_out(vty, "%s MM State: %s, Routeing Area: %u-%u-%u-%u, "
"Cell ID: %u%s", pfx,
get_value_string(gprs_mm_st_strs, mm->mm_state),
mm->ra.mcc, mm->ra.mnc, mm->ra.lac, mm->ra.rac,
mm->cell_id, VTY_NEWLINE);
mm->gb.cell_id, VTY_NEWLINE);
vty_out_rate_ctr_group(vty, " ", mm->ctrg);

View File

@@ -6,8 +6,7 @@ OSMO_LIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOABIS_LIBS)
bin_PROGRAMS = abisip-find ipaccess-config ipaccess-proxy
abisip_find_LDADD = $(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libmsc/libmsc.a \
$(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libxsc/libxsc.a \
$(top_builddir)/src/libtrau/libtrau.a \
$(top_builddir)/src/libcommon/libcommon.a \
$(OSMO_LIBS)
@@ -17,15 +16,14 @@ ipaccess_config_SOURCES = ipaccess-config.c ipaccess-firmware.c network_listen.c
# FIXME: resolve the bogus dependencies patched around here:
ipaccess_config_LDADD = $(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libxsc/libxsc.a \
$(top_builddir)/src/libtrau/libtrau.a \
$(top_builddir)/src/libcommon/libcommon.a \
$(LIBCRYPT) $(OSMO_LIBS)
ipaccess_proxy_SOURCES = ipaccess-proxy.c
ipaccess_proxy_LDADD = $(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libmsc/libmsc.a \
$(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libxsc/libxsc.a \
$(top_builddir)/src/libtrau/libtrau.a \
$(top_builddir)/src/libcommon/libcommon.a \
$(OSMO_LIBS)

View File

@@ -983,7 +983,7 @@ int main(int argc, char **argv)
}
libosmo_abis_init(tall_ctx_config);
bsc_gsmnet = gsm_network_init(1, 1, NULL);
bsc_gsmnet = gsm_network_init(tall_bsc_ctx, 1, 1, NULL);
if (!bsc_gsmnet)
exit(1);

View File

@@ -20,6 +20,7 @@ libbsc_a_SOURCES = abis_nm.c abis_nm_vty.c \
e1_config.c \
bsc_api.c bsc_msc.c bsc_vty.c \
gsm_04_08_utils.c \
gsm_04_80_utils.c \
bsc_init.c bts_init.c bsc_rf_ctrl.c \
arfcn_range_encode.c bsc_ctrl_commands.c \
bsc_ctrl_lookup.c \

View File

@@ -94,7 +94,7 @@ DEFUN(oml_class_inst, oml_class_inst_cmd,
struct oml_node_state *oms;
int bts_nr = atoi(argv[0]);
bts = gsm_bts_num(bsc_gsmnet, bts_nr);
bts = gsm_bts_num(gsmnet_from_vty(vty), bts_nr);
if (!bts) {
vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
return CMD_WARNING;
@@ -128,7 +128,7 @@ DEFUN(oml_classnum_inst, oml_classnum_inst_cmd,
struct oml_node_state *oms;
int bts_nr = atoi(argv[0]);
bts = gsm_bts_num(bsc_gsmnet, bts_nr);
bts = gsm_bts_num(gsmnet_from_vty(vty), bts_nr);
if (!bts) {
vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
return CMD_WARNING;

View File

@@ -82,7 +82,7 @@ DEFUN(om2k_class_inst, om2k_class_inst_cmd,
struct oml_node_state *oms;
int bts_nr = atoi(argv[0]);
bts = gsm_bts_num(bsc_gsmnet, bts_nr);
bts = gsm_bts_num(gsmnet_from_vty(vty), bts_nr);
if (!bts) {
vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
return CMD_WARNING;
@@ -122,7 +122,7 @@ DEFUN(om2k_classnum_inst, om2k_classnum_inst_cmd,
struct oml_node_state *oms;
int bts_nr = atoi(argv[0]);
bts = gsm_bts_num(bsc_gsmnet, bts_nr);
bts = gsm_bts_num(gsmnet_from_vty(vty), bts_nr);
if (!bts) {
vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
return CMD_WARNING;

View File

@@ -1048,7 +1048,7 @@ static void print_meas_rep(struct gsm_lchan *lchan, struct gsm_meas_rep *mr)
int i;
char *name = "";
if (lchan && lchan->conn && lchan->conn->subscr)
if (lchan && lchan->conn)
name = subscr_name(lchan->conn->subscr);
DEBUGP(DMEAS, "[%s] MEASUREMENT RESULT NR=%d ", name, mr->nr);
@@ -1087,6 +1087,19 @@ static void print_meas_rep(struct gsm_lchan *lchan, struct gsm_meas_rep *mr)
}
}
static struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan)
{
struct gsm_meas_rep *meas_rep;
meas_rep = &lchan->meas_rep[lchan->meas_rep_idx];
memset(meas_rep, 0, sizeof(*meas_rep));
meas_rep->lchan = lchan;
lchan->meas_rep_idx = (lchan->meas_rep_idx + 1)
% ARRAY_SIZE(lchan->meas_rep);
return meas_rep;
}
static int rsl_rx_meas_res(struct msgb *msg)
{
struct abis_rsl_dchan_hdr *dh = msgb_l2(msg);

View File

@@ -39,7 +39,7 @@
#define GSM0808_T10_VALUE 6, 0
static LLIST_HEAD(sub_connections);
static LLIST_HEAD(sub_connections); /* FIXME move to libmsc */
static void rll_ind_cb(struct gsm_lchan *, uint8_t, void *, enum bsc_rllr_ind);
static void send_sapi_reject(struct gsm_subscriber_connection *conn, int link_id);
@@ -147,7 +147,7 @@ static void assignment_t10_timeout(void *_conn)
conn->secondary_lchan = NULL;
/* inform them about the failure */
api = conn->bts->network->bsc_api;
api = conn->network->bsc_api;
api->assign_fail(conn, GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
}
@@ -158,7 +158,7 @@ static void handle_mr_config(struct gsm_subscriber_connection *conn,
struct gsm_lchan *lchan, int full_rate)
{
struct bsc_api *api;
api = conn->bts->network->bsc_api;
api = conn->network->bsc_api;
struct amr_multirate_conf *mr;
struct gsm48_multi_rate_conf *mr_conf;
@@ -204,7 +204,8 @@ static int handle_new_assignment(struct gsm_subscriber_connection *conn, int cha
chan_type = full_rate ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H;
new_lchan = lchan_alloc(conn->bts, chan_type, 0);
struct gsm_bts *bts = conn->lchan->ts->trx->bts; // MSCPLIT ??
new_lchan = lchan_alloc(bts, chan_type, 0);
if (!new_lchan) {
LOGP(DMSC, LOGL_NOTICE, "No free channel.\n");
@@ -239,24 +240,25 @@ static int handle_new_assignment(struct gsm_subscriber_connection *conn, int cha
return 0;
}
struct gsm_subscriber_connection *subscr_con_allocate(struct gsm_lchan *lchan)
struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_lchan *lchan)
{
struct gsm_subscriber_connection *conn;
struct gsm_network *network = lchan->ts->trx->bts->network;
conn = talloc_zero(lchan->ts->trx->bts->network, struct gsm_subscriber_connection);
conn = talloc_zero(network, struct gsm_subscriber_connection);
if (!conn)
return NULL;
/* Configure the time and start it so it will be closed */
/* FIXME: above comment is weird in at least two ways */
conn->network = network;
conn->lchan = lchan;
conn->bts = lchan->ts->trx->bts;
lchan->conn = conn;
llist_add_tail(&conn->entry, &sub_connections);
llist_add_tail(&conn->entry, &network->subscr_conns);
return conn;
}
/* TODO: move subscriber put here... */
void subscr_con_free(struct gsm_subscriber_connection *conn)
void bsc_subscr_con_free(struct gsm_subscriber_connection *conn)
{
if (!conn)
return;
@@ -387,7 +389,7 @@ static int chan_compat_with_mode(struct gsm_lchan *lchan, int chan_mode, int ful
int gsm0808_assign_req(struct gsm_subscriber_connection *conn, int chan_mode, int full_rate)
{
struct bsc_api *api;
api = conn->bts->network->bsc_api;
api = conn->network->bsc_api;
if (!chan_compat_with_mode(conn->lchan, chan_mode, full_rate)) {
if (handle_new_assignment(conn, chan_mode, full_rate) != 0)
@@ -424,7 +426,7 @@ static void handle_ass_compl(struct gsm_subscriber_connection *conn,
struct msgb *msg)
{
struct gsm48_hdr *gh;
struct bsc_api *api = conn->bts->network->bsc_api;
struct bsc_api *api = conn->network->bsc_api;
if (conn->secondary_lchan != msg->lchan) {
LOGP(DMSC, LOGL_ERROR, "Assignment Compl should occur on second lchan.\n");
@@ -439,8 +441,13 @@ static void handle_ass_compl(struct gsm_subscriber_connection *conn,
}
/* switch TRAU muxer for E1 based BTS from one channel to another */
#if BEFORE_MSCSPLIT
if (is_e1_bts(conn->bts))
switch_trau_mux(conn->lchan, conn->secondary_lchan);
#else
if (is_e1_bts(conn->lchan->ts->trx->bts))
switch_trau_mux(conn->lchan, conn->secondary_lchan);
#endif
/* swap channels */
osmo_timer_del(&conn->T10);
@@ -449,7 +456,7 @@ static void handle_ass_compl(struct gsm_subscriber_connection *conn,
conn->lchan = conn->secondary_lchan;
conn->secondary_lchan = NULL;
if (is_ipaccess_bts(conn->bts) && conn->lchan->tch_mode != GSM48_CMODE_SIGN)
if (is_ipaccess_bts(conn->lchan->ts->trx->bts) && conn->lchan->tch_mode != GSM48_CMODE_SIGN)
rsl_ipacc_crcx(conn->lchan);
api->assign_compl(conn, gh->data[0],
@@ -461,7 +468,7 @@ static void handle_ass_compl(struct gsm_subscriber_connection *conn,
static void handle_ass_fail(struct gsm_subscriber_connection *conn,
struct msgb *msg)
{
struct bsc_api *api = conn->bts->network->bsc_api;
struct bsc_api *api = conn->network->bsc_api;
uint8_t *rr_failure;
struct gsm48_hdr *gh;
@@ -656,7 +663,8 @@ static void dispatch_dtap(struct gsm_subscriber_connection *conn,
}
}
/*! \brief RSL has received a DATA INDICATION with L3 from MS */
/*! \brief RSL has received a DATA INDICATION with L3 from MS.
* (for Iu-CS see gsm0408_rcvmsg_iucs()) */
int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id)
{
int rc;
@@ -678,7 +686,7 @@ int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id)
} else {
/* allocate a new connection */
rc = BSC_API_CONN_POL_REJECT;
lchan->conn = subscr_con_allocate(msg->lchan);
lchan->conn = bsc_subscr_con_allocate(msg->lchan);
if (!lchan->conn) {
lchan_release(lchan, 1, RSL_REL_NORMAL);
return -1;
@@ -689,7 +697,7 @@ int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id)
if (rc != BSC_API_CONN_POL_ACCEPT) {
lchan->conn->lchan = NULL;
subscr_con_free(lchan->conn);
bsc_subscr_con_free(lchan->conn);
lchan_release(lchan, 1, RSL_REL_NORMAL);
}
}
@@ -737,7 +745,6 @@ int gsm0808_clear(struct gsm_subscriber_connection *conn)
conn->lchan = NULL;
conn->secondary_lchan = NULL;
conn->ho_lchan = NULL;
conn->bts = NULL;
osmo_timer_del(&conn->T10);
@@ -751,7 +758,7 @@ static void send_sapi_reject(struct gsm_subscriber_connection *conn, int link_id
if (!conn)
return;
api = conn->bts->network->bsc_api;
api = conn->network->bsc_api;
if (!api || !api->sapi_n_reject)
return;
@@ -848,7 +855,7 @@ static void handle_release(struct gsm_subscriber_connection *conn,
gsm0808_clear(conn);
if (destruct)
subscr_con_free(conn);
bsc_subscr_con_free(conn);
}
static void handle_chan_ack(struct gsm_subscriber_connection *conn,
@@ -877,7 +884,3 @@ static __attribute__((constructor)) void on_dso_load_bsc(void)
osmo_signal_register_handler(SS_LCHAN, bsc_handle_lchan_signal, NULL);
}
struct llist_head *bsc_api_sub_connections(struct gsm_network *net)
{
return &sub_connections;
}

View File

@@ -476,24 +476,24 @@ static int bootstrap_bts(struct gsm_bts *bts)
return 0;
}
int bsc_bootstrap_network(int (*mncc_recv)(struct gsm_network *, struct msgb *),
const char *config_file)
int bsc_network_init(mncc_recv_cb_t mncc_recv)
{
struct telnet_connection dummy_conn;
struct gsm_bts *bts;
int rc;
/* initialize our data structures */
bsc_gsmnet = gsm_network_init(1, 1, mncc_recv);
bsc_gsmnet = gsm_network_init(tall_bsc_ctx, 1, 1, mncc_recv);
if (!bsc_gsmnet)
return -ENOMEM;
bsc_gsmnet->name_long = talloc_strdup(bsc_gsmnet, "OpenBSC");
bsc_gsmnet->name_short = talloc_strdup(bsc_gsmnet, "OpenBSC");
/* our vty command code expects vty->priv to point to a telnet_connection */
dummy_conn.priv = bsc_gsmnet;
rc = vty_read_config_file(config_file, &dummy_conn);
return 0;
}
int bsc_network_configure(const char *config_file)
{
struct gsm_bts *bts;
int rc;
rc = vty_read_config_file(config_file, NULL);
if (rc < 0) {
LOGP(DNM, LOGL_FATAL, "Failed to parse the config file: '%s'\n", config_file);
return rc;

View File

@@ -53,15 +53,13 @@
#include <openbsc/osmo_msc_data.h>
#include <openbsc/osmo_bsc_rf.h>
#include <openbsc/xsc.h>
#include <inttypes.h>
#include "../../bscconfig.h"
#define NETWORK_STR "Configure the GSM network\n"
#define CODE_CMD_STR "Code commands\n"
#define NAME_CMD_STR "Name Commands\n"
#define NAME_STR "Name to use\n"
#define LCHAN_NR_STR "Logical Channel Number\n"
@@ -106,12 +104,6 @@ const struct value_string bts_loc_fix_names[] = {
{ 0, NULL }
};
struct cmd_node net_node = {
GSMNET_NODE,
"%s(config-net)# ",
1,
};
struct cmd_node bts_node = {
BTS_NODE,
"%s(config-net-bts)# ",
@@ -130,21 +122,6 @@ struct cmd_node ts_node = {
1,
};
extern struct gsm_network *bsc_gsmnet;
struct gsm_network *gsmnet_from_vty(struct vty *v)
{
/* In case we read from the config file, the vty->priv cannot
* point to a struct telnet_connection, and thus conn->priv
* will not point to the gsm_network structure */
#if 0
struct telnet_connection *conn = v->priv;
return (struct gsm_network *) conn->priv;
#else
return bsc_gsmnet;
#endif
}
static int dummy_config_write(struct vty *v)
{
return CMD_SUCCESS;
@@ -178,57 +155,6 @@ static void dump_pchan_load_vty(struct vty *vty, char *prefix,
}
}
static void net_dump_vty(struct vty *vty, struct gsm_network *net)
{
struct pchan_load pl;
vty_out(vty, "BSC is on Country Code %u, Network Code %u "
"and has %u BTS%s", net->country_code, net->network_code,
net->num_bts, VTY_NEWLINE);
vty_out(vty, " Long network name: '%s'%s",
net->name_long, VTY_NEWLINE);
vty_out(vty, " Short network name: '%s'%s",
net->name_short, VTY_NEWLINE);
vty_out(vty, " Authentication policy: %s%s",
gsm_auth_policy_name(net->auth_policy), VTY_NEWLINE);
vty_out(vty, " Location updating reject cause: %u%s",
net->reject_cause, VTY_NEWLINE);
vty_out(vty, " Encryption: A5/%u%s", net->a5_encryption,
VTY_NEWLINE);
vty_out(vty, " NECI (TCH/H): %u%s", net->neci,
VTY_NEWLINE);
vty_out(vty, " Use TCH for Paging any: %d%s", net->pag_any_tch,
VTY_NEWLINE);
vty_out(vty, " RRLP Mode: %s%s", rrlp_mode_name(net->rrlp.mode),
VTY_NEWLINE);
vty_out(vty, " MM Info: %s%s", net->send_mm_info ? "On" : "Off",
VTY_NEWLINE);
vty_out(vty, " Handover: %s%s", net->handover.active ? "On" : "Off",
VTY_NEWLINE);
network_chan_load(&pl, net);
vty_out(vty, " Current Channel Load:%s", VTY_NEWLINE);
dump_pchan_load_vty(vty, " ", &pl);
/* show rf */
if (net->bsc_data)
vty_out(vty, " Last RF Command: %s%s",
net->bsc_data->rf_ctrl->last_state_command,
VTY_NEWLINE);
if (net->bsc_data)
vty_out(vty, " Last RF Lock Command: %s%s",
net->bsc_data->rf_ctrl->last_rf_lock_ctrl_command,
VTY_NEWLINE);
}
DEFUN(show_net, show_net_cmd, "show network",
SHOW_STR "Display information about a GSM NETWORK\n")
{
struct gsm_network *net = gsmnet_from_vty(vty);
net_dump_vty(vty, net);
return CMD_SUCCESS;
}
static void e1isl_dump_vty(struct vty *vty, struct e1inp_sign_link *e1l)
{
struct e1inp_line *line;
@@ -550,14 +476,6 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
vty_out(vty, " location_area_code %u%s", bts->location_area_code,
VTY_NEWLINE);
vty_out(vty, " base_station_id_code %u%s", bts->bsic, VTY_NEWLINE);
if (bts->tz.override != 0) {
if (bts->tz.dst)
vty_out(vty, " timezone %d %d %d%s",
bts->tz.hr, bts->tz.mn, bts->tz.dst, VTY_NEWLINE);
else
vty_out(vty, " timezone %d %d%s",
bts->tz.hr, bts->tz.mn, VTY_NEWLINE);
}
vty_out(vty, " ms max power %u%s", bts->ms_max_power, VTY_NEWLINE);
vty_out(vty, " cell reselection hysteresis %u%s",
bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE);
@@ -591,13 +509,6 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
(sp->penalty_time*20)+20, VTY_NEWLINE);
}
/* Is periodic LU enabled or disabled? */
if (bts->si_common.chan_desc.t3212 == 0)
vty_out(vty, " no periodic location update%s", VTY_NEWLINE);
else
vty_out(vty, " periodic location update %u%s",
bts->si_common.chan_desc.t3212 * 6, VTY_NEWLINE);
vty_out(vty, " radio-link-timeout %d%s",
get_radio_link_timeout(&bts->si_common.cell_options),
VTY_NEWLINE);
@@ -766,56 +677,6 @@ static int config_write_bts(struct vty *v)
return CMD_SUCCESS;
}
static int config_write_net(struct vty *vty)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
vty_out(vty, "network%s", VTY_NEWLINE);
vty_out(vty, " network country code %u%s", gsmnet->country_code, VTY_NEWLINE);
vty_out(vty, " mobile network code %u%s", gsmnet->network_code, VTY_NEWLINE);
vty_out(vty, " short name %s%s", gsmnet->name_short, VTY_NEWLINE);
vty_out(vty, " long name %s%s", gsmnet->name_long, VTY_NEWLINE);
vty_out(vty, " auth policy %s%s", gsm_auth_policy_name(gsmnet->auth_policy), VTY_NEWLINE);
vty_out(vty, " location updating reject cause %u%s",
gsmnet->reject_cause, VTY_NEWLINE);
vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE);
vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE);
vty_out(vty, " paging any use tch %d%s", gsmnet->pag_any_tch, VTY_NEWLINE);
vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode),
VTY_NEWLINE);
vty_out(vty, " mm info %u%s", gsmnet->send_mm_info, VTY_NEWLINE);
vty_out(vty, " handover %u%s", gsmnet->handover.active, VTY_NEWLINE);
vty_out(vty, " handover window rxlev averaging %u%s",
gsmnet->handover.win_rxlev_avg, VTY_NEWLINE);
vty_out(vty, " handover window rxqual averaging %u%s",
gsmnet->handover.win_rxqual_avg, VTY_NEWLINE);
vty_out(vty, " handover window rxlev neighbor averaging %u%s",
gsmnet->handover.win_rxlev_avg_neigh, VTY_NEWLINE);
vty_out(vty, " handover power budget interval %u%s",
gsmnet->handover.pwr_interval, VTY_NEWLINE);
vty_out(vty, " handover power budget hysteresis %u%s",
gsmnet->handover.pwr_hysteresis, VTY_NEWLINE);
vty_out(vty, " handover maximum distance %u%s",
gsmnet->handover.max_distance, VTY_NEWLINE);
vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE);
vty_out(vty, " timer t3103 %u%s", gsmnet->T3103, VTY_NEWLINE);
vty_out(vty, " timer t3105 %u%s", gsmnet->T3105, VTY_NEWLINE);
vty_out(vty, " timer t3107 %u%s", gsmnet->T3107, VTY_NEWLINE);
vty_out(vty, " timer t3109 %u%s", gsmnet->T3109, VTY_NEWLINE);
vty_out(vty, " timer t3111 %u%s", gsmnet->T3111, VTY_NEWLINE);
vty_out(vty, " timer t3113 %u%s", gsmnet->T3113, VTY_NEWLINE);
vty_out(vty, " timer t3115 %u%s", gsmnet->T3115, VTY_NEWLINE);
vty_out(vty, " timer t3117 %u%s", gsmnet->T3117, VTY_NEWLINE);
vty_out(vty, " timer t3119 %u%s", gsmnet->T3119, VTY_NEWLINE);
vty_out(vty, " timer t3122 %u%s", gsmnet->T3122, VTY_NEWLINE);
vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE);
vty_out(vty, " dtx-used %u%s", gsmnet->dtx_enabled, VTY_NEWLINE);
vty_out(vty, " subscriber-keep-in-ram %d%s",
gsmnet->subscr_group->keep_subscr, VTY_NEWLINE);
return CMD_SUCCESS;
}
static void trx_dump_vty(struct vty *vty, struct gsm_bts_trx *trx)
{
vty_out(vty, "TRX %u of BTS %u is on ARFCN %u%s",
@@ -1320,321 +1181,6 @@ DEFUN(show_paging_group,
return CMD_SUCCESS;
}
DEFUN(cfg_net,
cfg_net_cmd,
"network", NETWORK_STR)
{
vty->index = gsmnet_from_vty(vty);
vty->node = GSMNET_NODE;
return CMD_SUCCESS;
}
DEFUN(cfg_net_ncc,
cfg_net_ncc_cmd,
"network country code <1-999>",
"Set the GSM network country code\n"
"Country commands\n"
CODE_CMD_STR
"Network Country Code to use\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->country_code = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_mnc,
cfg_net_mnc_cmd,
"mobile network code <0-999>",
"Set the GSM mobile network code\n"
"Network Commands\n"
CODE_CMD_STR
"Mobile Network Code to use\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->network_code = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_name_short,
cfg_net_name_short_cmd,
"short name NAME",
"Set the short GSM network name\n" NAME_CMD_STR NAME_STR)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
bsc_replace_string(gsmnet, &gsmnet->name_short, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_name_long,
cfg_net_name_long_cmd,
"long name NAME",
"Set the long GSM network name\n" NAME_CMD_STR NAME_STR)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
bsc_replace_string(gsmnet, &gsmnet->name_long, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_auth_policy,
cfg_net_auth_policy_cmd,
"auth policy (closed|accept-all|token)",
"Authentication (not cryptographic)\n"
"Set the GSM network authentication policy\n"
"Require the MS to be activated in HLR\n"
"Accept all MS, whether in HLR or not\n"
"Use SMS-token based authentication\n")
{
enum gsm_auth_policy policy = gsm_auth_policy_parse(argv[0]);
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->auth_policy = policy;
return CMD_SUCCESS;
}
DEFUN(cfg_net_reject_cause,
cfg_net_reject_cause_cmd,
"location updating reject cause <2-111>",
"Set the reject cause of location updating reject\n"
"Set the reject cause of location updating reject\n"
"Set the reject cause of location updating reject\n"
"Set the reject cause of location updating reject\n"
"Cause Value as Per GSM TS 04.08\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->reject_cause = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_encryption,
cfg_net_encryption_cmd,
"encryption a5 (0|1|2|3)",
"Encryption options\n"
"A5 encryption\n" "A5/0: No encryption\n"
"A5/1: Encryption\n" "A5/2: Export-grade Encryption\n"
"A5/3: 'New' Secure Encryption\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->a5_encryption= atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_neci,
cfg_net_neci_cmd,
"neci (0|1)",
"New Establish Cause Indication\n"
"Don't set the NECI bit\n" "Set the NECI bit\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->neci = atoi(argv[0]);
gsm_net_update_ctype(gsmnet);
return CMD_SUCCESS;
}
DEFUN(cfg_net_rrlp_mode, cfg_net_rrlp_mode_cmd,
"rrlp mode (none|ms-based|ms-preferred|ass-preferred)",
"Radio Resource Location Protocol\n"
"Set the Radio Resource Location Protocol Mode\n"
"Don't send RRLP request\n"
"Request MS-based location\n"
"Request any location, prefer MS-based\n"
"Request any location, prefer MS-assisted\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->rrlp.mode = rrlp_mode_parse(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_mm_info, cfg_net_mm_info_cmd,
"mm info (0|1)",
"Mobility Management\n"
"Send MM INFO after LOC UPD ACCEPT\n"
"Disable\n" "Enable\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->send_mm_info = atoi(argv[0]);
return CMD_SUCCESS;
}
#define HANDOVER_STR "Handover Options\n"
DEFUN(cfg_net_handover, cfg_net_handover_cmd,
"handover (0|1)",
HANDOVER_STR
"Don't perform in-call handover\n"
"Perform in-call handover\n")
{
int enable = atoi(argv[0]);
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
if (enable && ipacc_rtp_direct) {
vty_out(vty, "%% Cannot enable handover unless RTP Proxy mode "
"is enabled by using the -P command line option%s",
VTY_NEWLINE);
return CMD_WARNING;
}
gsmnet->handover.active = enable;
return CMD_SUCCESS;
}
#define HO_WIN_STR HANDOVER_STR "Measurement Window\n"
#define HO_WIN_RXLEV_STR HO_WIN_STR "Received Level Averaging\n"
#define HO_WIN_RXQUAL_STR HO_WIN_STR "Received Quality Averaging\n"
#define HO_PBUDGET_STR HANDOVER_STR "Power Budget\n"
#define HO_AVG_COUNT_STR "Amount to use for Averaging\n"
DEFUN(cfg_net_ho_win_rxlev_avg, cfg_net_ho_win_rxlev_avg_cmd,
"handover window rxlev averaging <1-10>",
HO_WIN_RXLEV_STR
"How many RxLev measurements are used for averaging\n"
HO_AVG_COUNT_STR)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.win_rxlev_avg = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_ho_win_rxqual_avg, cfg_net_ho_win_rxqual_avg_cmd,
"handover window rxqual averaging <1-10>",
HO_WIN_RXQUAL_STR
"How many RxQual measurements are used for averaging\n"
HO_AVG_COUNT_STR)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.win_rxqual_avg = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_ho_win_rxlev_neigh_avg, cfg_net_ho_win_rxlev_avg_neigh_cmd,
"handover window rxlev neighbor averaging <1-10>",
HO_WIN_RXLEV_STR "Neighbor\n"
"How many RxQual measurements are used for averaging\n"
HO_AVG_COUNT_STR)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.win_rxlev_avg_neigh = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_ho_pwr_interval, cfg_net_ho_pwr_interval_cmd,
"handover power budget interval <1-99>",
HO_PBUDGET_STR
"How often to check if we have a better cell (SACCH frames)\n"
"Interval\n" "Number\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.pwr_interval = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_ho_pwr_hysteresis, cfg_net_ho_pwr_hysteresis_cmd,
"handover power budget hysteresis <0-999>",
HO_PBUDGET_STR
"How many dB does a neighbor to be stronger to become a HO candidate\n"
"Hysteresis\n" "Number\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.pwr_hysteresis = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd,
"handover maximum distance <0-9999>",
HANDOVER_STR
"How big is the maximum timing advance before HO is forced\n"
"Distance\n" "Number\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.max_distance = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_pag_any_tch,
cfg_net_pag_any_tch_cmd,
"paging any use tch (0|1)",
"Assign a TCH when receiving a Paging Any request\n"
"Any Channel\n" "Use\n" "TCH\n"
"Do not use TCH for Paging Request Any\n"
"Do use TCH for Paging Request Any\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->pag_any_tch = atoi(argv[0]);
gsm_net_update_ctype(gsmnet);
return CMD_SUCCESS;
}
#define DECLARE_TIMER(number, doc) \
DEFUN(cfg_net_T##number, \
cfg_net_T##number##_cmd, \
"timer t" #number " <0-65535>", \
"Configure GSM Timers\n" \
doc "Timer Value in seconds\n") \
{ \
struct gsm_network *gsmnet = gsmnet_from_vty(vty); \
int value = atoi(argv[0]); \
\
if (value < 0 || value > 65535) { \
vty_out(vty, "Timer value %s out of range.%s", \
argv[0], VTY_NEWLINE); \
return CMD_WARNING; \
} \
\
gsmnet->T##number = value; \
return CMD_SUCCESS; \
}
DECLARE_TIMER(3101, "Set the timeout value for IMMEDIATE ASSIGNMENT.\n")
DECLARE_TIMER(3103, "Set the timeout value for HANDOVER.\n")
DECLARE_TIMER(3105, "Set the timer for repetition of PHYSICAL INFORMATION.\n")
DECLARE_TIMER(3107, "Currently not used.\n")
DECLARE_TIMER(3109, "Set the RSL SACCH deactivation timeout.\n")
DECLARE_TIMER(3111, "Set the RSL timeout to wait before releasing the RF Channel.\n")
DECLARE_TIMER(3113, "Set the time to try paging a subscriber.\n")
DECLARE_TIMER(3115, "Currently not used.\n")
DECLARE_TIMER(3117, "Currently not used.\n")
DECLARE_TIMER(3119, "Currently not used.\n")
DECLARE_TIMER(3122, "Waiting time (seconds) after IMM ASS REJECT\n")
DECLARE_TIMER(3141, "Currently not used.\n")
DEFUN(cfg_net_dtx,
cfg_net_dtx_cmd,
"dtx-used (0|1)",
"Enable the usage of DTX.\n"
"DTX is disabled\n" "DTX is enabled\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->dtx_enabled = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_subscr_keep,
cfg_net_subscr_keep_cmd,
"subscriber-keep-in-ram (0|1)",
"Keep unused subscribers in RAM.\n"
"Delete unused subscribers\n" "Keep unused subscribers\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->subscr_group->keep_subscr = atoi(argv[0]);
return CMD_SUCCESS;
}
/* per-BTS configuration */
DEFUN(cfg_bts,
cfg_bts_cmd,
@@ -1776,67 +1322,6 @@ DEFUN(cfg_bts_bsic,
return CMD_SUCCESS;
}
DEFUN(cfg_bts_timezone,
cfg_bts_timezone_cmd,
"timezone <-19-19> (0|15|30|45)",
"Set the Timezone Offset of this BTS\n"
"Timezone offset (hours)\n"
"Timezone offset (00 minutes)\n"
"Timezone offset (15 minutes)\n"
"Timezone offset (30 minutes)\n"
"Timezone offset (45 minutes)\n"
)
{
struct gsm_bts *bts = vty->index;
int tzhr = atoi(argv[0]);
int tzmn = atoi(argv[1]);
bts->tz.hr = tzhr;
bts->tz.mn = tzmn;
bts->tz.dst = 0;
bts->tz.override = 1;
return CMD_SUCCESS;
}
DEFUN(cfg_bts_timezone_dst,
cfg_bts_timezone_dst_cmd,
"timezone <-19-19> (0|15|30|45) <0-2>",
"Set the Timezone Offset of this BTS\n"
"Timezone offset (hours)\n"
"Timezone offset (00 minutes)\n"
"Timezone offset (15 minutes)\n"
"Timezone offset (30 minutes)\n"
"Timezone offset (45 minutes)\n"
"DST offset (hours)\n"
)
{
struct gsm_bts *bts = vty->index;
int tzhr = atoi(argv[0]);
int tzmn = atoi(argv[1]);
int tzdst = atoi(argv[2]);
bts->tz.hr = tzhr;
bts->tz.mn = tzmn;
bts->tz.dst = tzdst;
bts->tz.override = 1;
return CMD_SUCCESS;
}
DEFUN(cfg_bts_no_timezone,
cfg_bts_no_timezone_cmd,
"no timezone",
NO_STR
"Disable BTS specific timezone\n")
{
struct gsm_bts *bts = vty->index;
bts->tz.override = 0;
return CMD_SUCCESS;
}
DEFUN(cfg_bts_unit_id,
cfg_bts_unit_id_cmd,
"ip.access unit_id <0-65534> <0-255>",
@@ -2332,30 +1817,67 @@ DEFUN(cfg_bts_penalty_time_rsvd, cfg_bts_penalty_time_rsvd_cmd,
return CMD_SUCCESS;
}
DEFUN(cfg_bts_per_loc_upd, cfg_bts_per_loc_upd_cmd,
DEFUN(cfg_net_pag_any_tch,
cfg_net_pag_any_tch_cmd,
"paging any use tch (0|1)",
"Assign a TCH when receiving a Paging Any request\n"
"Any Channel\n" "Use\n" "TCH\n"
"Do not use TCH for Paging Request Any\n"
"Do use TCH for Paging Request Any\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->pag_any_tch = atoi(argv[0]);
gsm_net_update_ctype(gsmnet);
return CMD_SUCCESS;
}
DEFUN(cfg_net_neci,
cfg_net_neci_cmd,
"neci (0|1)",
"New Establish Cause Indication\n"
"Don't set the NECI bit\n" "Set the NECI bit\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->neci = atoi(argv[0]);
gsm_net_update_ctype(gsmnet);
return CMD_SUCCESS;
}
DEFUN(cfg_net_per_loc_upd, cfg_net_per_loc_upd_cmd,
"periodic location update <6-1530>",
"Periodic Location Updating Interval\n"
"Periodic Location Updating Interval\n"
"Periodic Location Updating Interval\n"
"Periodic Location Updating Interval in Minutes\n")
{
struct gsm_bts *bts = vty->index;
struct gsm_network *net = vty->index;
struct gsm_bts *bts;
bts->si_common.chan_desc.t3212 = atoi(argv[0]) / 6;
net->t3212 = atoi(argv[0]) / 6;
llist_for_each_entry(bts, &net->bts_list, list) {
bts->si_common.chan_desc.t3212 = net->t3212;
}
return CMD_SUCCESS;
}
DEFUN(cfg_bts_no_per_loc_upd, cfg_bts_no_per_loc_upd_cmd,
DEFUN(cfg_net_no_per_loc_upd, cfg_net_no_per_loc_upd_cmd,
"no periodic location update",
NO_STR
"Periodic Location Updating Interval\n"
"Periodic Location Updating Interval\n"
"Periodic Location Updating Interval\n")
{
struct gsm_bts *bts = vty->index;
struct gsm_network *net = vty->index;
struct gsm_bts *bts;
bts->si_common.chan_desc.t3212 = 0;
net->t3212 = 0;
llist_for_each_entry(bts, &net->bts_list, list) {
bts->si_common.chan_desc.t3212 = net->t3212;
}
return CMD_SUCCESS;
}
@@ -3776,7 +3298,7 @@ DEFUN(smscb_cmd, smscb_cmd_cmd,
uint8_t buf[88];
int rc;
bts = gsm_bts_num(bsc_gsmnet, bts_nr);
bts = gsm_bts_num(vty_global_gsm_network, bts_nr);
if (!bts) {
vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
return CMD_WARNING;
@@ -3827,7 +3349,7 @@ DEFUN(pdch_act, pdch_act_cmd,
int ts_nr = atoi(argv[2]);
int activate;
bts = gsm_bts_num(bsc_gsmnet, bts_nr);
bts = gsm_bts_num(vty_global_gsm_network, bts_nr);
if (!bts) {
vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
return CMD_WARNING;
@@ -3864,9 +3386,8 @@ DEFUN(pdch_act, pdch_act_cmd,
}
extern int bsc_vty_init_extra(void);
extern const char *openbsc_copyright;
int bsc_vty_init(const struct log_info *cat)
int bsc_vty_init(const struct log_info *cat, struct gsm_network *network)
{
cfg_ts_pchan_cmd.string =
vty_cmd_string_from_valstr(tall_bsc_ctx,
@@ -3890,8 +3411,16 @@ int bsc_vty_init(const struct log_info *cat)
"BTS Vendor/Type\n",
"\n", "", 0);
logging_vty_add_cmds(cat);
xsc_vty_init(network);
install_element(GSMNET_NODE, &cfg_net_neci_cmd);
install_element(GSMNET_NODE, &cfg_net_pag_any_tch_cmd);
install_element(GSMNET_NODE, &cfg_net_per_loc_upd_cmd);
install_element(GSMNET_NODE, &cfg_net_no_per_loc_upd_cmd);
gsm_net_update_ctype(network);
install_element_ve(&show_net_cmd);
install_element_ve(&show_bts_cmd);
install_element_ve(&show_trx_cmd);
install_element_ve(&show_ts_cmd);
@@ -3901,45 +3430,6 @@ int bsc_vty_init(const struct log_info *cat)
install_element_ve(&show_paging_cmd);
install_element_ve(&show_paging_group_cmd);
logging_vty_add_cmds(cat);
osmo_stats_vty_add_cmds();
install_element(CONFIG_NODE, &cfg_net_cmd);
install_node(&net_node, config_write_net);
vty_install_default(GSMNET_NODE);
install_element(GSMNET_NODE, &cfg_net_ncc_cmd);
install_element(GSMNET_NODE, &cfg_net_mnc_cmd);
install_element(GSMNET_NODE, &cfg_net_name_short_cmd);
install_element(GSMNET_NODE, &cfg_net_name_long_cmd);
install_element(GSMNET_NODE, &cfg_net_auth_policy_cmd);
install_element(GSMNET_NODE, &cfg_net_reject_cause_cmd);
install_element(GSMNET_NODE, &cfg_net_encryption_cmd);
install_element(GSMNET_NODE, &cfg_net_neci_cmd);
install_element(GSMNET_NODE, &cfg_net_rrlp_mode_cmd);
install_element(GSMNET_NODE, &cfg_net_mm_info_cmd);
install_element(GSMNET_NODE, &cfg_net_handover_cmd);
install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_cmd);
install_element(GSMNET_NODE, &cfg_net_ho_win_rxqual_avg_cmd);
install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_neigh_cmd);
install_element(GSMNET_NODE, &cfg_net_ho_pwr_interval_cmd);
install_element(GSMNET_NODE, &cfg_net_ho_pwr_hysteresis_cmd);
install_element(GSMNET_NODE, &cfg_net_ho_max_distance_cmd);
install_element(GSMNET_NODE, &cfg_net_T3101_cmd);
install_element(GSMNET_NODE, &cfg_net_T3103_cmd);
install_element(GSMNET_NODE, &cfg_net_T3105_cmd);
install_element(GSMNET_NODE, &cfg_net_T3107_cmd);
install_element(GSMNET_NODE, &cfg_net_T3109_cmd);
install_element(GSMNET_NODE, &cfg_net_T3111_cmd);
install_element(GSMNET_NODE, &cfg_net_T3113_cmd);
install_element(GSMNET_NODE, &cfg_net_T3115_cmd);
install_element(GSMNET_NODE, &cfg_net_T3117_cmd);
install_element(GSMNET_NODE, &cfg_net_T3119_cmd);
install_element(GSMNET_NODE, &cfg_net_T3122_cmd);
install_element(GSMNET_NODE, &cfg_net_T3141_cmd);
install_element(GSMNET_NODE, &cfg_net_dtx_cmd);
install_element(GSMNET_NODE, &cfg_net_subscr_keep_cmd);
install_element(GSMNET_NODE, &cfg_net_pag_any_tch_cmd);
install_element(GSMNET_NODE, &cfg_bts_cmd);
install_node(&bts_node, config_write_bts);
vty_install_default(BTS_NODE);
@@ -3953,9 +3443,6 @@ int bsc_vty_init(const struct log_info *cat)
install_element(BTS_NODE, &cfg_bts_bsic_cmd);
install_element(BTS_NODE, &cfg_bts_unit_id_cmd);
install_element(BTS_NODE, &cfg_bts_rsl_ip_cmd);
install_element(BTS_NODE, &cfg_bts_timezone_cmd);
install_element(BTS_NODE, &cfg_bts_timezone_dst_cmd);
install_element(BTS_NODE, &cfg_bts_no_timezone_cmd);
install_element(BTS_NODE, &cfg_bts_nokia_site_skip_reset_cmd);
install_element(BTS_NODE, &cfg_bts_nokia_site_no_loc_rel_cnf_cmd);
install_element(BTS_NODE, &cfg_bts_nokia_site_bts_reset_timer_cnf_cmd);
@@ -3974,8 +3461,6 @@ int bsc_vty_init(const struct log_info *cat)
install_element(BTS_NODE, &cfg_bts_rach_ec_allowed_cmd);
install_element(BTS_NODE, &cfg_bts_rach_ac_class_cmd);
install_element(BTS_NODE, &cfg_bts_ms_max_power_cmd);
install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd);
install_element(BTS_NODE, &cfg_bts_no_per_loc_upd_cmd);
install_element(BTS_NODE, &cfg_bts_cell_resel_hyst_cmd);
install_element(BTS_NODE, &cfg_bts_rxlev_acc_min_cmd);
install_element(BTS_NODE, &cfg_bts_cell_bar_qualify_cmd);

View File

@@ -39,6 +39,7 @@
#include <osmocom/abis/ipaccess.h>
#include <osmocom/core/logging.h>
#include <openbsc/ipaccess.h>
#include <openbsc/vty.h>
extern struct gsm_network *bsc_gsmnet;

View File

@@ -329,39 +329,6 @@ int lchan_release(struct gsm_lchan *lchan, int sacch_deact, enum rsl_rel_mode mo
return 1;
}
static struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr) {
struct gsm_bts_trx *trx;
int ts_no, lchan_no;
llist_for_each_entry(trx, &bts->trx_list, list) {
for (ts_no = 0; ts_no < 8; ++ts_no) {
for (lchan_no = 0; lchan_no < TS_MAX_LCHAN; ++lchan_no) {
struct gsm_lchan *lchan =
&trx->ts[ts_no].lchan[lchan_no];
if (lchan->conn && subscr == lchan->conn->subscr)
return lchan;
}
}
}
return NULL;
}
struct gsm_subscriber_connection *connection_for_subscr(struct gsm_subscriber *subscr)
{
struct gsm_bts *bts;
struct gsm_network *net = subscr->group->net;
struct gsm_lchan *lchan;
llist_for_each_entry(bts, &net->bts_list, list) {
lchan = lchan_find(bts, subscr);
if (lchan)
return lchan->conn;
}
return NULL;
}
void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts)
{
struct gsm_bts_trx *trx;

View File

@@ -258,30 +258,7 @@ int send_siemens_mrpci(struct gsm_lchan *lchan,
return rsl_siemens_mrpci(lchan, &mrpci);
}
int gsm48_extract_mi(uint8_t *classmark2_lv, int length, char *mi_string, uint8_t *mi_type)
{
/* Check the size for the classmark */
if (length < 1 + *classmark2_lv)
return -1;
uint8_t *mi_lv = classmark2_lv + *classmark2_lv + 1;
if (length < 2 + *classmark2_lv + mi_lv[0])
return -2;
*mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
return gsm48_mi_to_string(mi_string, GSM48_MI_SIZE, mi_lv+1, *mi_lv);
}
int gsm48_paging_extract_mi(struct gsm48_pag_resp *resp, int length,
char *mi_string, uint8_t *mi_type)
{
static const uint32_t classmark_offset =
offsetof(struct gsm48_pag_resp, classmark2);
uint8_t *classmark2_lv = (uint8_t *) &resp->classmark2;
return gsm48_extract_mi(classmark2_lv, length - classmark_offset,
mi_string, mi_type);
}
/* TODO MSCSPLIT remove gsm48_handle_paging_resp() */
int gsm48_handle_paging_resp(struct gsm_subscriber_connection *conn,
struct msgb *msg, struct gsm_subscriber *subscr)
{
@@ -634,39 +611,6 @@ int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg)
return 0;
}
struct msgb *gsm48_create_mm_serv_rej(enum gsm48_reject_value value)
{
struct msgb *msg;
struct gsm48_hdr *gh;
msg = gsm48_msgb_alloc_name("GSM 04.08 SERV REJ");
if (!msg)
return NULL;
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
gh->proto_discr = GSM48_PDISC_MM;
gh->msg_type = GSM48_MT_MM_CM_SERV_REJ;
gh->data[0] = value;
return msg;
}
struct msgb *gsm48_create_loc_upd_rej(uint8_t cause)
{
struct gsm48_hdr *gh;
struct msgb *msg;
msg = gsm48_msgb_alloc_name("GSM 04.08 LOC UPD REJ");
if (!msg)
return NULL;
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
gh->proto_discr = GSM48_PDISC_MM;
gh->msg_type = GSM48_MT_MM_LOC_UPD_REJECT;
gh->data[0] = cause;
return msg;
}
/* 9.2.5 CM service accept */
int gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn)
{

View File

@@ -1,6 +1,6 @@
/* Helpers for SMS/GSM 04.11 */
/*
* (C) 2014 by Holger Hans Peter Freyther
/* OpenBSC utility functions for 3GPP TS 04.80 */
/* (C) 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
*
* All Rights Reserved
*
@@ -19,19 +19,21 @@
*
*/
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_04_11.h>
#include <openbsc/gsm_04_80.h>
#include <openbsc/bsc_api.h>
uint8_t sms_next_rp_msg_ref(struct gsm_subscriber_connection *conn)
int gsm0480_send_ussdNotify(struct gsm_subscriber_connection *conn, int level, const char *text)
{
const uint8_t rp_msg_ref = conn->next_rp_ref;
/*
* This should wrap as the valid range is 0 to 255. We only
* transfer one SMS at a time so we don't need to check if
* the id has been already assigned.
*/
conn->next_rp_ref += 1;
return rp_msg_ref;
struct msgb *msg = gsm0480_gen_ussdNotify(level, text);
if (!msg)
return -1;
return gsm0808_submit_dtap(conn, msg, 0, 0);
}
int gsm0480_send_releaseComplete(struct gsm_subscriber_connection *conn)
{
struct msgb *msg = gsm0480_gen_releaseComplete();
if (!msg)
return -1;
return gsm0808_submit_dtap(conn, msg, 0, 0);
}

View File

@@ -33,6 +33,27 @@
#include <openbsc/handover.h>
#include <osmocom/gsm/gsm_utils.h>
/* Get reference to a neighbor cell on a given BCCH ARFCN */
static struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts,
uint16_t arfcn, uint8_t bsic)
{
struct gsm_bts *neigh;
/* FIXME: use some better heuristics here to determine which cell
* using this ARFCN really is closest to the target cell. For
* now we simply assume that each ARFCN will only be used by one
* cell */
llist_for_each_entry(neigh, &bts->network->bts_list, list) {
/* FIXME: this is probably returning the same bts again!? */
if (neigh->c0->arfcn == arfcn &&
neigh->bsic == bsic)
return neigh;
}
return NULL;
}
/* issue handover to a cell identified by ARFCN and BSIC */
static int handover_to_arfcn_bsic(struct gsm_lchan *lchan,
uint16_t arfcn, uint8_t bsic)

View File

@@ -269,9 +269,14 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
osmo_timer_del(&ho->T3103);
#if BEFORE_MSCSPLIT
/* switch TRAU muxer for E1 based BTS from one channel to another */
if (is_e1_bts(new_lchan->conn->bts))
switch_trau_mux(ho->old_lchan, new_lchan);
#else
if (is_e1_bts(new_lchan->ts->trx->bts))
switch_trau_mux(ho->old_lchan, new_lchan);
#endif
/* Replace the ho lchan with the primary one */
if (ho->old_lchan != new_lchan->conn->lchan)

View File

@@ -17,96 +17,3 @@
*
*/
#include <openbsc/gsm_data.h>
#include <openbsc/osmo_msc_data.h>
#include <openbsc/gsm_subscriber.h>
struct gsm_network *gsm_network_init(uint16_t country_code, uint16_t network_code,
int (*mncc_recv)(struct gsm_network *, struct msgb *))
{
struct gsm_network *net;
net = talloc_zero(tall_bsc_ctx, struct gsm_network);
if (!net)
return NULL;
net->bsc_data = talloc_zero(net, struct osmo_bsc_data);
if (!net->bsc_data) {
talloc_free(net);
return NULL;
}
net->subscr_group = talloc_zero(net, struct gsm_subscriber_group);
if (!net->subscr_group) {
talloc_free(net);
return NULL;
}
/* Init back pointer */
net->bsc_data->auto_off_timeout = -1;
net->bsc_data->network = net;
INIT_LLIST_HEAD(&net->bsc_data->mscs);
net->subscr_group->net = net;
net->create_subscriber = 1;
net->country_code = country_code;
net->network_code = network_code;
net->num_bts = 0;
net->reject_cause = GSM48_REJECT_ROAMING_NOT_ALLOWED;
net->T3101 = GSM_T3101_DEFAULT;
net->T3105 = GSM_T3105_DEFAULT;
net->T3113 = GSM_T3113_DEFAULT;
net->T3122 = GSM_T3122_DEFAULT;
/* FIXME: initialize all other timers! */
/* default set of handover parameters */
net->handover.win_rxlev_avg = 10;
net->handover.win_rxqual_avg = 1;
net->handover.win_rxlev_avg_neigh = 10;
net->handover.pwr_interval = 6;
net->handover.pwr_hysteresis = 3;
net->handover.max_distance = 9999;
INIT_LLIST_HEAD(&net->trans_list);
INIT_LLIST_HEAD(&net->upqueue);
INIT_LLIST_HEAD(&net->bts_list);
net->stats.chreq.total = osmo_counter_alloc("net.chreq.total");
net->stats.chreq.no_channel = osmo_counter_alloc("net.chreq.no_channel");
net->stats.handover.attempted = osmo_counter_alloc("net.handover.attempted");
net->stats.handover.no_channel = osmo_counter_alloc("net.handover.no_channel");
net->stats.handover.timeout = osmo_counter_alloc("net.handover.timeout");
net->stats.handover.completed = osmo_counter_alloc("net.handover.completed");
net->stats.handover.failed = osmo_counter_alloc("net.handover.failed");
net->stats.loc_upd_type.attach = osmo_counter_alloc("net.loc_upd_type.attach");
net->stats.loc_upd_type.normal = osmo_counter_alloc("net.loc_upd_type.normal");
net->stats.loc_upd_type.periodic = osmo_counter_alloc("net.loc_upd_type.periodic");
net->stats.loc_upd_type.detach = osmo_counter_alloc("net.imsi_detach.count");
net->stats.loc_upd_resp.reject = osmo_counter_alloc("net.loc_upd_resp.reject");
net->stats.loc_upd_resp.accept = osmo_counter_alloc("net.loc_upd_resp.accept");
net->stats.paging.attempted = osmo_counter_alloc("net.paging.attempted");
net->stats.paging.detached = osmo_counter_alloc("net.paging.detached");
net->stats.paging.completed = osmo_counter_alloc("net.paging.completed");
net->stats.paging.expired = osmo_counter_alloc("net.paging.expired");
net->stats.sms.submitted = osmo_counter_alloc("net.sms.submitted");
net->stats.sms.no_receiver = osmo_counter_alloc("net.sms.no_receiver");
net->stats.sms.delivered = osmo_counter_alloc("net.sms.delivered");
net->stats.sms.rp_err_mem = osmo_counter_alloc("net.sms.rp_err_mem");
net->stats.sms.rp_err_other = osmo_counter_alloc("net.sms.rp_err_other");
net->stats.call.mo_setup = osmo_counter_alloc("net.call.mo_setup");
net->stats.call.mo_connect_ack = osmo_counter_alloc("net.call.mo_connect_ack");
net->stats.call.mt_setup = osmo_counter_alloc("net.call.mt_setup");
net->stats.call.mt_connect = osmo_counter_alloc("net.call.mt_connect");
net->stats.chan.rf_fail = osmo_counter_alloc("net.chan.rf_fail");
net->stats.chan.rll_err = osmo_counter_alloc("net.chan.rll_err");
net->stats.bts.oml_fail = osmo_counter_alloc("net.bts.oml_fail");
net->stats.bts.rsl_fail = osmo_counter_alloc("net.bts.rsl_fail");
net->mncc_recv = mncc_recv;
gsm_net_update_ctype(net);
return net;
}

View File

@@ -54,6 +54,12 @@ void *tall_paging_ctx;
#define PAGING_TIMER 0, 500000
/*
* TODO MSCSPLIT: the paging in libbsc is closely tied to MSC land in that the
* MSC realm callback functions used to be invoked from the BSC/BTS level. So
* this entire file needs to be rewired for use with an A interface.
*/
/*
* Kill one paging request update the internal list...
*/

View File

@@ -42,6 +42,7 @@ int bsc_vty_go_parent(struct vty *vty)
vty->node = CONFIG_NODE;
vty->index = NULL;
break;
#ifdef ROLE_BSC
case BTS_NODE:
vty->node = GSMNET_NODE;
{
@@ -69,6 +70,7 @@ int bsc_vty_go_parent(struct vty *vty)
vty->index_sub = &ts->trx->description;
}
break;
#endif
case OML_NODE:
case OM2K_NODE:
vty->node = ENABLE_NODE;
@@ -106,7 +108,7 @@ int bsc_vty_go_parent(struct vty *vty)
case BSC_NODE:
case MSC_NODE:
case MNCC_INT_NODE:
case NITB_NODE:
case CSCN_NODE:
default:
if (bsc_vty_is_config_node(vty, vty->node))
vty->node = CONFIG_NODE;

View File

@@ -41,74 +41,74 @@ static const struct log_info_cat default_categories[] = {
.name = "DRLL",
.description = "A-bis Radio Link Layer (RLL)",
.color = "\033[1;31m",
.enabled = 1, .loglevel = LOGL_NOTICE,
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DCC] = {
.name = "DCC",
.description = "Layer3 Call Control (CC)",
.color = "\033[1;32m",
.enabled = 1, .loglevel = LOGL_NOTICE,
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DMM] = {
.name = "DMM",
.description = "Layer3 Mobility Management (MM)",
.color = "\033[1;33m",
.enabled = 1, .loglevel = LOGL_NOTICE,
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DRR] = {
.name = "DRR",
.description = "Layer3 Radio Resource (RR)",
.color = "\033[1;34m",
.enabled = 1, .loglevel = LOGL_NOTICE,
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DRSL] = {
.name = "DRSL",
.description = "A-bis Radio Siganlling Link (RSL)",
.color = "\033[1;35m",
.enabled = 1, .loglevel = LOGL_NOTICE,
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DNM] = {
.name = "DNM",
.description = "A-bis Network Management / O&M (NM/OML)",
.color = "\033[1;36m",
.enabled = 1, .loglevel = LOGL_INFO,
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DMNCC] = {
.name = "DMNCC",
.description = "MNCC API for Call Control application",
.color = "\033[1;39m",
.enabled = 1, .loglevel = LOGL_NOTICE,
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DPAG] = {
.name = "DPAG",
.description = "Paging Subsystem",
.color = "\033[1;38m",
.enabled = 1, .loglevel = LOGL_NOTICE,
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DMEAS] = {
.name = "DMEAS",
.description = "Radio Measurement Processing",
.enabled = 0, .loglevel = LOGL_NOTICE,
.enabled = 0, .loglevel = LOGL_DEBUG,
},
[DSCCP] = {
.name = "DSCCP",
.description = "SCCP Protocol",
.enabled = 1, .loglevel = LOGL_NOTICE,
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DMSC] = {
.name = "DMSC",
.description = "Mobile Switching Center",
.enabled = 1, .loglevel = LOGL_NOTICE,
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DMGCP] = {
.name = "DMGCP",
.description = "Media Gateway Control Protocol",
.enabled = 1, .loglevel = LOGL_NOTICE,
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DHO] = {
.name = "DHO",
.description = "Hand-Over",
.enabled = 1, .loglevel = LOGL_NOTICE,
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DDB] = {
.name = "DDB",
@@ -118,7 +118,7 @@ static const struct log_info_cat default_categories[] = {
[DREF] = {
.name = "DREF",
.description = "Reference Counting",
.enabled = 0, .loglevel = LOGL_NOTICE,
.enabled = 0, .loglevel = LOGL_DEBUG,
},
[DGPRS] = {
.name = "DGPRS",
@@ -128,7 +128,7 @@ static const struct log_info_cat default_categories[] = {
[DNS] = {
.name = "DNS",
.description = "GPRS Network Service (NS)",
.enabled = 1, .loglevel = LOGL_INFO,
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DBSSGP] = {
.name = "DBSSGP",
@@ -148,12 +148,12 @@ static const struct log_info_cat default_categories[] = {
[DNAT] = {
.name = "DNAT",
.description = "GSM 08.08 NAT/Multiplexer",
.enabled = 1, .loglevel = LOGL_NOTICE,
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DCTRL] = {
.name = "DCTRL",
.description = "Control interface",
.enabled = 1, .loglevel = LOGL_NOTICE,
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DSMPP] = {
.name = "DSMPP",
@@ -165,6 +165,21 @@ static const struct log_info_cat default_categories[] = {
.description = "BSC/NAT IMSI based filtering",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DRANAP] = {
.name = "DRANAP",
.description = "Radio Access Network Application Part Protocol",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DIUCS] = {
.name = "DIUCS",
.description = "Iu-CS Protocol",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
[DSUA] = {
.name = "DSUA",
.description = "SCCP User Adaptation Protocol",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
};
enum log_filter {

View File

@@ -70,25 +70,6 @@ int gsm_bts_model_register(struct gsm_bts_model *model)
return 0;
}
/* 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)
{
struct gsm_bts *neigh;
/* FIXME: use some better heuristics here to determine which cell
* using this ARFCN really is closest to the target cell. For
* now we simply assume that each ARFCN will only be used by one
* cell */
llist_for_each_entry(neigh, &bts->network->bts_list, list) {
if (neigh->c0->arfcn == arfcn &&
neigh->bsic == bsic)
return neigh;
}
return NULL;
}
const struct value_string bts_type_names[_NUM_GSM_BTS_TYPE+1] = {
{ GSM_BTS_TYPE_UNKNOWN, "unknown" },
{ GSM_BTS_TYPE_BS11, "bs11" },
@@ -228,19 +209,6 @@ int bts_gprs_mode_is_compat(struct gsm_bts *bts, enum bts_gprs_mode mode)
return 1;
}
struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan)
{
struct gsm_meas_rep *meas_rep;
meas_rep = &lchan->meas_rep[lchan->meas_rep_idx];
memset(meas_rep, 0, sizeof(*meas_rep));
meas_rep->lchan = lchan;
lchan->meas_rep_idx = (lchan->meas_rep_idx + 1)
% ARRAY_SIZE(lchan->meas_rep);
return meas_rep;
}
int gsm_btsmodel_set_feature(struct gsm_bts_model *bts, enum gsm_bts_features feat)
{
return bitvec_set_bit_pos(&bts->features, feat, 1);
@@ -336,7 +304,7 @@ struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net, enum gsm_bts_typ
bts->si_common.chan_desc.att = 1; /* attachment required */
bts->si_common.chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5; /* paging frames */
bts->si_common.chan_desc.bs_ag_blks_res = 1; /* reserved AGCH blocks */
bts->si_common.chan_desc.t3212 = 5; /* Use 30 min periodic update interval as sane default */
bts->si_common.chan_desc.t3212 = net->t3212; /* Use network's current value */
set_radio_link_timeout(&bts->si_common.cell_options, 32);
/* Use RADIO LINK TIMEOUT of 32 seconds */

View File

@@ -43,6 +43,9 @@ struct llist_head *subscr_bsc_active_subscribers(void)
char *subscr_name(struct gsm_subscriber *subscr)
{
if (!subscr)
return "unknown";
if (strlen(subscr->name))
return subscr->name;

View File

@@ -17,22 +17,22 @@ extern void *tall_map_ctx;
extern void *tall_upq_ctx;
extern void *tall_ctr_ctx;
void talloc_ctx_init(void)
void talloc_ctx_init(void *ctx_root)
{
tall_msgb_ctx = talloc_named_const(tall_bsc_ctx, 0, "msgb");
tall_fle_ctx = talloc_named_const(tall_bsc_ctx, 0,
tall_msgb_ctx = talloc_named_const(ctx_root, 0, "msgb");
tall_fle_ctx = talloc_named_const(ctx_root, 0,
"bs11_file_list_entry");
tall_locop_ctx = talloc_named_const(tall_bsc_ctx, 0, "loc_updating_oper");
tall_authciphop_ctx = talloc_named_const(tall_bsc_ctx, 0, "auth_ciph_oper");
tall_gsms_ctx = talloc_named_const(tall_bsc_ctx, 0, "sms");
tall_subscr_ctx = talloc_named_const(tall_bsc_ctx, 0, "subscriber");
tall_sub_req_ctx = talloc_named_const(tall_bsc_ctx, 0, "subscr_request");
tall_call_ctx = talloc_named_const(tall_bsc_ctx, 0, "gsm_call");
tall_paging_ctx = talloc_named_const(tall_bsc_ctx, 0, "paging_request");
tall_sigh_ctx = talloc_named_const(tall_bsc_ctx, 0, "signal_handler");
tall_tqe_ctx = talloc_named_const(tall_bsc_ctx, 0, "subch_txq_entry");
tall_trans_ctx = talloc_named_const(tall_bsc_ctx, 0, "transaction");
tall_map_ctx = talloc_named_const(tall_bsc_ctx, 0, "trau_map_entry");
tall_upq_ctx = talloc_named_const(tall_bsc_ctx, 0, "trau_upq_entry");
tall_ctr_ctx = talloc_named_const(tall_bsc_ctx, 0, "counter");
tall_locop_ctx = talloc_named_const(ctx_root, 0, "loc_updating_oper");
tall_authciphop_ctx = talloc_named_const(ctx_root, 0, "auth_ciph_oper");
tall_gsms_ctx = talloc_named_const(ctx_root, 0, "sms");
tall_subscr_ctx = talloc_named_const(ctx_root, 0, "subscriber");
tall_sub_req_ctx = talloc_named_const(ctx_root, 0, "subscr_request");
tall_call_ctx = talloc_named_const(ctx_root, 0, "gsm_call");
tall_paging_ctx = talloc_named_const(ctx_root, 0, "paging_request");
tall_sigh_ctx = talloc_named_const(ctx_root, 0, "signal_handler");
tall_tqe_ctx = talloc_named_const(ctx_root, 0, "subch_txq_entry");
tall_trans_ctx = talloc_named_const(ctx_root, 0, "transaction");
tall_map_ctx = talloc_named_const(ctx_root, 0, "trau_map_entry");
tall_upq_ctx = talloc_named_const(ctx_root, 0, "trau_upq_entry");
tall_ctr_ctx = talloc_named_const(ctx_root, 0, "counter");
}

View File

@@ -0,0 +1,10 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) \
$(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(LIBCRYPTO_CFLAGS) \
$(LIBASN1C_CFLAGS) \
$(LIBOSMOSIGTRAN_CFLAGS) $(LIBOSMORANAP_CFLAGS)
noinst_LIBRARIES = libiu.a
libiu_a_SOURCES = iu.c

771
openbsc/src/libiu/iu.c Normal file
View File

@@ -0,0 +1,771 @@
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <osmocom/core/select.h>
#include <osmocom/core/prim.h>
#include <osmocom/core/talloc.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/application.h>
#include <osmocom/vty/logging.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/gprs/gprs_msgb.h>
#include <osmocom/sigtran/sua.h>
#include <osmocom/sigtran/sccp_sap.h>
#include <osmocom/sigtran/sccp_helpers.h>
#include <openbsc/gprs_sgsn.h>
#include <openbsc/iu.h>
#include <openbsc/debug.h>
#include <pdp.h>
#include <osmocom/ranap/ranap_ies_defs.h>
#include <osmocom/ranap/ranap_common.h>
#include <osmocom/ranap/ranap_common_cn.h>
#include <osmocom/ranap/ranap_msg_factory.h>
#include <asn1c/asn1helpers.h>
/* Parsed global RNC id. See also struct RANAP_GlobalRNC_ID, and note that the
* PLMN identity is a BCD representation of the MCC and MNC.
* See iu_grnc_id_parse(). */
struct iu_grnc_id {
uint16_t mcc;
uint16_t mnc;
uint16_t rnc_id;
};
/* A remote RNC (Radio Network Controller, like BSC but for UMTS) that has
* called us and is currently reachable at the given osmo_sua_link. So, when we
* know a LAC for a subscriber, we can page it at the RNC matching that LAC or
* RAC. An HNB-GW typically presents itself as if it were a single RNC, even
* though it may have several RNCs in hNodeBs connected to it. Those will then
* share the same RNC id, which they actually receive and adopt from the HNB-GW
* in the HNBAP HNB REGISTER ACCEPT message. */
struct iu_rnc {
struct llist_head entry;
uint16_t rnc_id;
uint16_t lac; /* Location Area Code (used for CS and PS) */
uint8_t rac; /* Routing Area Code (used for PS only) */
struct osmo_sua_link *link;
};
void *talloc_iu_ctx;
int asn1_xer_print = 1;
void *talloc_asn1_ctx;
iu_recv_cb_t global_iu_recv_cb = NULL;
iu_event_cb_t global_iu_event_cb = NULL;
static LLIST_HEAD(ue_conn_ctx_list);
static LLIST_HEAD(rnc_list);
const struct value_string iu_event_type_names[] = {
#define IU_EVT_STR(X) { X, #X }
IU_EVT_STR(IU_EVENT_RAB_ASSIGN),
IU_EVT_STR(IU_EVENT_SECURITY_MODE_COMPLETE),
IU_EVT_STR(IU_EVENT_IU_RELEASE),
IU_EVT_STR(IU_EVENT_LINK_INVALIDATED),
#undef IU_EVT_STR
};
struct ue_conn_ctx *ue_conn_ctx_alloc(struct osmo_sua_link *link, uint32_t conn_id)
{
struct ue_conn_ctx *ctx = talloc_zero(talloc_iu_ctx, struct ue_conn_ctx);
ctx->link = link;
ctx->conn_id = conn_id;
llist_add(&ctx->list, &ue_conn_ctx_list);
return ctx;
}
struct ue_conn_ctx *ue_conn_ctx_find(struct osmo_sua_link *link,
uint32_t conn_id)
{
struct ue_conn_ctx *ctx;
llist_for_each_entry(ctx, &ue_conn_ctx_list, list) {
if (ctx->link == link && ctx->conn_id == conn_id)
return ctx;
}
return NULL;
}
static struct iu_rnc *iu_rnc_alloc(uint16_t rnc_id, uint16_t lac, uint8_t rac,
struct osmo_sua_link *link)
{
struct iu_rnc *rnc = talloc_zero(talloc_iu_ctx, struct iu_rnc);
rnc->rnc_id = rnc_id;
rnc->lac = lac;
rnc->rac = rac;
rnc->link = link;
llist_add(&rnc->entry, &rnc_list);
LOGP(DRANAP, LOGL_NOTICE, "New RNC %d (LAC=%d RAC=%d)\n",
rnc->rnc_id, rnc->lac, rnc->rac);
return rnc;
}
static struct iu_rnc *iu_rnc_register(uint16_t rnc_id, uint16_t lac,
uint8_t rac, struct osmo_sua_link *link)
{
struct iu_rnc *rnc;
llist_for_each_entry(rnc, &rnc_list, entry) {
if (rnc->rnc_id != rnc_id)
continue;
/* We have this RNC Id registered already. Make sure that the
* details match. */
/* TODO should a mismatch be an error? */
if (rnc->lac != lac || rnc->rac != rac)
LOGP(DRANAP, LOGL_NOTICE, "RNC %d changes its details:"
" LAC=%d RAC=%d --> LAC=%d RAC=%d\n",
rnc->rnc_id, rnc->lac, rnc->rac,
lac, rac);
rnc->lac = lac;
rnc->rac = rac;
if (link && rnc->link != link)
LOGP(DRANAP, LOGL_NOTICE, "RNC %d on new link"
" (LAC=%d RAC=%d)\n",
rnc->rnc_id, rnc->lac, rnc->rac);
rnc->link = link;
return rnc;
}
/* Not found, make a new one. */
return iu_rnc_alloc(rnc_id, lac, rac, link);
}
/* Discard/invalidate all ue_conn_ctx and iu_rnc entries that reference the
* given link, since this link is invalid and about to be deallocated. For
* each ue_conn_ctx, invoke the iu_event_cb_t with IU_EVENT_LINK_INVALIDATED.
*/
void iu_link_del(struct osmo_sua_link *link)
{
struct iu_rnc *rnc, *rnc_next;
llist_for_each_entry_safe(rnc, rnc_next, &rnc_list, entry) {
if (!rnc->link)
continue;
if (rnc->link != link)
continue;
rnc->link = NULL;
llist_del(&rnc->entry);
talloc_free(rnc);
}
struct ue_conn_ctx *uec, *uec_next;
llist_for_each_entry_safe(uec, uec_next, &ue_conn_ctx_list, list) {
if (uec->link != link)
continue;
uec->link = NULL;
global_iu_event_cb(uec, IU_EVENT_LINK_INVALIDATED, NULL);
}
}
/***********************************************************************
* RANAP handling
***********************************************************************/
static int iu_rab_act(struct ue_conn_ctx *ue_ctx, struct msgb *msg)
{
struct osmo_scu_prim *prim;
/* wrap RANAP message in SCCP N-DATA.req */
prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
prim->u.data.conn_id = ue_ctx->conn_id;
osmo_prim_init(&prim->oph,
SCCP_SAP_USER,
OSMO_SCU_PRIM_N_DATA,
PRIM_OP_REQUEST,
msg);
return osmo_sua_user_link_down(ue_ctx->link, &prim->oph);
}
int iu_rab_act_cs(struct ue_conn_ctx *ue_ctx, uint32_t rtp_ip, uint16_t rtp_port)
{
struct msgb *msg;
/* FIXME: Generate unique RAB ID per UE */
msg = ranap_new_msg_rab_assign_voice(1, rtp_ip, rtp_port);
msg->l2h = msg->data;
return iu_rab_act(ue_ctx, msg);
}
int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp, bool use_x213_nsap)
{
struct msgb *msg;
struct sgsn_mm_ctx *mm = pdp->mm;
struct ue_conn_ctx *uectx;
uint32_t ggsn_ip;
uectx = mm->iu.ue_ctx;
/* Get the IP address for ggsn user plane */
memcpy(&ggsn_ip, pdp->lib->gsnru.v, pdp->lib->gsnru.l);
ggsn_ip = htonl(ggsn_ip);
LOGP(DRANAP, LOGL_DEBUG, "Assigning RAB: rab_id=%d, ggsn_ip=%x,"
" teid_gn=%x, use_x213_nsap=%d\n",
rab_id, ggsn_ip, pdp->lib->teid_gn, use_x213_nsap);
msg = ranap_new_msg_rab_assign_data(rab_id, ggsn_ip,
pdp->lib->teid_gn, use_x213_nsap);
msg->l2h = msg->data;
return iu_rab_act(uectx, msg);
}
int iu_rab_deact(struct ue_conn_ctx *ue_ctx, uint8_t rab_id)
{
/* FIXME */
return -1;
}
int iu_tx_sec_mode_cmd(struct ue_conn_ctx *uectx, struct gsm_auth_tuple *tp,
int send_ck, int new_key)
{
struct osmo_scu_prim *prim;
struct msgb *msg;
uint8_t ik[16];
uint8_t ck[16];
unsigned int i;
/* C5 function to derive IK from Kc */
for (i = 0; i < 4; i++)
ik[i] = tp->vec.kc[i] ^ tp->vec.kc[i+4];
memcpy(ik+4, tp->vec.kc, 8);
for (i = 12; i < 16; i++)
ik[i] = ik[i-12];
if (send_ck) {
/* C4 function to derive CK from Kc */
memcpy(ck, tp->vec.kc, 8);
memcpy(ck+8, tp->vec.kc, 8);
}
/* create RANAP message */
msg = ranap_new_msg_sec_mod_cmd(ik, send_ck? ck : NULL, new_key ? RANAP_KeyStatus_new : RANAP_KeyStatus_old);
msg->l2h = msg->data;
/* wrap RANAP message in SCCP N-DATA.req */
prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
prim->u.data.conn_id = uectx->conn_id;
osmo_prim_init(&prim->oph, SCCP_SAP_USER,
OSMO_SCU_PRIM_N_DATA,
PRIM_OP_REQUEST, msg);
osmo_sua_user_link_down(uectx->link, &prim->oph);
return 0;
}
static int iu_grnc_id_parse(struct iu_grnc_id *dst,
struct RANAP_GlobalRNC_ID *src)
{
/* The size is coming from arbitrary sender, check it gracefully */
if (src->pLMNidentity.size != 3) {
LOGP(DRANAP, LOGL_ERROR, "Invalid PLMN Identity size:"
" should be 3, is %d\n", src->pLMNidentity.size);
return -1;
}
gsm48_mcc_mnc_from_bcd(&src->pLMNidentity.buf[0],
&dst->mcc, &dst->mnc);
dst->rnc_id = (uint16_t)src->rNC_ID;
return 0;
}
#if 0
-- not used at present --
static int iu_grnc_id_compose(struct iu_grnc_id *src,
struct RANAP_GlobalRNC_ID *dst)
{
/* The caller must ensure proper size */
OSMO_ASSERT(dst->pLMNidentity.size == 3);
gsm48_mcc_mnc_to_bcd(&dst->pLMNidentity.buf[0],
src->mcc, src->mnc);
dst->rNC_ID = src->rnc_id;
return 0;
}
#endif
static int ranap_handle_co_initial_ue(void *ctx, RANAP_InitialUE_MessageIEs_t *ies)
{
struct ue_conn_ctx *ue_conn = ctx;
struct gprs_ra_id ra_id;
struct iu_grnc_id grnc_id;
uint16_t sai;
struct msgb *msg = msgb_alloc(256, "RANAP->NAS");
if (ranap_parse_lai(&ra_id, &ies->lai) != 0) {
LOGP(DRANAP, LOGL_ERROR, "Failed to parse RANAP LAI IE\n");
return -1;
}
if (ies->presenceMask & INITIALUE_MESSAGEIES_RANAP_RAC_PRESENT) {
ra_id.rac = asn1str_to_u8(&ies->rac);
}
if (iu_grnc_id_parse(&grnc_id, &ies->globalRNC_ID) != 0) {
LOGP(DRANAP, LOGL_ERROR,
"Failed to parse RANAP Global-RNC-ID IE\n");
return -1;
}
sai = asn1str_to_u16(&ies->sai.sAC);
msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size);
memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size);
/* Make sure we know the RNC Id and LAC+RAC coming in on this connection. */
iu_rnc_register(grnc_id.rnc_id, ra_id.lac, ra_id.rac, ue_conn->link);
ue_conn->ra_id = ra_id;
/* Feed into the MM layer */
msg->dst = ctx;
global_iu_recv_cb(msg, &ra_id, &sai);
msgb_free(msg);
return 0;
}
static int ranap_handle_co_dt(void *ctx, RANAP_DirectTransferIEs_t *ies)
{
struct gprs_ra_id _ra_id, *ra_id = NULL;
uint16_t _sai, *sai = NULL;
struct msgb *msg = msgb_alloc(256, "RANAP->NAS");
if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_LAI_PRESENT) {
if (ranap_parse_lai(&_ra_id, &ies->lai) != 0) {
LOGP(DRANAP, LOGL_ERROR, "Failed to parse RANAP LAI IE\n");
return -1;
}
ra_id = &_ra_id;
if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_RAC_PRESENT) {
_ra_id.rac = asn1str_to_u8(&ies->rac);
}
if (ies->presenceMask & DIRECTTRANSFERIES_RANAP_SAI_PRESENT) {
_sai = asn1str_to_u16(&ies->sai.sAC);
sai = &_sai;
}
}
msgb_gmmh(msg) = msgb_put(msg, ies->nas_pdu.size);
memcpy(msgb_gmmh(msg), ies->nas_pdu.buf, ies->nas_pdu.size);
/* Feed into the MM/CC/SMS-CP layer */
msg->dst = ctx;
global_iu_recv_cb(msg, ra_id, sai);
msgb_free(msg);
return 0;
}
static int ranap_handle_co_err_ind(void *ctx, RANAP_ErrorIndicationIEs_t *ies)
{
if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT)
LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication (%s)\n",
ranap_cause_str(&ies->cause));
else
LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication\n");
return 0;
}
int iu_tx(struct msgb *msg_nas, uint8_t sapi)
{
struct ue_conn_ctx *uectx = msg_nas->dst;
struct msgb *msg;
struct osmo_scu_prim *prim;
LOGP(DRANAP, LOGL_INFO, "Transmitting L3 Message as RANAP DT (SUA link %p conn_id %u)\n",
uectx->link, uectx->conn_id);
msg = ranap_new_msg_dt(sapi, msg_nas->data, msgb_length(msg_nas));
msgb_free(msg_nas);
msg->l2h = msg->data;
prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
prim->u.data.conn_id = uectx->conn_id;
osmo_prim_init(&prim->oph, SCCP_SAP_USER,
OSMO_SCU_PRIM_N_DATA,
PRIM_OP_REQUEST, msg);
osmo_sua_user_link_down(uectx->link, &prim->oph);
return 0;
}
static int ranap_handle_co_iu_rel_req(struct ue_conn_ctx *ctx, RANAP_Iu_ReleaseRequestIEs_t *ies)
{
struct msgb *msg;
struct osmo_scu_prim *prim;
LOGP(DRANAP, LOGL_INFO, "Received Iu Release Request, Sending Release Command\n");
msg = ranap_new_msg_iu_rel_cmd(&ies->cause);
msg->l2h = msg->data;
prim = (struct osmo_scu_prim *) msgb_push(msg, sizeof(*prim));
prim->u.data.conn_id = ctx->conn_id;
osmo_prim_init(&prim->oph, SCCP_SAP_USER,
OSMO_SCU_PRIM_N_DATA,
PRIM_OP_REQUEST, msg);
osmo_sua_user_link_down(ctx->link, &prim->oph);
return 0;
}
static int ranap_handle_co_rab_ass_resp(struct ue_conn_ctx *ctx, RANAP_RAB_AssignmentResponseIEs_t *ies)
{
int rc = -1;
LOGP(DRANAP, LOGL_INFO, "RAB Asignment Response:");
if (ies->presenceMask & RAB_ASSIGNMENTRESPONSEIES_RANAP_RAB_SETUPORMODIFIEDLIST_PRESENT) {
/* TODO: Iterate over list of SetupOrModifiedList IEs and handle each one */
RANAP_IE_t *ranap_ie = ies->raB_SetupOrModifiedList.raB_SetupOrModifiedList_ies.list.array[0];
RANAP_RAB_SetupOrModifiedItemIEs_t setup_ies;
rc = ranap_decode_rab_setupormodifieditemies_fromlist(&setup_ies, &ranap_ie->value);
if (rc) {
LOGP(DRANAP, LOGL_ERROR, "Error in ranap_decode_rab_setupormodifieditemies()\n");
return rc;
}
rc = global_iu_event_cb(ctx, IU_EVENT_RAB_ASSIGN, &setup_ies);
ranap_free_rab_setupormodifieditemies(&setup_ies);
}
LOGPC(DRANAP, LOGL_INFO, "\n");
return rc;
}
/* Entry point for connection-oriented RANAP message */
static void cn_ranap_handle_co(void *ctx, ranap_message *message)
{
int rc;
LOGP(DRANAP, LOGL_NOTICE, "handle_co(dir=%u, proc=%u)\n", message->direction, message->procedureCode);
switch (message->direction) {
case RANAP_RANAP_PDU_PR_initiatingMessage:
switch (message->procedureCode) {
case RANAP_ProcedureCode_id_InitialUE_Message:
rc = ranap_handle_co_initial_ue(ctx, &message->msg.initialUE_MessageIEs);
break;
case RANAP_ProcedureCode_id_DirectTransfer:
rc = ranap_handle_co_dt(ctx, &message->msg.directTransferIEs);
break;
case RANAP_ProcedureCode_id_ErrorIndication:
rc = ranap_handle_co_err_ind(ctx, &message->msg.errorIndicationIEs);
break;
case RANAP_ProcedureCode_id_Iu_ReleaseRequest:
/* Iu Release Request */
rc = ranap_handle_co_iu_rel_req(ctx, &message->msg.iu_ReleaseRequestIEs);
break;
default:
LOGP(DRANAP, LOGL_ERROR, "Received Initiating Message: unknown Procedure Code %d\n",
message->procedureCode);
rc = -1;
break;
}
break;
case RANAP_RANAP_PDU_PR_successfulOutcome:
switch (message->procedureCode) {
case RANAP_ProcedureCode_id_SecurityModeControl:
/* Security Mode Complete */
rc = global_iu_event_cb(ctx, IU_EVENT_SECURITY_MODE_COMPLETE, NULL);
break;
case RANAP_ProcedureCode_id_Iu_Release:
/* Iu Release Complete */
rc = global_iu_event_cb(ctx, IU_EVENT_IU_RELEASE, NULL);
if (rc) {
LOGP(DRANAP, LOGL_ERROR, "Iu Release event: Iu Event callback returned %d\n",
rc);
}
break;
default:
LOGP(DRANAP, LOGL_ERROR, "Received Successful Outcome: unknown Procedure Code %d\n",
message->procedureCode);
rc = -1;
break;
}
break;
case RANAP_RANAP_PDU_PR_outcome:
switch (message->procedureCode) {
case RANAP_ProcedureCode_id_RAB_Assignment:
/* RAB Assignment Response */
rc = ranap_handle_co_rab_ass_resp(ctx, &message->msg.raB_AssignmentResponseIEs);
break;
default:
LOGP(DRANAP, LOGL_ERROR, "Received Outcome: unknown Procedure Code %d\n",
message->procedureCode);
rc = -1;
break;
}
break;
case RANAP_RANAP_PDU_PR_unsuccessfulOutcome:
default:
LOGP(DRANAP, LOGL_ERROR, "Received Unsuccessful Outcome: Procedure Code %d\n",
message->procedureCode);
rc = -1;
break;
}
if (rc) {
LOGP(DRANAP, LOGL_ERROR, "Error in cn_ranap_handle_co (%d)\n",
rc);
/* TODO handling of the error? */
}
}
static int ranap_handle_cl_reset_req(void *ctx, RANAP_ResetIEs_t *ies)
{
/* FIXME: send reset response */
return -1;
}
static int ranap_handle_cl_err_ind(void *ctx, RANAP_ErrorIndicationIEs_t *ies)
{
if (ies->presenceMask & ERRORINDICATIONIES_RANAP_CAUSE_PRESENT)
LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication (%s)\n",
ranap_cause_str(&ies->cause));
else
LOGP(DRANAP, LOGL_ERROR, "Rx Error Indication\n");
return 0;
}
/* Entry point for connection-less RANAP message */
static void cn_ranap_handle_cl(void *ctx, ranap_message *message)
{
int rc;
switch (message->direction) {
case RANAP_RANAP_PDU_PR_initiatingMessage:
switch (message->procedureCode) {
case RANAP_ProcedureCode_id_Reset:
/* received reset.req, send reset.resp */
rc = ranap_handle_cl_reset_req(ctx, &message->msg.resetIEs);
break;
case RANAP_ProcedureCode_id_ErrorIndication:
rc = ranap_handle_cl_err_ind(ctx, &message->msg.errorIndicationIEs);
break;
default:
rc = -1;
break;
}
break;
case RANAP_RANAP_PDU_PR_successfulOutcome:
case RANAP_RANAP_PDU_PR_unsuccessfulOutcome:
case RANAP_RANAP_PDU_PR_outcome:
default:
rc = -1;
break;
}
if (rc) {
LOGP(DRANAP, LOGL_ERROR, "Error in cn_ranap_handle_cl (%d)\n",
rc);
/* TODO handling of the error? */
}
}
/***********************************************************************
* Paging
***********************************************************************/
/* Send a paging command down a given SUA link. tmsi and paging_cause are
* optional and may be passed NULL and 0, respectively, to disable their use.
* See enum RANAP_PagingCause.
*
* If TMSI is given, the IMSI is not sent over the air interface. Nevertheless,
* the IMSI is still required for resolution in the HNB-GW and/or(?) RNC. */
static int iu_tx_paging_cmd(struct osmo_sua_link *link,
const char *imsi, const uint32_t *tmsi,
bool is_ps, uint32_t paging_cause)
{
struct msgb *msg;
msg = ranap_new_msg_paging_cmd(imsi, tmsi, is_ps? 1 : 0, paging_cause);
msg->l2h = msg->data;
return osmo_sccp_tx_unitdata_ranap(link, 1, 2, msg->data,
msgb_length(msg));
}
static int iu_page(const char *imsi, const uint32_t *tmsi_or_ptimsi,
uint16_t lac, uint8_t rac, bool is_ps)
{
struct iu_rnc *rnc;
int pagings_sent = 0;
if (tmsi_or_ptimsi) {
LOGP(DRANAP, LOGL_DEBUG, "%s: Looking for RNCs to page for IMSI %s"
" (paging will use %s %x)\n",
is_ps? "IuPS" : "IuCS",
imsi,
is_ps? "PTMSI" : "TMSI",
*tmsi_or_ptimsi);
} else {
LOGP(DRANAP, LOGL_DEBUG, "%s: Looking for RNCs to page for IMSI %s"
" (paging will use IMSI)\n",
is_ps? "IuPS" : "IuCS",
imsi
);
}
llist_for_each_entry(rnc, &rnc_list, entry) {
if (!rnc->link) {
/* Not actually connected, don't count it. */
continue;
}
if (rnc->lac != lac)
continue;
if (is_ps && rnc->rac != rac)
continue;
/* Found a match! */
if (iu_tx_paging_cmd(rnc->link, imsi, tmsi_or_ptimsi, is_ps, 0)
== 0) {
LOGP(DRANAP, LOGL_DEBUG,
"%s: Paged for IMSI %s on RNC %d, on SUA link %p\n",
is_ps? "IuPS" : "IuCS",
imsi, rnc->rnc_id, rnc->link);
pagings_sent ++;
}
}
/* Some logging... */
if (pagings_sent > 0) {
LOGP(DRANAP, LOGL_DEBUG,
"%s: %d RNCs were paged for IMSI %s.\n",
is_ps? "IuPS" : "IuCS",
pagings_sent, imsi);
}
else {
if (is_ps) {
LOGP(DRANAP, LOGL_ERROR, "IuPS: Found no RNC to page for"
" LAC %d RAC %d (would have paged IMSI %s)\n",
lac, rac, imsi);
}
else {
LOGP(DRANAP, LOGL_ERROR, "IuCS: Found no RNC to page for"
" LAC %d (would have paged IMSI %s)\n",
lac, imsi);
}
}
return pagings_sent;
}
int iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac)
{
return iu_page(imsi, tmsi, lac, 0, false);
}
int iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac)
{
return iu_page(imsi, ptmsi, lac, rac, true);
}
/***********************************************************************
*
***********************************************************************/
int tx_unitdata(struct osmo_sua_link *link);
int tx_conn_req(struct osmo_sua_link *link, uint32_t conn_id);
struct osmo_prim_hdr *make_conn_req(uint32_t conn_id);
struct osmo_prim_hdr *make_dt1_req(uint32_t conn_id, const uint8_t *data, unsigned int len);
struct osmo_prim_hdr *make_conn_resp(struct osmo_scu_connect_param *param)
{
struct msgb *msg = msgb_alloc(1024, "conn_resp");
struct osmo_scu_prim *prim;
prim = (struct osmo_scu_prim *) msgb_put(msg, sizeof(*prim));
osmo_prim_init(&prim->oph, SCCP_SAP_USER,
OSMO_SCU_PRIM_N_CONNECT,
PRIM_OP_RESPONSE, msg);
memcpy(&prim->u.connect, param, sizeof(prim->u.connect));
return &prim->oph;
}
static int sccp_sap_up(struct osmo_prim_hdr *oph, void *link)
{
struct osmo_scu_prim *prim = (struct osmo_scu_prim *) oph;
struct osmo_prim_hdr *resp = NULL;
int rc;
struct ue_conn_ctx *ue;
printf("sccp_sap_up(%s)\n", osmo_scu_prim_name(oph));
switch (OSMO_PRIM_HDR(oph)) {
case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM):
/* confirmation of outbound connection */
rc = -1;
break;
case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_INDICATION):
/* indication of new inbound connection request*/
printf("N-CONNECT.ind(X->%u)\n", prim->u.connect.conn_id);
if (/* prim->u.connect.called_addr.ssn != OSMO_SCCP_SSN_RANAP || */
!msgb_l2(oph->msg) || msgb_l2len(oph->msg) == 0) {
LOGP(DGPRS, LOGL_NOTICE, "Received invalid N-CONNECT.ind\n");
return 0;
}
ue = ue_conn_ctx_alloc(link, prim->u.connect.conn_id);
/* first ensure the local SUA/SCCP socket is ACTIVE */
resp = make_conn_resp(&prim->u.connect);
osmo_sua_user_link_down(link, resp);
/* then handle the RANAP payload */
rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg));
break;
case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION):
/* indication of disconnect */
printf("N-DISCONNECT.ind(%u)\n", prim->u.disconnect.conn_id);
ue = ue_conn_ctx_find(link, prim->u.disconnect.conn_id);
rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg));
break;
case OSMO_PRIM(OSMO_SCU_PRIM_N_DATA, PRIM_OP_INDICATION):
/* connection-oriented data received */
printf("N-DATA.ind(%u, %s)\n", prim->u.data.conn_id,
osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
/* resolve UE context */
ue = ue_conn_ctx_find(link, prim->u.data.conn_id);
rc = ranap_cn_rx_co(cn_ranap_handle_co, ue, msgb_l2(oph->msg), msgb_l2len(oph->msg));
break;
case OSMO_PRIM(OSMO_SCU_PRIM_N_UNITDATA, PRIM_OP_INDICATION):
/* connection-less data received */
printf("N-UNITDATA.ind(%s)\n",
osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
rc = ranap_cn_rx_cl(cn_ranap_handle_cl, link, msgb_l2(oph->msg), msgb_l2len(oph->msg));
break;
default:
rc = -1;
break;
}
msgb_free(oph->msg);
return rc;
}
int iu_init(void *ctx, const char *listen_addr, uint16_t listen_port,
iu_recv_cb_t iu_recv_cb, iu_event_cb_t iu_event_cb)
{
struct osmo_sua_user *user;
talloc_iu_ctx = talloc_named_const(ctx, 1, "iu");
talloc_asn1_ctx = talloc_named_const(talloc_iu_ctx, 1, "asn1");
global_iu_recv_cb = iu_recv_cb;
global_iu_event_cb = iu_event_cb;
osmo_sua_set_log_area(DSUA);
user = osmo_sua_user_create(talloc_iu_ctx, sccp_sap_up, talloc_iu_ctx);
return osmo_sua_server_listen(user, listen_addr, listen_port);
}

View File

@@ -1,4 +1,5 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) \
-DCOMPILING_LIBMSC=1
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) \
$(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBSMPP34_CFLAGS)
@@ -8,7 +9,7 @@ noinst_LIBRARIES = libmsc.a
libmsc_a_SOURCES = auth.c \
db.c \
gsm_04_08.c gsm_04_11.c gsm_04_11_helper.c \
gsm_04_08.c gsm_04_11.c \
gsm_04_80.c \
gsm_subscriber.c \
mncc.c mncc_builtin.c mncc_sock.c \
@@ -18,8 +19,11 @@ libmsc_a_SOURCES = auth.c \
token_auth.c \
ussd.c \
vty_interface_layer3.c \
cscn_vty.c \
transaction.c \
osmo_msc.c ctrl_commands.c meas_feed.c
osmo_msc.c ctrl_commands.c meas_feed.c \
msc_api.c msc_ifaces.c iu_cs.c \
a_iface.c
if BUILD_SMPP
noinst_HEADERS += smpp_smsc.h

View File

@@ -0,0 +1,77 @@
/* A-interface implementation, from MSC to BSC */
/* (C) 2016 by sysmocom s.m.f.c GmbH <info@sysmocom.de>
*
* 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/core/msgb.h>
#include <osmocom/core/logging.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/msc_ifaces.h>
int a_tx(struct msgb *msg)
{
LOGP(DMSC, LOGL_ERROR, "message to be sent to BSC, but A-interface"
" not implemented.\n%s\n", osmo_hexdump(msg->data, msg->len));
return -1;
}
int gsm0808_cipher_mode(struct gsm_subscriber_connection *conn, int cipher,
const uint8_t *key, int len, int include_imeisv)
{
/* TODO generalize for A- and Iu interfaces, don't name after 08.08 */
LOGP(DMSC, LOGL_ERROR, "gsm0808_cipher_mode(): message to be sent to"
" BSC, but A interface not yet implemented.\n");
return -1;
}
/* from gsm_04_08_utils.c *****/
/* 9.2.5 CM service accept */
int gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn)
{
struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERV ACC");
struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
gh->proto_discr = GSM48_PDISC_MM;
gh->msg_type = GSM48_MT_MM_CM_SERV_ACC;
DEBUGP(DMM, "-> CM SERVICE ACCEPT\n");
return msc_tx_dtap(conn, msg);
}
/* 9.2.6 CM service reject */
int gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn,
enum gsm48_reject_value value)
{
struct msgb *msg;
msg = gsm48_create_mm_serv_rej(value);
if (!msg) {
LOGP(DMM, LOGL_ERROR, "Failed to allocate CM Service Reject.\n");
return -1;
}
DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value);
return msc_tx_dtap(conn, msg);
}

View File

@@ -91,8 +91,6 @@ int auth_get_tuple_for_subscr(struct gsm_auth_tuple *atuple,
/* Get subscriber info (if any) */
rc = db_get_authinfo_for_subscr(&ainfo, subscr);
if (rc < 0) {
LOGP(DMM, LOGL_NOTICE,
"No retrievable Ki for subscriber, skipping auth\n");
return rc == -ENOENT ? AUTH_NOT_AVAIL : AUTH_ERROR;
}
@@ -134,11 +132,13 @@ int auth_get_tuple_for_subscr(struct gsm_auth_tuple *atuple,
case AUTH_ALGO_XOR:
if (_use_xor(&ainfo, atuple))
/* non-zero return value means failure */
return AUTH_NOT_AVAIL;
break;
case AUTH_ALGO_COMP128v1:
if (_use_comp128_v1(&ainfo, atuple))
/* non-zero return value means failure */
return AUTH_NOT_AVAIL;
break;

View File

@@ -0,0 +1,100 @@
/* MSC interface to quagga VTY */
/* (C) 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
* Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c)
* (C) 2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2009-2011 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/>.
*
*/
/* NOTE: I would have liked to call this the MSC_NODE instead of the CSCN_NODE,
* but MSC_NODE already exists to configure a remote MSC for osmo-bsc. */
#include <osmocom/vty/command.h>
#include <openbsc/vty.h>
#include <openbsc/gsm_data.h>
static struct cmd_node cscn_node = {
CSCN_NODE,
"%s(config-cscn)# ",
1,
};
DEFUN(cfg_cscn, cfg_cscn_cmd,
"cscn", "Configure CSCN options")
{
vty->node = CSCN_NODE;
return CMD_SUCCESS;
}
DEFUN(cfg_cscn_subscr_create, cfg_cscn_subscr_create_cmd,
"subscriber-create-on-demand",
"Make a new record when a subscriber is first seen.\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->create_subscriber = 1;
return CMD_SUCCESS;
}
DEFUN(cfg_cscn_no_subscr_create, cfg_cscn_no_subscr_create_cmd,
"no subscriber-create-on-demand",
NO_STR "Make a new record when a subscriber is first seen.\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->create_subscriber = 0;
return CMD_SUCCESS;
}
DEFUN(cfg_cscn_assign_tmsi, cfg_cscn_assign_tmsi_cmd,
"assign-tmsi",
"Assign TMSI during Location Updating.\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->avoid_tmsi = 0;
return CMD_SUCCESS;
}
DEFUN(cfg_cscn_no_assign_tmsi, cfg_cscn_no_assign_tmsi_cmd,
"no assign-tmsi",
NO_STR "Assign TMSI during Location Updating.\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->avoid_tmsi = 1;
return CMD_SUCCESS;
}
static int config_write_cscn(struct vty *vty)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
vty_out(vty, "cscn%s", VTY_NEWLINE);
vty_out(vty, " %ssubscriber-create-on-demand%s",
gsmnet->create_subscriber ? "" : "no ", VTY_NEWLINE);
vty_out(vty, " %sassign-tmsi%s",
gsmnet->avoid_tmsi ? "no " : "", VTY_NEWLINE);
return CMD_SUCCESS;
}
void cscn_vty_init(void)
{
install_element(CONFIG_NODE, &cfg_cscn_cmd);
install_node(&cscn_node, config_write_cscn);
install_element(CSCN_NODE, &cfg_cscn_subscr_create_cmd);
install_element(CSCN_NODE, &cfg_cscn_no_subscr_create_cmd);
install_element(CSCN_NODE, &cfg_cscn_assign_tmsi_cmd);
install_element(CSCN_NODE, &cfg_cscn_no_assign_tmsi_cmd);
}

View File

@@ -891,7 +891,7 @@ struct gsm_subscriber *db_get_subscriber(enum gsm_subscriber_field field,
subscr->id = dbi_result_get_ulonglong(result, "id");
db_set_from_query(subscr, result);
DEBUGP(DDB, "Found Subscriber: ID %llu, IMSI %s, NAME '%s', TMSI %u, EXTEN '%s', LAC %hu, AUTH %u\n",
DEBUGP(DDB, "Found Subscriber: ID %llu, IMSI %s, NAME '%s', TMSI %x, EXTEN '%s', LAC %hu, AUTH %u\n",
subscr->id, subscr->imsi, subscr->name, subscr->tmsi, subscr->extension,
subscr->lac, subscr->authorized);
dbi_result_free(result);

File diff suppressed because it is too large Load Diff

View File

@@ -53,7 +53,7 @@
#include <openbsc/paging.h>
#include <openbsc/bsc_rll.h>
#include <openbsc/chan_alloc.h>
#include <openbsc/bsc_api.h>
#include <openbsc/msc_ifaces.h>
#ifdef BUILD_SMPP
#include "smpp_smsc.h"
@@ -124,7 +124,7 @@ static int gsm411_sendmsg(struct gsm_subscriber_connection *conn, struct msgb *m
{
DEBUGP(DLSMS, "GSM4.11 TX %s\n", osmo_hexdump(msg->data, msg->len));
msg->l3h = msg->data;
return gsm0808_submit_dtap(conn, msg, UM_SAPI_SMS, 1);
return msc_tx_dtap(conn, msg);
}
/* Prefix msg with a 04.08/04.11 CP header */
@@ -304,7 +304,7 @@ try_local:
#endif
/* determine gsms->receiver based on dialled number */
gsms->receiver = subscr_get_by_extension(conn->bts->network->subscr_group,
gsms->receiver = subscr_get_by_extension(conn->network->subscr_group,
gsms->dst.addr);
if (!gsms->receiver) {
#ifdef BUILD_SMPP
@@ -315,14 +315,14 @@ try_local:
rc = smpp_try_deliver(gsms, conn);
if (rc == 1) {
rc = 1; /* cause 1: unknown subscriber */
osmo_counter_inc(conn->bts->network->stats.sms.no_receiver);
osmo_counter_inc(conn->network->stats.sms.no_receiver);
} else if (rc < 0) {
rc = 21; /* cause 21: short message transfer rejected */
/* FIXME: handle the error somehow? */
}
#else
rc = 1; /* cause 1: unknown subscriber */
osmo_counter_inc(conn->bts->network->stats.sms.no_receiver);
osmo_counter_inc(conn->network->stats.sms.no_receiver);
#endif
return rc;
}
@@ -363,7 +363,7 @@ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *m
uint8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
int rc = 0;
osmo_counter_inc(conn->bts->network->stats.sms.submitted);
osmo_counter_inc(conn->network->stats.sms.submitted);
gsms = sms_alloc();
if (!gsms)
@@ -605,7 +605,7 @@ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans,
static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
struct gsm411_rp_hdr *rph)
{
struct gsm_network *net = trans->conn->bts->network;
struct gsm_network *net = trans->conn->network;
struct gsm_sms *sms = trans->sms.sms;
uint8_t cause_len = rph->data[0];
uint8_t cause = rph->data[1];
@@ -805,7 +805,7 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn,
if (!trans) {
DEBUGP(DLSMS, " -> (new transaction)\n");
trans = trans_alloc(conn->bts->network, conn->subscr,
trans = trans_alloc(conn->network, conn->subscr,
GSM48_PDISC_SMS,
transaction_id, new_callref++);
if (!trans) {
@@ -855,19 +855,19 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn,
}
/* Take a SMS in gsm_sms structure and send it through an already
* existing lchan. We also assume that the caller ensured this lchan already
* existing conn. We also assume that the caller ensured this conn already
* has a SAPI3 RLL connection! */
int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
{
struct msgb *msg = gsm411_msgb_alloc();
struct gsm_trans *trans;
uint8_t *data, *rp_ud_len;
uint8_t msg_ref = sms_next_rp_msg_ref(conn);
uint8_t msg_ref = sms_next_rp_msg_ref(&conn->next_rp_ref);
int transaction_id;
int rc;
transaction_id =
trans_assign_trans_id(conn->bts->network, conn->subscr,
trans_assign_trans_id(conn->network, conn->subscr,
GSM48_PDISC_SMS, 0);
if (transaction_id == -1) {
LOGP(DLSMS, LOGL_ERROR, "No available transaction ids\n");
@@ -877,10 +877,10 @@ int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
return -EBUSY;
}
DEBUGP(DLSMS, "send_sms_lchan()\n");
DEBUGP(DLSMS, "gsm411_send_sms()\n");
/* FIXME: allocate transaction with message reference */
trans = trans_alloc(conn->bts->network, conn->subscr,
trans = trans_alloc(conn->network, conn->subscr,
GSM48_PDISC_SMS,
transaction_id, new_callref++);
if (!trans) {
@@ -932,7 +932,7 @@ int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
DEBUGP(DLSMS, "TX: SMS DELIVER\n");
osmo_counter_inc(conn->bts->network->stats.sms.delivered);
osmo_counter_inc(conn->network->stats.sms.delivered);
db_sms_inc_deliver_attempts(trans->sms.sms);
return gsm411_rp_sendmsg(&trans->sms.smr_inst, msg,
@@ -981,16 +981,19 @@ int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
struct gsm_subscriber_connection *conn;
void *res;
/* check if we already have an open lchan to the subscriber.
/* check if we already have an open conn to the subscriber.
* if yes, send the SMS this way */
conn = connection_for_subscr(subscr);
if (conn) {
LOGP(DLSMS, LOGL_DEBUG, "Sending SMS via already open connection %p to %s\n",
conn, subscr_name(subscr));
return gsm411_send_sms(conn, sms);
}
/* if not, we have to start paging */
res = subscr_request_channel(subscr, RSL_CHANNEED_SDCCH,
paging_cb_send_sms, sms);
LOGP(DLSMS, LOGL_DEBUG, "Sending SMS: no connection open, start paging %s\n",
subscr_name(subscr));
res = subscr_request_conn(subscr, paging_cb_send_sms, sms);
if (!res) {
send_signal(S_SMS_UNKNOWN_ERROR, NULL, sms, GSM_PAGING_BUSY);
sms_free(sms);
@@ -1022,7 +1025,7 @@ void gsm411_sapi_n_reject(struct gsm_subscriber_connection *conn)
struct gsm_network *net;
struct gsm_trans *trans, *tmp;
net = conn->bts->network;
net = conn->network;
llist_for_each_entry_safe(trans, tmp, &net->trans_list, entry) {
struct gsm_sms *sms;

View File

@@ -32,7 +32,7 @@
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/gsm_04_80.h>
#include <openbsc/bsc_api.h>
#include <openbsc/msc_ifaces.h>
#include <osmocom/gsm/gsm0480.h>
#include <osmocom/gsm/gsm_utils.h>
@@ -106,7 +106,7 @@ int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
| (1<<7); /* TI direction = 1 */
gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
return gsm0808_submit_dtap(conn, msg, 0, 0);
return msc_tx_dtap(conn, msg);
}
int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
@@ -135,41 +135,21 @@ int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
gh->proto_discr |= req->transaction_id | (1<<7); /* TI direction = 1 */
gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
return gsm0808_submit_dtap(conn, msg, 0, 0);
return msc_tx_dtap(conn, msg);
}
int gsm0480_send_ussdNotify(struct gsm_subscriber_connection *conn, int level, const char *text)
{
struct gsm48_hdr *gh;
struct msgb *msg;
msg = gsm0480_create_unstructuredSS_Notify(level, text);
struct msgb *msg = gsm0480_gen_ussdNotify(level, text);
if (!msg)
return -1;
gsm0480_wrap_invoke(msg, GSM0480_OP_CODE_USS_NOTIFY, 0);
gsm0480_wrap_facility(msg);
/* And finally pre-pend the L3 header */
gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
gh->proto_discr = GSM48_PDISC_NC_SS;
gh->msg_type = GSM0480_MTYPE_REGISTER;
return gsm0808_submit_dtap(conn, msg, 0, 0);
return msc_tx_dtap(conn, msg);
}
int gsm0480_send_releaseComplete(struct gsm_subscriber_connection *conn)
{
struct gsm48_hdr *gh;
struct msgb *msg;
msg = gsm48_msgb_alloc_name("GSM 04.08 USSD REL COMPL");
struct msgb *msg = gsm0480_gen_releaseComplete();
if (!msg)
return -1;
gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
gh->proto_discr = GSM48_PDISC_NC_SS;
gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
return gsm0808_submit_dtap(conn, msg, 0, 0);
return msc_tx_dtap(conn, msg);
}

View File

@@ -38,6 +38,7 @@
#include <openbsc/signal.h>
#include <openbsc/db.h>
#include <openbsc/chan_alloc.h>
#include <openbsc/iu.h>
void *tall_sub_req_ctx;
@@ -47,20 +48,6 @@ int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq,
gsm_cbfn *cb, void *cb_data);
/*
* Struct for pending channel requests. This is managed in the
* llist_head requests of each subscriber. The reference counting
* should work in such a way that a subscriber with a pending request
* remains in memory.
*/
struct subscr_request {
struct llist_head entry;
/* the callback data */
gsm_cbfn *cbfn;
void *param;
};
static struct gsm_subscriber *get_subscriber(struct gsm_subscriber_group *sgrp,
int type, const char *ident)
{
@@ -70,31 +57,32 @@ static struct gsm_subscriber *get_subscriber(struct gsm_subscriber_group *sgrp,
return subscr;
}
/*
* We got the channel assigned and can now hand this channel
* over to one of our callbacks.
*/
/* A connection is established and the paging callbacks may run now. */
static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
struct msgb *msg, void *data, void *param)
struct msgb *msg, void *data, void *param)
{
struct subscr_request *request, *tmp;
struct gsm_subscriber_connection *conn = data;
struct gsm_subscriber *subscr = param;
struct paging_signal_data sig_data;
OSMO_ASSERT(subscr->is_paging);
OSMO_ASSERT(hooknum == GSM_HOOK_RR_PAGING);
OSMO_ASSERT(subscr);
OSMO_ASSERT(!(conn && (conn->subscr != subscr)));
OSMO_ASSERT(!((event == GSM_PAGING_SUCCEEDED) && !conn));
/*
* Stop paging on all other BTS. E.g. if this is
* the first timeout on a BTS then the others will
* timeout soon as well. Let's just stop everything
* and forget we wanted to page.
*/
paging_request_stop(NULL, subscr, NULL, NULL);
LOGP(DPAG, LOGL_DEBUG, "Paging %s for %s (event=%d)\n",
event == GSM_PAGING_SUCCEEDED ? "success" : "failure",
subscr_name(subscr), event);
if (!subscr->is_paging) {
LOGP(DPAG, LOGL_NOTICE,
"Paging Response received for subscriber"
" that is not paging.\n");
}
/* Inform parts of the system we don't know */
sig_data.subscr = subscr;
sig_data.bts = conn ? conn->bts : NULL;
sig_data.conn = conn;
sig_data.paging_result = event;
osmo_signal_dispatch(
@@ -106,83 +94,143 @@ static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
llist_for_each_entry_safe(request, tmp, &subscr->requests, entry) {
llist_del(&request->entry);
request->cbfn(hooknum, event, msg, data, request->param);
if (request->cbfn) {
LOGP(DPAG, LOGL_DEBUG, "Calling paging cbfn.\n");
request->cbfn(hooknum, event, msg, data, request->param);
} else
LOGP(DPAG, LOGL_DEBUG, "Paging without action.\n");
talloc_free(request);
}
/* balanced with the moment we start paging */
subscr->is_paging = 0;
/* balanced with the moment we receive a paging response */
subscr_put(subscr);
return 0;
}
static void paging_timeout_release(struct gsm_subscriber *subscr)
{
DEBUGP(DPAG, "Paging timeout released for %s\n", subscr_name(subscr));
osmo_timer_del(&subscr->paging_timeout);
}
static void paging_timeout(void *data)
{
struct gsm_subscriber *subscr = data;
DEBUGP(DPAG, "Paging timeout reached for %s\n", subscr_name(subscr));
paging_timeout_release(subscr);
subscr_paging_dispatch(GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED,
NULL, NULL, subscr);
}
static void paging_timeout_start(struct gsm_subscriber *subscr)
{
DEBUGP(DPAG, "Starting paging timeout for %s\n", subscr_name(subscr));
subscr->paging_timeout.data = subscr;
subscr->paging_timeout.cb = paging_timeout;
osmo_timer_schedule(&subscr->paging_timeout, 10, 0);
/* TODO: configurable timeout duration? */
}
static int subscr_paging_sec_cb(unsigned int hooknum, unsigned int event,
struct msgb *msg, void *data, void *param)
{
int rc;
struct gsm_subscriber_connection *conn = data;
OSMO_ASSERT(conn);
switch (event) {
case GSM_SECURITY_AUTH_FAILED:
/* Dispatch as paging failure */
LOGP(DPAG, LOGL_ERROR,
"Dropping Paging Response:"
" authorization failed for subscriber %s\n",
subscr_name(conn->subscr));
rc = subscr_paging_dispatch(
GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED,
msg, data, param);
msg, conn, conn->subscr);
break;
case GSM_SECURITY_NOAVAIL:
case GSM_SECURITY_SUCCEEDED:
/* Dispatch as paging failure */
rc = subscr_paging_dispatch(
GSM_HOOK_RR_PAGING, GSM_PAGING_SUCCEEDED,
msg, data, param);
msg, conn, conn->subscr);
break;
default:
LOGP(DPAG, LOGL_FATAL,
"Invalid authorization event: %d\n", event);
rc = -EINVAL;
}
return rc;
}
static int subscr_paging_cb(unsigned int hooknum, unsigned int event,
struct msgb *msg, void *data, void *param)
int subscr_rx_paging_response(struct msgb *msg,
struct gsm_subscriber_connection *conn)
{
struct gsm_subscriber_connection *conn = data;
struct gsm48_hdr *gh;
struct gsm48_pag_resp *pr;
/* Other cases mean problem, dispatch direclty */
if (event != GSM_PAGING_SUCCEEDED)
return subscr_paging_dispatch(hooknum, event, msg, data, param);
/* Get paging response */
/* Get key_seq from Paging Response headers */
gh = msgb_l3(msg);
pr = (struct gsm48_pag_resp *)gh->data;
/* We _really_ have a channel, secure it now ! */
return gsm48_secure_channel(conn, pr->key_seq, subscr_paging_sec_cb, param);
paging_timeout_release(conn->subscr);
/* Secure the connection */
if (subscr_authorized(conn->subscr))
return gsm48_secure_channel(conn, pr->key_seq,
subscr_paging_sec_cb, NULL);
/* Not authorized. Failure. */
subscr_paging_sec_cb(GSM_HOOK_RR_SECURITY, GSM_SECURITY_AUTH_FAILED,
msg, conn, NULL);
return -1;
}
struct subscr_request *subscr_request_channel(struct gsm_subscriber *subscr,
int channel_type, gsm_cbfn *cbfn, void *param)
static int msc_paging_request(struct gsm_subscriber *subscr)
{
/* The subscriber was last seen in subscr->lac. Find out which
* BSCs/RNCs are responsible and send them a paging request via open
* SCCP connections (if any). */
/* TODO Implementing only RNC paging, since this is code on the iu branch.
* Need to add BSC paging at some point. */
return iu_page_cs(subscr->imsi,
subscr->tmsi == GSM_RESERVED_TMSI?
NULL : &subscr->tmsi,
subscr->lac);
}
struct subscr_request *subscr_request_conn(struct gsm_subscriber *subscr,
gsm_cbfn *cbfn, void *param)
{
int rc;
struct subscr_request *request;
/* Start paging.. we know it is async so we can do it before */
if (!subscr->is_paging) {
LOGP(DMM, LOGL_DEBUG, "Subscriber %s not paged yet.\n",
LOGP(DMM, LOGL_DEBUG, "Subscriber %s not paged yet, start paging.\n",
subscr_name(subscr));
rc = paging_request(subscr->group->net, subscr, channel_type,
subscr_paging_cb, subscr);
rc = msc_paging_request(subscr);
if (rc <= 0) {
LOGP(DMM, LOGL_ERROR, "Subscriber %s paging failed: %d\n",
subscr_name(subscr), rc);
return NULL;
}
/* reduced on the first paging callback */
/* reduced in subscr_rx_paging_response() */
subscr_get(subscr);
subscr->is_paging = 1;
LOGP(DMM, LOGL_DEBUG, "Paged subscriber %s.\n",
subscr_name(subscr));
paging_timeout_start(subscr);
}
else {
LOGP(DMM, LOGL_DEBUG, "Subscriber %s already paged.\n",
subscr_name(subscr));
}
/* TODO: Stop paging in case of memory allocation failure */
@@ -268,7 +316,7 @@ struct gsm_subscriber *subscr_get_by_id(struct gsm_subscriber_group *sgrp,
return get_subscriber(sgrp, GSM_SUBSCRIBER_ID, buf);
}
int subscr_update_expire_lu(struct gsm_subscriber *s, struct gsm_bts *bts)
int subscr_update_expire_lu(struct gsm_network *network, struct gsm_subscriber *s)
{
int rc;
@@ -279,27 +327,27 @@ int subscr_update_expire_lu(struct gsm_subscriber *s, struct gsm_bts *bts)
* Timeout is twice the t3212 value plus one minute */
/* Is expiration handling enabled? */
if (bts->si_common.chan_desc.t3212 == 0)
if (network->t3212 == 0)
s->expire_lu = GSM_SUBSCRIBER_NO_EXPIRATION;
else
s->expire_lu = time(NULL) +
(bts->si_common.chan_desc.t3212 * 60 * 6 * 2) + 60;
s->expire_lu = time(NULL) + (network->t3212 * 60 * 6 * 2) + 60;
rc = db_sync_subscriber(s);
db_subscriber_update(s);
return rc;
}
int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason)
int subscr_update(struct gsm_network *network, struct gsm_subscriber *s,
uint16_t lac, int reason)
{
int rc;
/* FIXME: Migrate pending requests from one BSC to another */
switch (reason) {
case GSM_SUBSCRIBER_UPDATE_ATTACHED:
s->group = bts->network->subscr_group;
s->group = network->subscr_group;
/* Indicate "attached to LAC" */
s->lac = bts->location_area_code;
s->lac = lac;
LOGP(DMM, LOGL_INFO, "Subscriber %s ATTACHED LAC=%u\n",
subscr_name(s), s->lac);
@@ -308,12 +356,12 @@ int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason)
* The below will set a new expire_lu but as a side-effect
* the new lac will be saved in the database.
*/
rc = subscr_update_expire_lu(s, bts);
rc = subscr_update_expire_lu(network, s);
osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_ATTACHED, s);
break;
case GSM_SUBSCRIBER_UPDATE_DETACHED:
/* Only detach if we are currently in this area */
if (bts->location_area_code == s->lac)
if (lac == s->lac)
s->lac = GSM_LAC_RESERVED_DETACHED;
LOGP(DMM, LOGL_INFO, "Subscriber %s DETACHED\n", subscr_name(s));
rc = db_sync_subscriber(s);
@@ -352,7 +400,7 @@ static void subscr_expire_callback(void *data, long long unsigned int id)
if (conn && conn->expire_timer_stopped) {
LOGP(DMM, LOGL_DEBUG, "Not expiring subscriber %s (ID %llu)\n",
subscr_name(s), id);
subscr_update_expire_lu(s, conn->bts);
subscr_update_expire_lu(conn->network, s);
subscr_put(s);
return;
}
@@ -370,3 +418,30 @@ void subscr_expire(struct gsm_subscriber_group *sgrp)
{
db_subscriber_expire(sgrp->net, subscr_expire_callback);
}
bool subscr_authorized(struct gsm_subscriber *subscriber)
{
switch (subscriber->group->net->auth_policy) {
case GSM_AUTH_POLICY_CLOSED:
LOGP(DMM, LOGL_DEBUG, "subscriber %s authorized = %d\n",
subscr_name(subscriber), subscriber->authorized);
return subscriber->authorized ? true : false;
case GSM_AUTH_POLICY_TOKEN:
if (subscriber->authorized) {
LOGP(DMM, LOGL_DEBUG,
"subscriber %s authorized = %d\n",
subscr_name(subscriber), subscriber->authorized);
return subscriber->authorized;
}
LOGP(DMM, LOGL_DEBUG, "subscriber %s first contact = %d\n",
subscr_name(subscriber),
(int)(subscriber->flags & GSM_SUBSCRIBER_FIRST_CONTACT));
return (subscriber->flags & GSM_SUBSCRIBER_FIRST_CONTACT);
case GSM_AUTH_POLICY_ACCEPT_ALL:
return true;
default:
LOGP(DMM, LOGL_DEBUG, "unknown auth_policy, rejecting"
" subscriber %s\n", subscr_name(subscriber));
return false;
}
}

173
openbsc/src/libmsc/iu_cs.c Normal file
View File

@@ -0,0 +1,173 @@
#include <inttypes.h>
#include <osmocom/core/logging.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/msc_api.h>
#include <openbsc/iu.h>
#include <openbsc/gsm_subscriber.h>
/* For A-interface see libbsc/bsc_api.c subscr_con_allocate() */
static struct gsm_subscriber_connection *subscr_conn_allocate_iu(struct gsm_network *network,
struct ue_conn_ctx *ue,
uint16_t lac)
{
struct gsm_subscriber_connection *conn;
DEBUGP(DIUCS, "Allocating IuCS subscriber conn: lac %d, link_id %p, conn_id %" PRIx32 "\n",
lac, ue->link, ue->conn_id);
conn = talloc_zero(network, struct gsm_subscriber_connection);
if (!conn)
return NULL;
conn->network = network;
conn->via_iface = IFACE_IU;
conn->iu.ue_ctx = ue;
conn->lac = lac;
llist_add_tail(&conn->entry, &network->subscr_conns);
return conn;
}
static int same_ue_conn(struct ue_conn_ctx *a, struct ue_conn_ctx *b)
{
if (a == b)
return 1;
return (a->link == b->link)
&& (a->conn_id == b->conn_id);
}
static inline void log_subscribers(struct gsm_network *network)
{
if (!log_check_level(DIUCS, LOGL_DEBUG))
return;
struct gsm_subscriber_connection *conn;
int i = 0;
llist_for_each_entry(conn, &network->subscr_conns, entry) {
DEBUGP(DIUCS, "%3d: %s", i, subscr_name(conn->subscr));
switch (conn->via_iface) {
case IFACE_IU:
DEBUGPC(DIUCS, " Iu");
if (conn->iu.ue_ctx) {
DEBUGPC(DIUCS, " link %p, conn_id %d",
conn->iu.ue_ctx->link,
conn->iu.ue_ctx->conn_id
);
}
break;
case IFACE_A:
DEBUGPC(DIUCS, " A");
/* TODO log A-interface connection details */
break;
case IFACE_UNKNOWN:
DEBUGPC(DIUCS, " ?");
break;
default:
DEBUGPC(DIUCS, " invalid");
break;
}
DEBUGPC(DIUCS, "\n");
i++;
}
DEBUGP(DIUCS, "subscribers registered: %d\n", i);
}
/* Return an existing IuCS subscriber connection record for the given link and
* connection IDs, or return NULL if not found. */
struct gsm_subscriber_connection *subscr_conn_lookup_iu(
struct gsm_network *network,
struct ue_conn_ctx *ue)
{
struct gsm_subscriber_connection *conn;
DEBUGP(DIUCS, "Looking for IuCS subscriber: link_id %p, conn_id %" PRIx32 "\n",
ue->link, ue->conn_id);
log_subscribers(network);
llist_for_each_entry(conn, &network->subscr_conns, entry) {
if (conn->via_iface != IFACE_IU)
continue;
if (!same_ue_conn(conn->iu.ue_ctx, ue))
continue;
DEBUGP(DIUCS, "Found IuCS subscriber for link_id %p, conn_id %" PRIx32 "\n",
ue->link, ue->conn_id);
return conn;
}
DEBUGP(DIUCS, "No IuCS subscriber found for link_id %p, conn_id %" PRIx32 "\n",
ue->link, ue->conn_id);
return NULL;
}
/* Receive MM/CC/... message from IuCS (SCCP user SAP).
* msg->dst must reference a struct ue_conn_ctx, which identifies the peer that
* sent the msg.
*
* For A-interface see libbsc/bsc_api.c gsm0408_rcvmsg(). */
int gsm0408_rcvmsg_iucs(struct gsm_network *network, struct msgb *msg,
uint16_t *lac)
{
int rc;
struct ue_conn_ctx *ue_ctx;
struct gsm_subscriber_connection *conn;
ue_ctx = (struct ue_conn_ctx*)msg->dst;
/* TODO: are there message types that could allow us to skip this
* search? */
conn = subscr_conn_lookup_iu(network, ue_ctx);
if (conn && lac && (conn->lac != *lac)) {
LOGP(DIUCS, LOGL_ERROR, "IuCS subscriber has changed LAC"
" within the same connection, discarding connection:"
" %s from LAC %d to %d\n",
subscr_name(conn->subscr), conn->lac, *lac);
/* Deallocate conn with previous LAC */
gsm0408_clear_request(conn, 0);
/* At this point we could be tolerant and allocate a new
* connection, but changing the LAC within the same connection
* is shifty. Rather cancel everything. */
return -1;
}
if (conn) {
/* if we already have a connection, handle DTAP.
gsm0408_dispatch() is aka msc_dtap() */
/* Make sure we don't receive RR over IuCS; otherwise all
* messages handled by gsm0408_dispatch() are of interest (CC,
* MM, SMS, NS_SS, maybe even MM_GPRS and SM_GPRS). */
struct gsm48_hdr *gh = msgb_l3(msg);
uint8_t pdisc = gh->proto_discr & 0x0f;
OSMO_ASSERT(pdisc != GSM48_PDISC_RR);
rc = gsm0408_dispatch(conn, msg);
} else {
/* allocate a new connection */
if (!lac) {
LOGP(DIUCS, LOGL_ERROR, "New IuCS subscriber"
" but no LAC available. Expecting an InitialUE"
" message containing a LAI IE."
" Dropping connection.\n");
return -1;
}
conn = subscr_conn_allocate_iu(network, ue_ctx, *lac);
if (!conn)
abort();
rc = msc_compl_l3(conn, msg, 0);
if (rc != MSC_CONN_ACCEPT) {
gsm0408_clear_request(conn, 0);
rc = -1;
}
else
rc = 0;
}
return rc;
}

View File

@@ -207,9 +207,11 @@ static int mncc_setup_cnf(struct gsm_call *call, int msg_type,
bridge.callref[1] = call->remote_ref;
DEBUGP(DMNCC, "(call %x) Bridging with remote.\n", call->callref);
#if BEFORE_MSCSPLIT
/* in direct mode, we always have to bridge the channels */
if (ipacc_rtp_direct)
return mncc_tx_to_cc(call->net, MNCC_BRIDGE, &bridge);
#endif
/* proxy mode */
if (!net->handover.active) {
@@ -293,11 +295,16 @@ static int mncc_rcv_data(struct gsm_call *call, int msg_type,
return -EIO;
}
#if BEFORE_MSCSPLIT
/* RTP socket of remote end has meanwhile died */
if (!remote_trans->conn->lchan->abis_ip.rtp_socket)
return -EIO;
return rtp_send_frame(remote_trans->conn->lchan->abis_ip.rtp_socket, dfr);
#else
/* not implemented yet! */
return -1;
#endif
}

View File

@@ -0,0 +1,56 @@
/* Implementations for receiving or sending MM|CC|... messages from/to the
* BSC|RNC direction, regardless of which particular external interface is
* actually involved (A or IuCS). */
/* (C) 2016 by sysmocom s.m.f.c GmbH <info@sysmocom.de>
*
* Based on parts of osmo_msc.c:
* (C) 2010,2013 by Holger Hans Peter Freyther <zecke@selfish.org>
* (C) 2010 by On-Waves
*
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU 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/core/logging.h>
#include <openbsc/debug.h>
#include <openbsc/msc_api.h>
#include <openbsc/gsm_data.h>
#include <openbsc/transaction.h>
int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg,
uint16_t chosen_channel)
{
gsm0408_new_conn(conn);
gsm0408_dispatch(conn, msg);
/*
* If this is a silent call we want the channel to remain open as long as
* possible and this is why we accept this connection regardless of any
* pending transaction or ongoing operation.
*/
if (conn->silent_call)
return MSC_CONN_ACCEPT;
if (conn->loc_operation || conn->sec_operation || conn->anch_operation)
return MSC_CONN_ACCEPT;
if (trans_has_conn(conn))
return MSC_CONN_ACCEPT;
LOGP(DRR, LOGL_INFO, "MSC Complete L3: Rejecting connection.\n");
return MSC_CONN_REJECT;
}

View File

@@ -0,0 +1,52 @@
/* Implementation for MSC decisions which interface to send messages out on. */
/* (C) 2016 by sysmocom s.m.f.c GmbH <info@sysmocom.de>
*
* 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/core/logging.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/msc_ifaces.h>
static int msc_tx(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
switch (conn->via_iface) {
case IFACE_A:
msg->dst = conn;
return a_tx(msg);
case IFACE_IU:
msg->dst = conn->iu.ue_ctx;
return iu_tx(msg, 0);
default:
LOGP(DMSC, LOGL_ERROR,
"msc_tx(): conn->via_iface invalid (%d)\n",
conn->via_iface);
return -1;
}
}
int msc_tx_dtap(struct gsm_subscriber_connection *conn,
struct msgb *msg)
{
return msc_tx(conn, msg);
}

View File

@@ -26,6 +26,7 @@
#include <openbsc/transaction.h>
#include <openbsc/db.h>
#include <openbsc/msc_api.h>
#include <openbsc/gsm_04_11.h>
static void msc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci)
@@ -42,28 +43,6 @@ static int msc_clear_request(struct gsm_subscriber_connection *conn, uint32_t ca
return 1;
}
static int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg,
uint16_t chosen_channel)
{
gsm0408_new_conn(conn);
gsm0408_dispatch(conn, msg);
/*
* If this is a silent call we want the channel to remain open as long as
* possible and this is why we accept this connection regardless of any
* pending transaction or ongoing operation.
*/
if (conn->silent_call)
return BSC_API_CONN_POL_ACCEPT;
if (conn->loc_operation || conn->sec_operation || conn->anch_operation)
return BSC_API_CONN_POL_ACCEPT;
if (trans_has_conn(conn))
return BSC_API_CONN_POL_ACCEPT;
LOGP(DRR, LOGL_INFO, "MSC Complete L3: Rejecting connection.\n");
return BSC_API_CONN_POL_REJECT;
}
static void msc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg)
{
gsm0408_dispatch(conn, msg);
@@ -143,7 +122,7 @@ struct bsc_api *msc_bsc_api() {
return &msc_handler;
}
/* lchan release handling */
/* conn release handling */
void msc_release_connection(struct gsm_subscriber_connection *conn)
{
/* skip when we are in release, e.g. due an error */
@@ -169,9 +148,8 @@ void msc_release_connection(struct gsm_subscriber_connection *conn)
* to restarting the timer. Set the new expiration time.
*/
if (conn->expire_timer_stopped)
subscr_update_expire_lu(conn->subscr, conn->bts);
subscr_update_expire_lu(conn->network, conn->subscr);
conn->in_release = 1;
gsm0808_clear(conn);
subscr_con_free(conn);
msc_subscr_con_free(conn);
}

View File

@@ -40,7 +40,7 @@ static const uint8_t ass_pref_pos_req[] = { 0x40, 0x03, 0x79, 0x50 };
static int send_rrlp_req(struct gsm_subscriber_connection *conn)
{
struct gsm_network *net = conn->bts->network;
struct gsm_network *net = conn->network;
const uint8_t *req;
switch (net->rrlp.mode) {

View File

@@ -52,8 +52,10 @@ static int paging_cb_silent(unsigned int hooknum, unsigned int event,
switch (event) {
case GSM_PAGING_SUCCEEDED:
#if BEFORE_MSCSPLIT
DEBUGPC(DLSMS, "success, using Timeslot %u on ARFCN %u\n",
conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn);
#endif
conn->silent_call = 1;
/* increment lchan reference count */
osmo_signal_dispatch(SS_SCALL, S_SCALL_SUCCESS, &sigdata);
@@ -121,7 +123,10 @@ int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data, int type)
{
struct subscr_request *req;
req = subscr_request_channel(subscr, type, paging_cb_silent, data);
/* FIXME the VTY command allows selecting a silent call channel type.
* This doesn't apply to the situation after MSCSPLIT with an
* A-interface. */
req = subscr_request_conn(subscr, paging_cb_silent, data);
return req != NULL;
}
@@ -138,8 +143,10 @@ int gsm_silent_call_stop(struct gsm_subscriber *subscr)
if (!conn->silent_call)
return -EINVAL;
#if BEFORE_MSCSPLIT
DEBUGPC(DLSMS, "Stopping silent call using Timeslot %u on ARFCN %u\n",
conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn);
#endif
conn->silent_call = 0;
msc_release_connection(conn);

View File

@@ -420,6 +420,7 @@ void append_tlv_u16(tlv_t **req_tlv, uint16_t tag, uint16_t val)
build_tlv(req_tlv, &tlv);
}
#if BEFORE_MSCSPLIT
/* Append the Osmocom vendor-specific additional TLVs to a SMPP msg */
static void append_osmo_tlvs(tlv_t **req_tlv, const struct gsm_lchan *lchan)
{
@@ -458,6 +459,7 @@ static void append_osmo_tlvs(tlv_t **req_tlv, const struct gsm_lchan *lchan)
(uint8_t *)subscr->equipment.imei, imei_len+1);
}
}
#endif
static int deliver_to_esme(struct osmo_esme *esme, struct gsm_sms *sms,
struct gsm_subscriber_connection *conn)
@@ -533,8 +535,10 @@ static int deliver_to_esme(struct osmo_esme *esme, struct gsm_sms *sms,
memcpy(deliver.short_message, sms->user_data, deliver.sm_length);
}
#if BEFORE_MSCSPLIT
if (esme->acl && esme->acl->osmocom_ext && conn->lchan)
append_osmo_tlvs(&deliver.tlv, conn->lchan);
#endif
return smpp_tx_deliver(esme, &deliver);
}

View File

@@ -225,10 +225,14 @@ static void sms_submit_pending(void *_data)
sms = take_next_sms(smsq);
if (!sms)
if (!sms) {
LOGP(DLSMS, LOGL_DEBUG, "Sending SMS done (%d attempted)\n",
attempted);
break;
}
rounds += 1;
LOGP(DLSMS, LOGL_DEBUG, "Sending SMS round %d\n", rounds);
/*
* This code needs to detect a loop. It assumes that no SMS
@@ -243,6 +247,8 @@ static void sms_submit_pending(void *_data)
first_sub = sms->receiver->id;
initialized = 1;
} else if (first_sub == sms->receiver->id) {
LOGP(DLSMS, LOGL_DEBUG, "Sending SMS done (loop) (%d attempted)\n",
attempted);
sms_free(sms);
break;
}
@@ -324,6 +330,7 @@ no_pending_sms:
*/
int sms_queue_trigger(struct gsm_sms_queue *smsq)
{
LOGP(DLSMS, LOGL_DEBUG, "Triggering SMS queue\n");
if (osmo_timer_pending(&smsq->push_queue))
return 0;

View File

@@ -37,7 +37,7 @@ struct gsm_trans *trans_find_by_id(struct gsm_subscriber_connection *conn,
uint8_t proto, uint8_t trans_id)
{
struct gsm_trans *trans;
struct gsm_network *net = conn->bts->network;
struct gsm_network *net = conn->network;
struct gsm_subscriber *subscr = conn->subscr;
llist_for_each_entry(trans, &net->trans_list, entry) {
@@ -155,7 +155,7 @@ int trans_has_conn(const struct gsm_subscriber_connection *conn)
{
struct gsm_trans *trans;
llist_for_each_entry(trans, &conn->bts->network->trans_list, entry)
llist_for_each_entry(trans, &conn->network->trans_list, entry)
if (trans->conn == conn)
return 1;

View File

@@ -53,8 +53,6 @@
#include "meas_feed.h"
extern struct gsm_network *gsmnet_from_vty(struct vty *v);
static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr)
{
int rc;
@@ -139,7 +137,7 @@ DEFUN(show_subscr_cache,
DEFUN(sms_send_pend,
sms_send_pend_cmd,
"sms send pending",
"SMS related comamnds\n" "SMS Sending related commands\n"
"SMS related commands\n" "SMS Sending related commands\n"
"Send all pending SMS")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
@@ -174,6 +172,7 @@ static int _send_sms_str(struct gsm_subscriber *receiver,
sms_free(sms);
return CMD_WARNING;
}
LOGP(DLSMS, LOGL_DEBUG, "SMS stored in DB\n");
sms_free(sms);
sms_queue_trigger(receiver->group->net->sms_queue);
@@ -197,10 +196,10 @@ static struct gsm_subscriber *get_subscr_by_argv(struct gsm_network *gsmnet,
}
#define SUBSCR_TYPES "(extension|imsi|tmsi|id)"
#define SUBSCR_HELP "Operations on a Subscriber\n" \
"Identify subscriber by his extension (phone number)\n" \
"Identify subscriber by his IMSI\n" \
"Identify subscriber by his TMSI\n" \
"Identify subscriber by his database ID\n" \
"Identify subscriber by extension (phone number)\n" \
"Identify subscriber by IMSI\n" \
"Identify subscriber by TMSI\n" \
"Identify subscriber by database ID\n" \
"Identifier for the subscriber\n"
DEFUN(show_subscr,
@@ -611,6 +610,7 @@ DEFUN(ena_subscr_handover,
SUBSCR_HELP "Handover the active connection\n"
"Number of the BTS to handover to\n")
{
#if BEFORE_MSCSPLIT
int ret;
struct gsm_subscriber_connection *conn;
struct gsm_bts *bts;
@@ -654,6 +654,10 @@ DEFUN(ena_subscr_handover,
subscr_put(subscr);
return CMD_SUCCESS;
#else
vty_out(vty, "%% Not implemented!%s", VTY_NEWLINE);
return -1;
#endif
}
#define A3A8_ALG_TYPES "(none|xor|comp128v1)"
@@ -768,6 +772,7 @@ DEFUN(subscriber_update,
static int scall_cbfn(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
#if BEFORE_MSCSPLIT
struct scall_signal_data *sigdata = signal_data;
struct vty *vty = sigdata->data;
@@ -782,6 +787,10 @@ static int scall_cbfn(unsigned int subsys, unsigned int signal,
break;
}
return 0;
#else
/* not implemented yet! */
return -1;
#endif
}
DEFUN(show_stats,
@@ -791,7 +800,6 @@ DEFUN(show_stats,
{
struct gsm_network *net = gsmnet_from_vty(vty);
openbsc_vty_print_statistics(vty, net);
vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s",
osmo_counter_get(net->stats.loc_upd_type.attach),
osmo_counter_get(net->stats.loc_upd_type.normal),
@@ -1018,66 +1026,6 @@ DEFUN(logging_fltr_imsi,
return CMD_SUCCESS;
}
static struct cmd_node nitb_node = {
NITB_NODE,
"%s(config-nitb)# ",
1,
};
DEFUN(cfg_nitb, cfg_nitb_cmd,
"nitb", "Configure NITB options")
{
vty->node = NITB_NODE;
return CMD_SUCCESS;
}
DEFUN(cfg_nitb_subscr_create, cfg_nitb_subscr_create_cmd,
"subscriber-create-on-demand",
"Make a new record when a subscriber is first seen.\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->create_subscriber = 1;
return CMD_SUCCESS;
}
DEFUN(cfg_nitb_no_subscr_create, cfg_nitb_no_subscr_create_cmd,
"no subscriber-create-on-demand",
NO_STR "Make a new record when a subscriber is first seen.\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->create_subscriber = 0;
return CMD_SUCCESS;
}
DEFUN(cfg_nitb_assign_tmsi, cfg_nitb_assign_tmsi_cmd,
"assign-tmsi",
"Assign TMSI during Location Updating.\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->avoid_tmsi = 0;
return CMD_SUCCESS;
}
DEFUN(cfg_nitb_no_assign_tmsi, cfg_nitb_no_assign_tmsi_cmd,
"no assign-tmsi",
NO_STR "Assign TMSI during Location Updating.\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->avoid_tmsi = 1;
return CMD_SUCCESS;
}
static int config_write_nitb(struct vty *vty)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
vty_out(vty, "nitb%s", VTY_NEWLINE);
vty_out(vty, " %ssubscriber-create-on-demand%s",
gsmnet->create_subscriber ? "" : "no ", VTY_NEWLINE);
vty_out(vty, " %sassign-tmsi%s",
gsmnet->avoid_tmsi ? "no " : "", VTY_NEWLINE);
return CMD_SUCCESS;
}
int bsc_vty_init_extra(void)
{
osmo_signal_register_handler(SS_SCALL, scall_cbfn, NULL);
@@ -1123,13 +1071,5 @@ int bsc_vty_init_extra(void)
install_element(CFG_LOG_NODE, &log_level_sms_cmd);
install_element(CFG_LOG_NODE, &logging_fltr_imsi_cmd);
install_element(CONFIG_NODE, &cfg_nitb_cmd);
install_node(&nitb_node, config_write_nitb);
install_element(NITB_NODE, &cfg_nitb_subscr_create_cmd);
install_element(NITB_NODE, &cfg_nitb_no_subscr_create_cmd);
install_element(NITB_NODE, &cfg_nitb_assign_tmsi_cmd);
install_element(NITB_NODE, &cfg_nitb_no_assign_tmsi_cmd);
return 0;
}

View File

@@ -172,7 +172,7 @@ static int rtp_decode(struct msgb *msg, uint32_t callref, struct msgb **data)
/* always allocate for the maximum possible size to avoid
* fragmentation */
new_msg = msgb_alloc(sizeof(struct gsm_data_frame) +
MAX_RTP_PAYLOAD_LEN, "GSM-DATA (TCH)");
MAX_RTP_PAYLOAD_LEN+1, "GSM-DATA (TCH)");
if (!new_msg)
return -ENOMEM;

View File

@@ -0,0 +1,7 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) \
$(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS)
noinst_LIBRARIES = libxsc.a
libxsc_a_SOURCES = xsc.c xsc_vty.c

260
openbsc/src/libxsc/xsc.c Normal file
View File

@@ -0,0 +1,260 @@
/* Code used by both libbsc and libmsc (xsc means "BSC or MSC").
*
* (C) 2016 by sysmocom s.m.f.c. <info@sysmocom.de>
* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2014 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/>.
*
*/
/* TODO: this file was created during the MSCSPLIT, separating the BSC from the
* NITB to create a standalone MSC. Things from libbsc that are needed from
* libmsc have been moved here, probably taking along some stuff not actually
* needed by the MSC. It may make sense to move things to more appropriate
* places or implement things differently when they become more obvious. I'm
* taking that as an excuse to make a mess of this file in the sense of keeping
* #includes close to their use, and not caring much about mixing things. */
/* FIXME parts of the gsm_network are BSC specific and don't belong here. */
#include <osmocom/gsm/gsm0480.h>
#include <openbsc/gsm_data.h>
#include <openbsc/osmo_msc_data.h>
#include <openbsc/gsm_subscriber.h>
struct gsm_network *gsm_network_init(void *ctx,
uint16_t country_code,
uint16_t network_code,
mncc_recv_cb_t mncc_recv)
{
struct gsm_network *net;
net = talloc_zero(ctx, struct gsm_network);
if (!net)
return NULL;
net->bsc_data = talloc_zero(net, struct osmo_bsc_data);
if (!net->bsc_data) {
talloc_free(net);
return NULL;
}
net->subscr_group = talloc_zero(net, struct gsm_subscriber_group);
if (!net->subscr_group) {
talloc_free(net);
return NULL;
}
/* Init back pointer */
net->bsc_data->auto_off_timeout = -1;
net->bsc_data->network = net;
INIT_LLIST_HEAD(&net->bsc_data->mscs);
net->subscr_group->net = net;
net->create_subscriber = 1;
net->country_code = country_code;
net->network_code = network_code;
net->num_bts = 0;
net->reject_cause = GSM48_REJECT_ROAMING_NOT_ALLOWED;
net->T3101 = GSM_T3101_DEFAULT;
net->T3105 = GSM_T3105_DEFAULT;
net->T3113 = GSM_T3113_DEFAULT;
net->T3122 = GSM_T3122_DEFAULT;
/* FIXME: initialize all other timers! */
/* default set of handover parameters */
net->handover.win_rxlev_avg = 10;
net->handover.win_rxqual_avg = 1;
net->handover.win_rxlev_avg_neigh = 10;
net->handover.pwr_interval = 6;
net->handover.pwr_hysteresis = 3;
net->handover.max_distance = 9999;
/* Use 30 min periodic update interval as sane default */
net->t3212 = 5;
INIT_LLIST_HEAD(&net->trans_list);
INIT_LLIST_HEAD(&net->upqueue);
INIT_LLIST_HEAD(&net->bts_list);
INIT_LLIST_HEAD(&net->subscr_conns);
net->stats.chreq.total = osmo_counter_alloc("net.chreq.total");
net->stats.chreq.no_channel = osmo_counter_alloc("net.chreq.no_channel");
net->stats.handover.attempted = osmo_counter_alloc("net.handover.attempted");
net->stats.handover.no_channel = osmo_counter_alloc("net.handover.no_channel");
net->stats.handover.timeout = osmo_counter_alloc("net.handover.timeout");
net->stats.handover.completed = osmo_counter_alloc("net.handover.completed");
net->stats.handover.failed = osmo_counter_alloc("net.handover.failed");
net->stats.loc_upd_type.attach = osmo_counter_alloc("net.loc_upd_type.attach");
net->stats.loc_upd_type.normal = osmo_counter_alloc("net.loc_upd_type.normal");
net->stats.loc_upd_type.periodic = osmo_counter_alloc("net.loc_upd_type.periodic");
net->stats.loc_upd_type.detach = osmo_counter_alloc("net.imsi_detach.count");
net->stats.loc_upd_resp.reject = osmo_counter_alloc("net.loc_upd_resp.reject");
net->stats.loc_upd_resp.accept = osmo_counter_alloc("net.loc_upd_resp.accept");
net->stats.paging.attempted = osmo_counter_alloc("net.paging.attempted");
net->stats.paging.detached = osmo_counter_alloc("net.paging.detached");
net->stats.paging.completed = osmo_counter_alloc("net.paging.completed");
net->stats.paging.expired = osmo_counter_alloc("net.paging.expired");
net->stats.sms.submitted = osmo_counter_alloc("net.sms.submitted");
net->stats.sms.no_receiver = osmo_counter_alloc("net.sms.no_receiver");
net->stats.sms.delivered = osmo_counter_alloc("net.sms.delivered");
net->stats.sms.rp_err_mem = osmo_counter_alloc("net.sms.rp_err_mem");
net->stats.sms.rp_err_other = osmo_counter_alloc("net.sms.rp_err_other");
net->stats.call.mo_setup = osmo_counter_alloc("net.call.mo_setup");
net->stats.call.mo_connect_ack = osmo_counter_alloc("net.call.mo_connect_ack");
net->stats.call.mt_setup = osmo_counter_alloc("net.call.mt_setup");
net->stats.call.mt_connect = osmo_counter_alloc("net.call.mt_connect");
net->stats.chan.rf_fail = osmo_counter_alloc("net.chan.rf_fail");
net->stats.chan.rll_err = osmo_counter_alloc("net.chan.rll_err");
net->stats.bts.oml_fail = osmo_counter_alloc("net.bts.oml_fail");
net->stats.bts.rsl_fail = osmo_counter_alloc("net.bts.rsl_fail");
net->mncc_recv = mncc_recv;
return net;
}
struct gsm_subscriber_connection *connection_for_subscr(struct gsm_subscriber *subscr)
{
/* FIXME: replace this with a backpointer in gsm_subscriber? */
struct gsm_network *net = subscr->group->net;
struct gsm_subscriber_connection *conn;
llist_for_each_entry(conn, &net->subscr_conns, entry) {
if (conn->subscr == subscr)
return conn;
}
return NULL;
}
/* from gsm_04_08_utils.c *****/
struct msgb *gsm48_create_mm_serv_rej(enum gsm48_reject_value value)
{
struct msgb *msg;
struct gsm48_hdr *gh;
msg = gsm48_msgb_alloc_name("GSM 04.08 SERV REJ");
if (!msg)
return NULL;
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
gh->proto_discr = GSM48_PDISC_MM;
gh->msg_type = GSM48_MT_MM_CM_SERV_REJ;
gh->data[0] = value;
return msg;
}
struct msgb *gsm48_create_loc_upd_rej(uint8_t cause)
{
struct gsm48_hdr *gh;
struct msgb *msg;
msg = gsm48_msgb_alloc_name("GSM 04.08 LOC UPD REJ");
if (!msg)
return NULL;
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
gh->proto_discr = GSM48_PDISC_MM;
gh->msg_type = GSM48_MT_MM_LOC_UPD_REJECT;
gh->data[0] = cause;
return msg;
}
int gsm48_extract_mi(uint8_t *classmark2_lv, int length, char *mi_string, uint8_t *mi_type)
{
/* Check the size for the classmark */
if (length < 1 + *classmark2_lv)
return -1;
uint8_t *mi_lv = classmark2_lv + *classmark2_lv + 1;
if (length < 2 + *classmark2_lv + mi_lv[0])
return -2;
*mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
return gsm48_mi_to_string(mi_string, GSM48_MI_SIZE, mi_lv+1, *mi_lv);
}
int gsm48_paging_extract_mi(struct gsm48_pag_resp *resp, int length,
char *mi_string, uint8_t *mi_type)
{
static const uint32_t classmark_offset =
offsetof(struct gsm48_pag_resp, classmark2);
uint8_t *classmark2_lv = (uint8_t *) &resp->classmark2;
return gsm48_extract_mi(classmark2_lv, length - classmark_offset,
mi_string, mi_type);
}
struct msgb *gsm0480_gen_ussdNotify(int level, const char *text)
{
struct gsm48_hdr *gh;
struct msgb *msg;
msg = gsm0480_create_unstructuredSS_Notify(level, text);
if (!msg)
return NULL;
gsm0480_wrap_invoke(msg, GSM0480_OP_CODE_USS_NOTIFY, 0);
gsm0480_wrap_facility(msg);
/* And finally pre-pend the L3 header */
gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
gh->proto_discr = GSM48_PDISC_NC_SS;
gh->msg_type = GSM0480_MTYPE_REGISTER;
return msg;
}
struct msgb *gsm0480_gen_releaseComplete(void)
{
struct gsm48_hdr *gh;
struct msgb *msg;
msg = gsm48_msgb_alloc_name("GSM 04.08 USSD REL COMPL");
if (!msg)
return NULL;
gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
gh->proto_discr = GSM48_PDISC_NC_SS;
gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
return msg;
}
/* Helpers for SMS/GSM 04.11 */
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_04_11.h>
uint8_t sms_next_rp_msg_ref(uint8_t *next_rp_ref)
{
const uint8_t rp_msg_ref = *next_rp_ref;
/*
* This should wrap as the valid range is 0 to 255. We only
* transfer one SMS at a time so we don't need to check if
* the id has been already assigned.
*/
*next_rp_ref += 1;
return rp_msg_ref;
}

View File

@@ -0,0 +1,587 @@
/* Code used by both libbsc and libmsc (xsc means "BSC or MSC").
*
* (C) 2016 by sysmocom s.m.f.c. <info@sysmocom.de>
* (C) 2008-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/>.
*
*/
/* FIXME parts of the gsm_network VTY commands are BSC specific and don't
* belong here. */
#include <osmocom/core/utils.h>
#include <osmocom/vty/command.h>
#include <osmocom/vty/logging.h>
#include <osmocom/vty/stats.h>
#include <openbsc/vty.h>
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_subscriber.h>
struct cmd_node net_node = {
GSMNET_NODE,
"%s(config-net)# ",
1,
};
struct gsm_network *vty_global_gsm_network = 0;
struct gsm_network *gsmnet_from_vty(struct vty *v)
{
/* In case we read from the config file, the vty->priv cannot
* point to a struct telnet_connection, and thus conn->priv
* will not point to the gsm_network structure.
* It can't hurt to force callers to continue to pass the vty instance
* to this function, in case we'd like to retrieve the global
* gsm_network instance from the vty at some point in the future. But
* until then, just return the global pointer, which should have been
* initialized by bsc_vty_init().
*/
OSMO_ASSERT(vty_global_gsm_network);
return vty_global_gsm_network;
}
static void net_dump_vty(struct vty *vty, struct gsm_network *net)
{
vty_out(vty, "BSC is on Country Code %u, Network Code %u "
"and has %u BTS%s", net->country_code, net->network_code,
net->num_bts, VTY_NEWLINE);
vty_out(vty, " Long network name: '%s'%s",
net->name_long, VTY_NEWLINE);
vty_out(vty, " Short network name: '%s'%s",
net->name_short, VTY_NEWLINE);
vty_out(vty, " Authentication policy: %s%s",
gsm_auth_policy_name(net->auth_policy), VTY_NEWLINE);
vty_out(vty, " Location updating reject cause: %u%s",
net->reject_cause, VTY_NEWLINE);
vty_out(vty, " Encryption: A5/%u%s", net->a5_encryption,
VTY_NEWLINE);
vty_out(vty, " NECI (TCH/H): %u%s", net->neci,
VTY_NEWLINE);
vty_out(vty, " Use TCH for Paging any: %d%s", net->pag_any_tch,
VTY_NEWLINE);
vty_out(vty, " RRLP Mode: %s%s", rrlp_mode_name(net->rrlp.mode),
VTY_NEWLINE);
vty_out(vty, " MM Info: %s%s", net->send_mm_info ? "On" : "Off",
VTY_NEWLINE);
vty_out(vty, " Handover: %s%s", net->handover.active ? "On" : "Off",
VTY_NEWLINE);
#if BEFORE_MSCSPLIT
struct pchan_load pl;
network_chan_load(&pl, net);
vty_out(vty, " Current Channel Load:%s", VTY_NEWLINE);
dump_pchan_load_vty(vty, " ", &pl);
/* show rf */
if (net->bsc_data)
vty_out(vty, " Last RF Command: %s%s",
net->bsc_data->rf_ctrl->last_state_command,
VTY_NEWLINE);
if (net->bsc_data)
vty_out(vty, " Last RF Lock Command: %s%s",
net->bsc_data->rf_ctrl->last_rf_lock_ctrl_command,
VTY_NEWLINE);
#endif
}
DEFUN(show_net, show_net_cmd, "show network",
SHOW_STR "Display information about a GSM NETWORK\n")
{
struct gsm_network *net = gsmnet_from_vty(vty);
net_dump_vty(vty, net);
return CMD_SUCCESS;
}
static int config_write_net(struct vty *vty)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
vty_out(vty, "network%s", VTY_NEWLINE);
vty_out(vty, " network country code %u%s", gsmnet->country_code, VTY_NEWLINE);
vty_out(vty, " mobile network code %u%s", gsmnet->network_code, VTY_NEWLINE);
vty_out(vty, " short name %s%s", gsmnet->name_short, VTY_NEWLINE);
vty_out(vty, " long name %s%s", gsmnet->name_long, VTY_NEWLINE);
vty_out(vty, " auth policy %s%s", gsm_auth_policy_name(gsmnet->auth_policy), VTY_NEWLINE);
vty_out(vty, " location updating reject cause %u%s",
gsmnet->reject_cause, VTY_NEWLINE);
vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE);
vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE);
vty_out(vty, " paging any use tch %d%s", gsmnet->pag_any_tch, VTY_NEWLINE);
vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode),
VTY_NEWLINE);
vty_out(vty, " mm info %u%s", gsmnet->send_mm_info, VTY_NEWLINE);
vty_out(vty, " handover %u%s", gsmnet->handover.active, VTY_NEWLINE);
vty_out(vty, " handover window rxlev averaging %u%s",
gsmnet->handover.win_rxlev_avg, VTY_NEWLINE);
vty_out(vty, " handover window rxqual averaging %u%s",
gsmnet->handover.win_rxqual_avg, VTY_NEWLINE);
vty_out(vty, " handover window rxlev neighbor averaging %u%s",
gsmnet->handover.win_rxlev_avg_neigh, VTY_NEWLINE);
vty_out(vty, " handover power budget interval %u%s",
gsmnet->handover.pwr_interval, VTY_NEWLINE);
vty_out(vty, " handover power budget hysteresis %u%s",
gsmnet->handover.pwr_hysteresis, VTY_NEWLINE);
vty_out(vty, " handover maximum distance %u%s",
gsmnet->handover.max_distance, VTY_NEWLINE);
vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE);
vty_out(vty, " timer t3103 %u%s", gsmnet->T3103, VTY_NEWLINE);
vty_out(vty, " timer t3105 %u%s", gsmnet->T3105, VTY_NEWLINE);
vty_out(vty, " timer t3107 %u%s", gsmnet->T3107, VTY_NEWLINE);
vty_out(vty, " timer t3109 %u%s", gsmnet->T3109, VTY_NEWLINE);
vty_out(vty, " timer t3111 %u%s", gsmnet->T3111, VTY_NEWLINE);
vty_out(vty, " timer t3113 %u%s", gsmnet->T3113, VTY_NEWLINE);
vty_out(vty, " timer t3115 %u%s", gsmnet->T3115, VTY_NEWLINE);
vty_out(vty, " timer t3117 %u%s", gsmnet->T3117, VTY_NEWLINE);
vty_out(vty, " timer t3119 %u%s", gsmnet->T3119, VTY_NEWLINE);
vty_out(vty, " timer t3122 %u%s", gsmnet->T3122, VTY_NEWLINE);
vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE);
vty_out(vty, " dtx-used %u%s", gsmnet->dtx_enabled, VTY_NEWLINE);
vty_out(vty, " subscriber-keep-in-ram %d%s",
gsmnet->subscr_group->keep_subscr, VTY_NEWLINE);
if (gsmnet->tz.override != 0) {
if (gsmnet->tz.dst)
vty_out(vty, " timezone %d %d %d%s",
gsmnet->tz.hr, gsmnet->tz.mn, gsmnet->tz.dst,
VTY_NEWLINE);
else
vty_out(vty, " timezone %d %d%s",
gsmnet->tz.hr, gsmnet->tz.mn, VTY_NEWLINE);
}
if (gsmnet->t3212 == 0)
vty_out(vty, " no periodic location update%s", VTY_NEWLINE);
else
vty_out(vty, " periodic location update %u%s",
gsmnet->t3212 * 6, VTY_NEWLINE);
return CMD_SUCCESS;
}
#define NETWORK_STR "Configure the GSM network\n"
#define CODE_CMD_STR "Code commands\n"
#define NAME_CMD_STR "Name Commands\n"
#define NAME_STR "Name to use\n"
DEFUN(cfg_net,
cfg_net_cmd,
"network", NETWORK_STR)
{
vty->index = gsmnet_from_vty(vty);
vty->node = GSMNET_NODE;
return CMD_SUCCESS;
}
DEFUN(cfg_net_ncc,
cfg_net_ncc_cmd,
"network country code <1-999>",
"Set the GSM network country code\n"
"Country commands\n"
CODE_CMD_STR
"Network Country Code to use\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->country_code = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_mnc,
cfg_net_mnc_cmd,
"mobile network code <0-999>",
"Set the GSM mobile network code\n"
"Network Commands\n"
CODE_CMD_STR
"Mobile Network Code to use\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->network_code = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_name_short,
cfg_net_name_short_cmd,
"short name NAME",
"Set the short GSM network name\n" NAME_CMD_STR NAME_STR)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
bsc_replace_string(gsmnet, &gsmnet->name_short, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_name_long,
cfg_net_name_long_cmd,
"long name NAME",
"Set the long GSM network name\n" NAME_CMD_STR NAME_STR)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
bsc_replace_string(gsmnet, &gsmnet->name_long, argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_auth_policy,
cfg_net_auth_policy_cmd,
"auth policy (closed|accept-all|token)",
"Authentication (not cryptographic)\n"
"Set the GSM network authentication policy\n"
"Require the MS to be activated in HLR\n"
"Accept all MS, whether in HLR or not\n"
"Use SMS-token based authentication\n")
{
enum gsm_auth_policy policy = gsm_auth_policy_parse(argv[0]);
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->auth_policy = policy;
return CMD_SUCCESS;
}
DEFUN(cfg_net_reject_cause,
cfg_net_reject_cause_cmd,
"location updating reject cause <2-111>",
"Set the reject cause of location updating reject\n"
"Set the reject cause of location updating reject\n"
"Set the reject cause of location updating reject\n"
"Set the reject cause of location updating reject\n"
"Cause Value as Per GSM TS 04.08\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->reject_cause = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_encryption,
cfg_net_encryption_cmd,
"encryption a5 (0|1|2|3)",
"Encryption options\n"
"A5 encryption\n" "A5/0: No encryption\n"
"A5/1: Encryption\n" "A5/2: Export-grade Encryption\n"
"A5/3: 'New' Secure Encryption\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->a5_encryption= atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_rrlp_mode, cfg_net_rrlp_mode_cmd,
"rrlp mode (none|ms-based|ms-preferred|ass-preferred)",
"Radio Resource Location Protocol\n"
"Set the Radio Resource Location Protocol Mode\n"
"Don't send RRLP request\n"
"Request MS-based location\n"
"Request any location, prefer MS-based\n"
"Request any location, prefer MS-assisted\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->rrlp.mode = rrlp_mode_parse(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_mm_info, cfg_net_mm_info_cmd,
"mm info (0|1)",
"Mobility Management\n"
"Send MM INFO after LOC UPD ACCEPT\n"
"Disable\n" "Enable\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->send_mm_info = atoi(argv[0]);
return CMD_SUCCESS;
}
#define HANDOVER_STR "Handover Options\n"
DEFUN(cfg_net_handover, cfg_net_handover_cmd,
"handover (0|1)",
HANDOVER_STR
"Don't perform in-call handover\n"
"Perform in-call handover\n")
{
int enable = atoi(argv[0]);
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
#if BEFORE_MSCSPLIT
if (enable && ipacc_rtp_direct) {
vty_out(vty, "%% Cannot enable handover unless RTP Proxy mode "
"is enabled by using the -P command line option%s",
VTY_NEWLINE);
return CMD_WARNING;
}
#endif
gsmnet->handover.active = enable;
return CMD_SUCCESS;
}
#define HO_WIN_STR HANDOVER_STR "Measurement Window\n"
#define HO_WIN_RXLEV_STR HO_WIN_STR "Received Level Averaging\n"
#define HO_WIN_RXQUAL_STR HO_WIN_STR "Received Quality Averaging\n"
#define HO_PBUDGET_STR HANDOVER_STR "Power Budget\n"
#define HO_AVG_COUNT_STR "Amount to use for Averaging\n"
DEFUN(cfg_net_ho_win_rxlev_avg, cfg_net_ho_win_rxlev_avg_cmd,
"handover window rxlev averaging <1-10>",
HO_WIN_RXLEV_STR
"How many RxLev measurements are used for averaging\n"
HO_AVG_COUNT_STR)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.win_rxlev_avg = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_ho_win_rxqual_avg, cfg_net_ho_win_rxqual_avg_cmd,
"handover window rxqual averaging <1-10>",
HO_WIN_RXQUAL_STR
"How many RxQual measurements are used for averaging\n"
HO_AVG_COUNT_STR)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.win_rxqual_avg = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_ho_win_rxlev_neigh_avg, cfg_net_ho_win_rxlev_avg_neigh_cmd,
"handover window rxlev neighbor averaging <1-10>",
HO_WIN_RXLEV_STR "Neighbor\n"
"How many RxQual measurements are used for averaging\n"
HO_AVG_COUNT_STR)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.win_rxlev_avg_neigh = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_ho_pwr_interval, cfg_net_ho_pwr_interval_cmd,
"handover power budget interval <1-99>",
HO_PBUDGET_STR
"How often to check if we have a better cell (SACCH frames)\n"
"Interval\n" "Number\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.pwr_interval = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_ho_pwr_hysteresis, cfg_net_ho_pwr_hysteresis_cmd,
"handover power budget hysteresis <0-999>",
HO_PBUDGET_STR
"How many dB does a neighbor to be stronger to become a HO candidate\n"
"Hysteresis\n" "Number\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.pwr_hysteresis = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd,
"handover maximum distance <0-9999>",
HANDOVER_STR
"How big is the maximum timing advance before HO is forced\n"
"Distance\n" "Number\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->handover.max_distance = atoi(argv[0]);
return CMD_SUCCESS;
}
#define DECLARE_TIMER(number, doc) \
DEFUN(cfg_net_T##number, \
cfg_net_T##number##_cmd, \
"timer t" #number " <0-65535>", \
"Configure GSM Timers\n" \
doc "Timer Value in seconds\n") \
{ \
struct gsm_network *gsmnet = gsmnet_from_vty(vty); \
int value = atoi(argv[0]); \
\
if (value < 0 || value > 65535) { \
vty_out(vty, "Timer value %s out of range.%s", \
argv[0], VTY_NEWLINE); \
return CMD_WARNING; \
} \
\
gsmnet->T##number = value; \
return CMD_SUCCESS; \
}
DECLARE_TIMER(3101, "Set the timeout value for IMMEDIATE ASSIGNMENT.\n")
DECLARE_TIMER(3103, "Set the timeout value for HANDOVER.\n")
DECLARE_TIMER(3105, "Set the timer for repetition of PHYSICAL INFORMATION.\n")
DECLARE_TIMER(3107, "Currently not used.\n")
DECLARE_TIMER(3109, "Set the RSL SACCH deactivation timeout.\n")
DECLARE_TIMER(3111, "Set the RSL timeout to wait before releasing the RF Channel.\n")
DECLARE_TIMER(3113, "Set the time to try paging a subscriber.\n")
DECLARE_TIMER(3115, "Currently not used.\n")
DECLARE_TIMER(3117, "Currently not used.\n")
DECLARE_TIMER(3119, "Currently not used.\n")
DECLARE_TIMER(3122, "Waiting time (seconds) after IMM ASS REJECT\n")
DECLARE_TIMER(3141, "Currently not used.\n")
DEFUN(cfg_net_dtx,
cfg_net_dtx_cmd,
"dtx-used (0|1)",
"Enable the usage of DTX.\n"
"DTX is disabled\n" "DTX is enabled\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->dtx_enabled = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_subscr_keep,
cfg_net_subscr_keep_cmd,
"subscriber-keep-in-ram (0|1)",
"Keep unused subscribers in RAM.\n"
"Delete unused subscribers\n" "Keep unused subscribers\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->subscr_group->keep_subscr = atoi(argv[0]);
return CMD_SUCCESS;
}
DEFUN(cfg_net_timezone,
cfg_net_timezone_cmd,
"timezone <-19-19> (0|15|30|45)",
"Set the Timezone Offset of the network\n"
"Timezone offset (hours)\n"
"Timezone offset (00 minutes)\n"
"Timezone offset (15 minutes)\n"
"Timezone offset (30 minutes)\n"
"Timezone offset (45 minutes)\n"
)
{
struct gsm_network *net = vty->index;
int tzhr = atoi(argv[0]);
int tzmn = atoi(argv[1]);
net->tz.hr = tzhr;
net->tz.mn = tzmn;
net->tz.dst = 0;
net->tz.override = 1;
return CMD_SUCCESS;
}
DEFUN(cfg_net_timezone_dst,
cfg_net_timezone_dst_cmd,
"timezone <-19-19> (0|15|30|45) <0-2>",
"Set the Timezone Offset of the network\n"
"Timezone offset (hours)\n"
"Timezone offset (00 minutes)\n"
"Timezone offset (15 minutes)\n"
"Timezone offset (30 minutes)\n"
"Timezone offset (45 minutes)\n"
"DST offset (hours)\n"
)
{
struct gsm_network *net = vty->index;
int tzhr = atoi(argv[0]);
int tzmn = atoi(argv[1]);
int tzdst = atoi(argv[2]);
net->tz.hr = tzhr;
net->tz.mn = tzmn;
net->tz.dst = tzdst;
net->tz.override = 1;
return CMD_SUCCESS;
}
DEFUN(cfg_net_no_timezone,
cfg_net_no_timezone_cmd,
"no timezone",
NO_STR
"Disable network timezone override, use system tz\n")
{
struct gsm_network *net = vty->index;
net->tz.override = 0;
return CMD_SUCCESS;
}
int gsmnet_vty_init(struct gsm_network *network)
{
vty_global_gsm_network = network;
install_element_ve(&show_net_cmd);
install_element(CONFIG_NODE, &cfg_net_cmd);
install_node(&net_node, config_write_net);
vty_install_default(GSMNET_NODE);
install_element(GSMNET_NODE, &cfg_net_ncc_cmd);
install_element(GSMNET_NODE, &cfg_net_mnc_cmd);
install_element(GSMNET_NODE, &cfg_net_name_short_cmd);
install_element(GSMNET_NODE, &cfg_net_name_long_cmd);
install_element(GSMNET_NODE, &cfg_net_auth_policy_cmd);
install_element(GSMNET_NODE, &cfg_net_reject_cause_cmd);
install_element(GSMNET_NODE, &cfg_net_encryption_cmd);
install_element(GSMNET_NODE, &cfg_net_rrlp_mode_cmd);
install_element(GSMNET_NODE, &cfg_net_mm_info_cmd);
install_element(GSMNET_NODE, &cfg_net_handover_cmd);
install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_cmd);
install_element(GSMNET_NODE, &cfg_net_ho_win_rxqual_avg_cmd);
install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_neigh_cmd);
install_element(GSMNET_NODE, &cfg_net_ho_pwr_interval_cmd);
install_element(GSMNET_NODE, &cfg_net_ho_pwr_hysteresis_cmd);
install_element(GSMNET_NODE, &cfg_net_ho_max_distance_cmd);
install_element(GSMNET_NODE, &cfg_net_T3101_cmd);
install_element(GSMNET_NODE, &cfg_net_T3103_cmd);
install_element(GSMNET_NODE, &cfg_net_T3105_cmd);
install_element(GSMNET_NODE, &cfg_net_T3107_cmd);
install_element(GSMNET_NODE, &cfg_net_T3109_cmd);
install_element(GSMNET_NODE, &cfg_net_T3111_cmd);
install_element(GSMNET_NODE, &cfg_net_T3113_cmd);
install_element(GSMNET_NODE, &cfg_net_T3115_cmd);
install_element(GSMNET_NODE, &cfg_net_T3117_cmd);
install_element(GSMNET_NODE, &cfg_net_T3119_cmd);
install_element(GSMNET_NODE, &cfg_net_T3122_cmd);
install_element(GSMNET_NODE, &cfg_net_T3141_cmd);
install_element(GSMNET_NODE, &cfg_net_dtx_cmd);
install_element(GSMNET_NODE, &cfg_net_subscr_keep_cmd);
install_element(GSMNET_NODE, &cfg_net_timezone_cmd);
install_element(GSMNET_NODE, &cfg_net_timezone_dst_cmd);
install_element(GSMNET_NODE, &cfg_net_no_timezone_cmd);
return CMD_SUCCESS;
}
/* VTY elements used in both BSC and MSC */
int xsc_vty_init(struct gsm_network *network)
{
osmo_stats_vty_add_cmds();
gsmnet_vty_init(network);
return CMD_SUCCESS;
}

View File

@@ -12,11 +12,9 @@ osmo_bsc_SOURCES = osmo_bsc_main.c osmo_bsc_vty.c osmo_bsc_api.c \
osmo_bsc_LDADD = \
$(top_builddir)/src/libfilter/libfilter.a \
$(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libmsc/libmsc.a \
$(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libxsc/libxsc.a \
$(top_builddir)/src/libtrau/libtrau.a \
$(top_builddir)/src/libcommon/libcommon.a \
$(top_builddir)/src/libcommon/libcommon.a \
$(LIBOSMOSCCP_LIBS) $(LIBOSMOCORE_LIBS) \
$(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOCTRL_LIBS) \
$(COVERAGE_LDFLAGS) $(LIBOSMOABIS_LIBS)

View File

@@ -330,7 +330,7 @@ static int move_to_msc(struct gsm_subscriber_connection *_conn,
_conn->sccp_con = NULL;
if (complete_layer3(_conn, msg, msc) != BSC_API_CONN_POL_ACCEPT) {
gsm0808_clear(_conn);
subscr_con_free(_conn);
bsc_subscr_con_free(_conn);
return 1;
}

View File

@@ -185,7 +185,7 @@ static int bssmap_handle_clear_command(struct osmo_bsc_sccp_con *conn,
if (conn->conn) {
LOGP(DMSC, LOGL_INFO, "Releasing all transactions on %p\n", conn);
gsm0808_clear(conn->conn);
subscr_con_free(conn->conn);
bsc_subscr_con_free(conn->conn);
conn->conn = NULL;
}

View File

@@ -371,9 +371,10 @@ static int get_bts_timezone(struct ctrl_cmd *cmd, void *data)
return CTRL_CMD_ERROR;
}
if (bts->tz.override)
struct gsm_tz *tz = &bts->network->tz;
if (tz->override)
cmd->reply = talloc_asprintf(cmd, "%d,%d,%d",
bts->tz.hr, bts->tz.mn, bts->tz.dst);
tz->hr, tz->mn, tz->dst);
else
cmd->reply = talloc_asprintf(cmd, "off");
@@ -385,8 +386,19 @@ static int get_bts_timezone(struct ctrl_cmd *cmd, void *data)
return CTRL_CMD_REPLY;
}
/* Note: it may appear that set_bts_timezone() is never used, but is in in fact
* used by CTRL_CMD_DEFINE(bts_timezone, "timezone"); above. */
static int set_bts_timezone(struct ctrl_cmd *cmd, void *data)
{
/* FIXME: in the course of MSCSPLIT, the osmo CN no longer has access
* to the BTS structs, and hence the timezone override was moved to the
* network level. It does of course still make sense to allow adjusting
* the timezone per BTS in osmo-bsc. This function currently modifies
* the global timezone data on network level, thus having an effect on
* all other BTSs at the same time. I'm doing it this way because I'm
* focusing on IuCS and the MSCSPLIT and hope to do this properly
* at a later time. Sorry about that... ~Neels */
char *saveptr, *hourstr, *minstr, *dststr, *tmp = 0;
int override;
struct gsm_bts *bts = (struct gsm_bts *) cmd->node;
@@ -409,12 +421,13 @@ static int set_bts_timezone(struct ctrl_cmd *cmd, void *data)
if (hourstr != NULL)
override = strcasecmp(hourstr, "off") != 0;
bts->tz.override = override;
struct gsm_tz *tz = &bts->network->tz;
tz->override = override;
if (override) {
bts->tz.hr = hourstr ? atol(hourstr) : 0;
bts->tz.mn = minstr ? atol(minstr) : 0;
bts->tz.dst = dststr ? atol(dststr) : 0;
tz->hr = hourstr ? atol(hourstr) : 0;
tz->mn = minstr ? atol(minstr) : 0;
tz->dst = dststr ? atol(dststr) : 0;
}
talloc_free(tmp);
@@ -583,7 +596,7 @@ static int set_net_ussd_notify(struct ctrl_cmd *cmd, void *data)
alert = atoi(alert_str);
net = cmd->node;
llist_for_each_entry(conn, bsc_api_sub_connections(net), entry) {
llist_for_each_entry(conn, &net->subscr_conns, entry) {
if (!conn->sccp_con)
continue;

View File

@@ -270,23 +270,24 @@ static int bsc_patch_mm_info(struct gsm_subscriber_connection *conn,
return 0;
/* Is TZ patching enabled? */
if (!bts->tz.override)
struct gsm_tz *tz = &bts->network->tz;
if (!tz->override)
return 0;
/* Convert tz.hr and tz.mn to units */
if (bts->tz.hr < 0) {
tzunits = -bts->tz.hr*4;
if (tz->hr < 0) {
tzunits = -tz->hr*4;
tzbsd |= 0x08;
} else
tzunits = bts->tz.hr*4;
tzunits = tz->hr*4;
tzunits = tzunits + (bts->tz.mn/15);
tzunits = tzunits + (tz->mn/15);
tzbsd |= (tzunits % 10)*0x10 + (tzunits / 10);
/* Convert DST value */
if (bts->tz.dst >= 0 && bts->tz.dst <= 2)
dst = bts->tz.dst;
if (tz->dst >= 0 && tz->dst <= 2)
dst = tz->dst;
if (TLVP_PRESENT(&tp, GSM48_IE_UTC)) {
LOGP(DMSC, LOGL_DEBUG,

View File

@@ -204,7 +204,7 @@ int main(int argc, char **argv)
/* This needs to precede handle_options() */
vty_info.copyright = openbsc_copyright;
vty_init(&vty_info);
bsc_vty_init(&log_info);
bsc_vty_init(&log_info, bsc_gsmnet);
bsc_msg_lst_vty_init(tall_bsc_ctx, &access_lists, BSC_NODE);
ctrl_vty_init(tall_bsc_ctx);
@@ -219,8 +219,12 @@ int main(int argc, char **argv)
/* initialize SCCP */
sccp_set_log_area(DSCCP);
rc = bsc_bootstrap_network(NULL, config_file);
rc = bsc_network_init(NULL);
if (rc) {
fprintf(stderr, "Allocation failed. exiting.\n");
exit(1);
}
rc = bsc_network_configure(config_file);
if (rc < 0) {
fprintf(stderr, "Bootstrapping the network failed. exiting.\n");
exit(1);

View File

@@ -84,7 +84,7 @@ static void msc_outgoing_sccp_state(struct sccp_connection *conn, int old_state)
LOGP(DMSC, LOGL_ERROR,
"ERROR: The lchan is still associated.\n");
gsm0808_clear(con_data->conn);
subscr_con_free(con_data->conn);
bsc_subscr_con_free(con_data->conn);
con_data->conn = NULL;
}
@@ -107,7 +107,7 @@ static void bsc_sccp_force_free(struct osmo_bsc_sccp_con *data)
{
if (data->conn) {
gsm0808_clear(data->conn);
subscr_con_free(data->conn);
bsc_subscr_con_free(data->conn);
data->conn = NULL;
}

View File

@@ -11,6 +11,7 @@ osmo_bsc_nat_SOURCES = bsc_filter.c bsc_mgcp_utils.c bsc_nat.c bsc_nat_utils.c \
osmo_bsc_nat_LDADD = \
$(top_builddir)/src/libmgcp/libmgcp.a \
$(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libxsc/libxsc.a \
$(top_builddir)/src/libtrau/libtrau.a \
$(top_builddir)/src/libcommon/libcommon.a \
$(top_builddir)/src/libfilter/libfilter.a \

View File

@@ -1329,7 +1329,7 @@ int bsc_nat_vty_init(struct bsc_nat *nat)
/* called by the telnet interface... we have our own init above */
int bsc_vty_init(const struct log_info *cat)
int bsc_vty_init(const struct log_info *cat, struct gsm_network *network)
{
logging_vty_add_cmds(cat);
return 0;

View File

@@ -1,19 +1,25 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) \
-DCOMPILING_LIBMSC=1
AM_CFLAGS=-Wall $(COVERAGE_CFLAGS) \
$(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) \
$(LIBOSMOCTRL_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBSMPP34_CFLAGS)
$(LIBOSMOCTRL_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(LIBSMPP34_CFLAGS) \
$(LIBOSMORANAP_CFLAGS) $(LIBASN1C_CFLAGS) $(LIBOSMOSIGTRAN_CFLAGS)
AM_LDFLAGS = $(COVERAGE_LDFLAGS)
bin_PROGRAMS = osmo-nitb
bin_PROGRAMS = osmo-cscn
osmo_nitb_SOURCES = bsc_hack.c
osmo_nitb_LDADD = \
$(top_builddir)/src/libbsc/libbsc.a \
noinst_HEADERS = iucs_ranap.h
osmo_cscn_SOURCES = cscn_main.c iucs_ranap.c
osmo_cscn_LDADD = \
$(top_builddir)/src/libiu/libiu.a \
$(top_builddir)/src/libmsc/libmsc.a \
$(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libtrau/libtrau.a \
$(top_builddir)/src/libcommon/libcommon.a \
$(top_builddir)/src/libxsc/libxsc.a \
-ldbi $(LIBCRYPT) \
$(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOCORE_LIBS) \
$(LIBOSMOCTRL_LIBS) $(LIBOSMOABIS_LIBS) $(LIBSMPP34_LIBS) $(LIBCRYPTO_LIBS)
$(LIBOSMOCTRL_LIBS) $(LIBOSMOABIS_LIBS) $(LIBSMPP34_LIBS) $(LIBCRYPTO_LIBS) \
$(LIBOSMORANAP_LIBS) $(LIBASN1C_LIBS) $(LIBOSMOSIGTRAN_LIBS)

View File

@@ -1,6 +1,11 @@
/* A hackish minimal BSC (+MSC +HLR) implementation */
/* OsmoCSCN - Circuit-Switched Core Network (MSC+VLR+HLR+SMSC) implementation
*/
/* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* Based on OsmoNITB:
* (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>
* (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
* All Rights Reserved
*
@@ -29,6 +34,9 @@
#define _GNU_SOURCE
#include <getopt.h>
/* build switches from the configure script */
#include "../../bscconfig.h"
#include <openbsc/db.h>
#include <osmocom/core/application.h>
#include <osmocom/core/select.h>
@@ -41,6 +49,9 @@
#include <openbsc/osmo_msc.h>
#include <openbsc/osmo_msc_data.h>
#include <openbsc/sms_queue.h>
#include <osmocom/vty/telnet_interface.h>
#include <osmocom/vty/ports.h>
#include <osmocom/vty/logging.h>
#include <openbsc/vty.h>
#include <openbsc/bss.h>
#include <openbsc/mncc.h>
@@ -48,23 +59,55 @@
#include <openbsc/handover_decision.h>
#include <openbsc/rrlp.h>
#include <osmocom/ctrl/control_if.h>
#include <osmocom/ctrl/ports.h>
#include <osmocom/ctrl/control_vty.h>
#include <osmocom/ctrl/ports.h>
#include <openbsc/ctrl.h>
#include <openbsc/osmo_bsc_rf.h>
#include <openbsc/smpp.h>
#include <osmocom/sigtran/sccp_sap.h>
#include <osmocom/sigtran/sua.h>
#include "../../bscconfig.h"
#include <openbsc/msc_ifaces.h>
#include <openbsc/iu.h>
#include <openbsc/iu_cs.h>
/* MCC and MNC for the Location Area Identifier */
struct gsm_network *bsc_gsmnet = 0;
static const char *database_name = "hlr.sqlite3";
static const char *config_file = "openbsc.cfg";
static const char *rf_ctrl_path = NULL;
extern const char *openbsc_copyright;
static int daemonize = 0;
static const char *mncc_sock_path = NULL;
static int use_db_counter = 1;
#include "iucs_ranap.h"
static const char * const osmocscn_copyright =
"OsmoCSCN - Osmocom Circuit-Switched Core Network implementation\r\n"
"Copyright (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>\r\n"
"Based on OsmoNITB:\r\n"
" (C) 2008-2010 by Harald Welte <laforge@gnumonks.org>\r\n"
" (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>\r\n"
"Contributions by Daniel Willmann, Jan Lübbe, Stefan Schmidt\r\n"
"Dieter Spaar, Andreas Eversberg, Sylvain Munaut, Neels Hofmeyr\r\n\r\n"
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
"This is free software: you are free to change and redistribute it.\r\n"
"There is NO WARRANTY, to the extent permitted by law.\r\n";
void *tall_cscn_ctx = NULL;
/* satisfy deps from libbsc legacy.
TODO double check these */
void *tall_fle_ctx = NULL;
void *tall_paging_ctx = NULL;
void *tall_map_ctx = NULL;
void *tall_upq_ctx = NULL;
/* end deps from libbsc legacy. */
static struct {
const char *database_name;
const char *config_file;
int daemonize;
const char *mncc_sock_path;
int use_db_counter;
} cscn_cmdline_config = {
"hlr.sqlite3",
"osmo-cscn.cfg",
0,
0,
1
};
/* timer to store statistics */
#define DB_SYNC_INTERVAL 60, 0
@@ -104,10 +147,8 @@ static void print_help()
printf(" -V --version Print the version of OpenBSC.\n");
printf(" -P --rtp-proxy Enable the RTP Proxy code inside OpenBSC.\n");
printf(" -e --log-level number Set a global loglevel.\n");
printf(" -M --mncc-sock-path PATH Disable built-in MNCC handler and offer socket.\n");
printf(" -m --mncc-sock Same as `-M /tmp/bsc_mncc' (deprecated).\n");
printf(" -m --mncc-sock Disable built-in MNCC handler and offer socket.\n");
printf(" -C --no-dbcounter Disable regular syncing of counters to database.\n");
printf(" -r --rf-ctl PATH A unix domain socket to listen for cmds.\n");
}
static void handle_options(int argc, char **argv)
@@ -130,7 +171,6 @@ static void handle_options(int argc, char **argv)
{"mncc-sock", 0, 0, 'm'},
{"mncc-sock-path", 1, 0, 'M'},
{"no-dbcounter", 0, 0, 'C'},
{"rf-ctl", 1, 0, 'r'},
{0, 0, 0, 0}
};
@@ -151,13 +191,13 @@ static void handle_options(int argc, char **argv)
log_parse_category_mask(osmo_stderr_target, optarg);
break;
case 'D':
daemonize = 1;
cscn_cmdline_config.daemonize = 1;
break;
case 'l':
database_name = optarg;
cscn_cmdline_config.database_name = optarg;
break;
case 'c':
config_file = optarg;
cscn_cmdline_config.config_file = optarg;
break;
case 'p':
create_pcap_file(optarg);
@@ -165,37 +205,58 @@ static void handle_options(int argc, char **argv)
case 'T':
log_set_print_timestamp(osmo_stderr_target, 1);
break;
#if BEFORE_MSCSPLIT
case 'P':
ipacc_rtp_direct = 0;
break;
#endif
case 'e':
log_set_log_level(osmo_stderr_target, atoi(optarg));
break;
case 'M':
mncc_sock_path = optarg;
cscn_cmdline_config.mncc_sock_path = optarg;
break;
case 'm':
mncc_sock_path = "/tmp/bsc_mncc";
cscn_cmdline_config.mncc_sock_path = "/tmp/bsc_mncc";
break;
case 'C':
use_db_counter = 0;
cscn_cmdline_config.use_db_counter = 0;
break;
case 'V':
print_version(1);
exit(0);
break;
case 'r':
rf_ctrl_path = optarg;
break;
default:
/* catch unknown options *as well as* missing arguments. */
fprintf(stderr, "Error in command line options. Exiting.\n");
exit(-1);
/* ignore */
break;
}
}
}
struct gsm_network *cscn_network_init(void *ctx,
mncc_recv_cb_t mncc_recv)
{
struct gsm_network *net = gsm_network_init(ctx, 1, 1, mncc_recv);
if (!net)
return NULL;
net->name_long = talloc_strdup(net, "OsmoCSCN");
net->name_short = talloc_strdup(net, "OsmoCSCN");
return net;
}
void cscn_network_shutdown(struct gsm_network *net)
{
/* nothing here yet */
}
static struct gsm_network *cscn_network = NULL;
/* TODO this is here to satisfy linking during intermediate development. Once
* libbsc is not linked to osmo-cscn, this should go away. */
struct gsm_network *bsc_gsmnet = NULL;
extern void *tall_vty_ctx;
static void signal_handler(int signal)
{
@@ -203,7 +264,7 @@ static void signal_handler(int signal)
switch (signal) {
case SIGINT:
bsc_shutdown_net(bsc_gsmnet);
cscn_network_shutdown(cscn_network);
osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
sleep(3);
exit(0);
@@ -213,7 +274,7 @@ static void signal_handler(int signal)
* and then return to the caller, who will abort the process */
case SIGUSR1:
talloc_report(tall_vty_ctx, stderr);
talloc_report_full(tall_bsc_ctx, stderr);
talloc_report_full(tall_cscn_ctx, stderr);
break;
case SIGUSR2:
talloc_report_full(tall_vty_ctx, stderr);
@@ -238,119 +299,186 @@ static void db_sync_timer_cb(void *data)
static void subscr_expire_cb(void *data)
{
subscr_expire(bsc_gsmnet->subscr_group);
osmo_timer_schedule(&bsc_gsmnet->subscr_expire_timer, EXPIRE_INTERVAL);
subscr_expire(cscn_network->subscr_group);
osmo_timer_schedule(&cscn_network->subscr_expire_timer, EXPIRE_INTERVAL);
}
void talloc_ctx_init(void);
void talloc_ctx_init(void *ctx_root);
extern int bsc_vty_go_parent(struct vty *vty);
static struct vty_app_info vty_info = {
.name = "OpenBSC",
static struct vty_app_info cscn_vty_info = {
.name = "OsmoCSCN",
.version = PACKAGE_VERSION,
.go_parent_cb = bsc_vty_go_parent,
.is_config_node = bsc_vty_is_config_node,
};
static int rcvmsg_iu_cs(struct msgb *msg, struct gprs_ra_id *ra_id, /* FIXME gprs_ in CS code */
uint16_t *sai)
{
DEBUGP(DIUCS, "got IuCS message"
" %d bytes: %s\n",
msg->len, osmo_hexdump(msg->data, msg->len));
if (ra_id) {
DEBUGP(DIUCS, "got IuCS message on"
" MNC %d MCC %d LAC %d RAC %d\n",
ra_id->mnc, ra_id->mcc, ra_id->lac, ra_id->rac);
}
return gsm0408_rcvmsg_iucs(cscn_network, msg, ra_id? &ra_id->lac : NULL);
}
static int rx_iu_event(struct ue_conn_ctx *ctx, enum iu_event_type type,
void *data)
{
DEBUGP(DIUCS, "got IuCS event %u: %s\n", type,
iu_event_type_str(type));
return iucs_rx_ranap_event(cscn_network, ctx, type, data);
}
int main(int argc, char **argv)
{
int rc;
vty_info.copyright = openbsc_copyright;
cscn_vty_info.copyright = osmocscn_copyright;
tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
talloc_ctx_init();
on_dso_load_token();
on_dso_load_rrlp();
on_dso_load_ho_dec();
tall_cscn_ctx = talloc_named_const(NULL, 1, "osmo_cscn");
talloc_ctx_init(tall_cscn_ctx);
libosmo_abis_init(tall_bsc_ctx);
osmo_init_logging(&log_info);
osmo_stats_init(tall_bsc_ctx);
bts_init();
osmo_stats_init(tall_cscn_ctx);
/* This needs to precede handle_options() */
vty_init(&vty_info);
bsc_vty_init(&log_info);
ctrl_vty_init(tall_bsc_ctx);
handle_options(argc, argv);
cscn_network = cscn_network_init(tall_cscn_ctx,
cscn_cmdline_config.mncc_sock_path?
mncc_sock_from_cc
: int_mncc_recv);
if (!cscn_network)
return -ENOMEM;
vty_init(&cscn_vty_info);
ctrl_vty_init(tall_cscn_ctx);
logging_vty_add_cmds(&log_info);
xsc_vty_init(cscn_network);
cscn_vty_init();
bsc_vty_init_extra();
#ifdef BUILD_SMPP
if (smpp_openbsc_alloc_init(tall_bsc_ctx) < 0)
if (smpp_openbsc_alloc_init(tall_cscn_ctx) < 0)
return -1;
#endif
/* parse options */
handle_options(argc, argv);
rc = vty_read_config_file(cscn_cmdline_config.config_file, NULL);
if (rc < 0) {
LOGP(DNM, LOGL_FATAL, "Failed to parse the config file: '%s'\n",
cscn_cmdline_config.config_file);
return 1;
}
/* internal MNCC handler or MNCC socket? */
if (mncc_sock_path) {
rc = bsc_bootstrap_network(mncc_sock_from_cc, config_file);
if (rc >= 0)
mncc_sock_init(bsc_gsmnet, mncc_sock_path);
if (cscn_cmdline_config.mncc_sock_path) {
rc = mncc_sock_init(cscn_network,
cscn_cmdline_config.mncc_sock_path);
if (rc < 0)
exit(1);
} else {
DEBUGP(DMNCC, "Using internal MNCC handler.\n");
rc = bsc_bootstrap_network(int_mncc_recv, config_file);
}
/* start telnet after reading config for vty_get_bind_addr() */
LOGP(DGPRS, LOGL_NOTICE, "VTY at %s %d\n",
vty_get_bind_addr(), OSMO_VTY_PORT_CSCN);
rc = telnet_init_dynif(tall_cscn_ctx, &cscn_network,
vty_get_bind_addr(), OSMO_VTY_PORT_CSCN);
if (rc < 0)
exit(1);
#ifdef BUILD_SMPP
smpp_openbsc_start(bsc_gsmnet);
return 2;
/* BSC stuff is to be split behind an A-interface to be used with
* OsmoBSC, but there is no need to remove it yet. Most of the
* following code until iu_init() is legacy. */
#if 0
on_dso_load_token();
on_dso_load_rrlp();
on_dso_load_ho_dec();
libosmo_abis_init(tall_cscn_ctx);
bts_init();
#endif
bsc_api_init(bsc_gsmnet, msc_bsc_api());
#ifdef BUILD_SMPP
smpp_openbsc_start(cscn_network);
#endif
#if 0
bsc_api_init(cscn_network, msc_bsc_api()); // pobably not.
#endif
#if 0
the bsc_ctrl_node_lookup() only returns BSC specific ctrl nodes
/* start control interface after reading config for
* ctrl_vty_get_bind_addr() */
LOGP(DNM, LOGL_NOTICE, "CTRL at %s %d\n",
ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_NITB_BSC);
bsc_gsmnet->ctrl = bsc_controlif_setup(bsc_gsmnet,
ctrl_vty_get_bind_addr(),
OSMO_CTRL_PORT_NITB_BSC);
if (!bsc_gsmnet->ctrl) {
ctrl_vty_get_bind_addr(), OSMO_CTRL_PORT_CSCN);
cscn_network->ctrl = bsc_controlif_setup(cscn_network,
ctrl_vty_get_bind_addr(),
OSMO_CTRL_PORT_CSCN);
if (!cscn_network->ctrl) {
printf("Failed to initialize control interface. Exiting.\n");
return -1;
}
#endif
#if 0
TODO: we probably want some of the _net_ ctrl commands from bsc_base_ctrl_cmds_install().
if (bsc_base_ctrl_cmds_install() != 0) {
printf("Failed to initialize the BSC control commands.\n");
return -1;
}
#endif
#if 0
if (msc_ctrl_cmds_install() != 0) {
printf("Failed to initialize the MSC control commands.\n");
return -1;
}
#endif
/* seed the PRNG */
srand(time(NULL));
/* TODO: is this used for crypto?? Improve randomness, at least we
* should try to use the nanoseconds part of the current time. */
bsc_gsmnet->bsc_data->rf_ctrl = osmo_bsc_rf_create(rf_ctrl_path, bsc_gsmnet);
if (!bsc_gsmnet->bsc_data->rf_ctrl) {
#if 0
cscn_network->bsc_data->rf_ctrl = osmo_bsc_rf_create(rf_ctrl_name, cscn_network);
if (!cscn_network->bsc_data->rf_ctrl) {
fprintf(stderr, "Failed to create the RF service.\n");
exit(1);
return 3;
}
#endif
if (db_init(database_name)) {
printf("DB: Failed to init database. Please check the option settings.\n");
return -1;
if (db_init(cscn_cmdline_config.database_name)) {
printf("DB: Failed to init database: %s\n",
cscn_cmdline_config.database_name);
return 4;
}
printf("DB: Database initialized.\n");
if (db_prepare()) {
printf("DB: Failed to prepare database.\n");
return -1;
return 5;
}
printf("DB: Database prepared.\n");
/* setup the timer */
db_sync_timer.cb = db_sync_timer_cb;
db_sync_timer.data = NULL;
if (use_db_counter)
if (cscn_cmdline_config.use_db_counter)
osmo_timer_schedule(&db_sync_timer, DB_SYNC_INTERVAL);
bsc_gsmnet->subscr_expire_timer.cb = subscr_expire_cb;
bsc_gsmnet->subscr_expire_timer.data = NULL;
osmo_timer_schedule(&bsc_gsmnet->subscr_expire_timer, EXPIRE_INTERVAL);
cscn_network->subscr_expire_timer.cb = subscr_expire_cb;
cscn_network->subscr_expire_timer.data = NULL;
osmo_timer_schedule(&cscn_network->subscr_expire_timer, EXPIRE_INTERVAL);
signal(SIGINT, &signal_handler);
signal(SIGABRT, &signal_handler);
@@ -359,14 +487,20 @@ int main(int argc, char **argv)
osmo_init_ignore_signals();
/* start the SMS queue */
if (sms_queue_start(bsc_gsmnet, 20) != 0)
if (sms_queue_start(cscn_network, 20) != 0)
return -1;
if (daemonize) {
/* Set up A-Interface */
/* TODO: implement A-Interface and remove above legacy stuff. */
/* Set up IuCS */
iu_init(tall_cscn_ctx, "127.0.0.1", 14001, rcvmsg_iu_cs, rx_iu_event);
if (cscn_cmdline_config.daemonize) {
rc = osmo_daemonize();
if (rc < 0) {
perror("Error during daemonize");
exit(1);
return 6;
}
}

View File

@@ -0,0 +1,120 @@
/* Implementation of RANAP messages to/from an MSC via an Iu-CS interface.
* This keeps direct RANAP dependencies out of libmsc. */
/* (C) 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de>
*
* 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/core/logging.h>
#include <osmocom/ranap/ranap_ies_defs.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/iu.h>
#include <openbsc/iu_cs.h>
#include "iucs_ranap.h"
/* To continue authorization after a Security Mode Complete */
int gsm0408_authorize(struct gsm_subscriber_connection *conn);
static int iucs_rx_rab_assign(struct gsm_subscriber_connection *conn,
RANAP_RAB_SetupOrModifiedItemIEs_t *setup_ies)
{
uint8_t rab_id;
RANAP_RAB_SetupOrModifiedItem_t *item = &setup_ies->raB_SetupOrModifiedItem;
rab_id = item->rAB_ID.buf[0];
LOGP(DIUCS, LOGL_NOTICE, "Received RAB assignment event for %s"
" rab_id=%hhd\n", subscr_name(conn->subscr), rab_id);
/* TODO do stuff like in sgsn_ranap_rab_ass_resp() */
return 0;
}
int iucs_rx_sec_mode_compl(struct gsm_subscriber_connection *conn,
RANAP_SecurityModeCompleteIEs_t *ies)
{
gsm_cbfn *cb;
OSMO_ASSERT(conn->via_iface == IFACE_IU);
if (!conn->sec_operation) {
LOGP(DIUCS, LOGL_ERROR,
"Received Security Mode Complete message, but no"
" authentication/cipher operation in progress"
" for subscr %s\n", subscr_name(conn->subscr));
return;
}
/* TODO evalute ies */
if (conn->iu.integrity_protection)
LOGP(DIUCS, LOGL_NOTICE, "Integrity Protection"
" was already enabled for %s\n",
subscr_name(conn->subscr));
conn->iu.integrity_protection = INTEGRITY_PROTECTION_IK;
cb = conn->sec_operation->cb;
if (cb)
cb(GSM_HOOK_RR_SECURITY, GSM_SECURITY_SUCCEEDED, NULL,
conn, conn->sec_operation->cb_data);
release_security_operation(conn);
return 0;
}
int iucs_rx_ranap_event(struct gsm_network *network,
struct ue_conn_ctx *ue_ctx, int type, void *data)
{
struct gsm_subscriber_connection *conn;
conn = subscr_conn_lookup_iu(network, ue_ctx);
if (!conn) {
LOGP(DRANAP, LOGL_ERROR, "Cannot find subscriber for IU event %u\n", type);
return -1;
}
switch (type) {
case IU_EVENT_IU_RELEASE:
case IU_EVENT_LINK_INVALIDATED:
LOGP(DIUCS, LOGL_INFO, "IuCS release for %s\n",
subscr_name(conn->subscr));
gsm0408_clear_request(conn, 0);
return 0;
case IU_EVENT_SECURITY_MODE_COMPLETE:
LOGP(DIUCS, LOGL_INFO, "IuCS security mode complete for %s\n",
subscr_name(conn->subscr));
return iucs_rx_sec_mode_compl(conn,
(RANAP_SecurityModeCompleteIEs_t*)data);
case IU_EVENT_RAB_ASSIGN:
return iucs_rx_rab_assign(conn,
(RANAP_RAB_SetupOrModifiedItemIEs_t*)data);
default:
LOGP(DIUCS, LOGL_NOTICE, "Unknown message received:"
" RANAP event: %i\n", type);
return -1;
}
}

View File

@@ -0,0 +1,7 @@
#pragma once
struct ue_conn_ctx;
int iucs_rx_ranap_event(struct gsm_network *network,
struct ue_conn_ctx *ue_ctx, int type, void *data);

View File

@@ -1,5 +1,5 @@
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(SQLITE3_CFLAGS) \
AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(SQLITE3_CFLAGS) \
$(LIBSMPP34_CFLAGS)
AM_LDFLAGS = $(COVERAGE_LDFLAGS)
@@ -21,6 +21,7 @@ bs11_config_SOURCES = bs11_config.c
bs11_config_LDADD = $(top_builddir)/src/libbsc/libbsc.a \
$(top_builddir)/src/libtrau/libtrau.a \
$(top_builddir)/src/libcommon/libcommon.a \
$(top_builddir)/src/libxsc/libxsc.a \
$(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOABIS_LIBS)
isdnsync_SOURCES = isdnsync.c

View File

@@ -893,7 +893,7 @@ int main(int argc, char **argv)
handle_options(argc, argv);
bts_model_bs11_init();
gsmnet = gsm_network_init(1, 1, NULL);
gsmnet = gsm_network_init(tall_bsc_ctx, 1, 1, NULL);
if (!gsmnet) {
fprintf(stderr, "Unable to allocate gsm network\n");
exit(1);

Some files were not shown because too many files have changed in this diff Show More