large refactoring: support inter-BSC and inter-MSC Handover

3GPP TS 49.008 '4.3 Roles of MSC-A, MSC-I and MSC-T' defines distinct roles:
- MSC-A is responsible for managing subscribers,
- MSC-I is the gateway to the RAN.
- MSC-T is a second transitory gateway to another RAN during Handover.

After inter-MSC Handover, the MSC-I is handled by a remote MSC instance, while
the original MSC-A retains the responsibility of subscriber management.

MSC-T exists in this patch but is not yet used, since Handover is only prepared
for, not yet implemented.

Facilitate Inter-MSC and inter-BSC Handover by the same internal split of MSC
roles.

Compared to inter-MSC Handover, mere inter-BSC has the obvious simplifications:
- all of MSC-A, MSC-I and MSC-T roles will be served by the same osmo-msc
  instance,
- messages between MSC-A and MSC-{I,T} don't need to be routed via E-interface
  (GSUP),
- no call routing between MSC-A and -I via MNCC necessary.

This is the largest code bomb I have submitted, ever. Out of principle, I
apologize to everyone trying to read this as a whole. Unfortunately, I see no
sense in trying to split this patch into smaller bits. It would be a huge
amount of work to introduce these changes in separate chunks, especially if
each should in turn be useful and pass all test suites. So, unfortunately, we
are stuck with this code bomb.

The following are some details and rationale for this rather huge refactoring:

* separate MSC subscriber management from ran_conn

struct ran_conn is reduced from the pivotal subscriber management entity it has
been so far to a mere storage for an SCCP connection ID and an MSC subscriber
reference.

The new pivotal subscriber management entity is struct msc_a -- struct msub
lists the msc_a, msc_i, msc_t roles, the vast majority of code paths however
use msc_a, since MSC-A is where all the interesting stuff happens.

Before handover, msc_i is an FSM implementation that encodes to the local
ran_conn. After inter-MSC Handover, msc_i is a compatible but different FSM
implementation that instead forwards via/from GSUP. Same goes for the msc_a
struct: if osmo-msc is the MSC-I "RAN proxy" for a remote MSC-A role, the
msc_a->fi is an FSM implementation that merely forwards via/from GSUP.

* New SCCP implementation for RAN access

To be able to forward BSSAP and RANAP messages via the GSUP interface, the
individual message layers need to be cleanly separated. The IuCS implementation
used until now (iu_client from libosmo-ranap) did not provide this level of
separation, and needed a complete rewrite. It was trivial to implement this in
such a way that both BSSAP and RANAP can be handled by the same SCCP code,
hence the new SCCP-RAN layer also replaces BSSAP handling.

sccp_ran.h: struct sccp_ran_inst provides an abstract handler for incoming RAN
connections. A set of callback functions provides implementation specific
details.

* RAN Abstraction (BSSAP vs. RANAP)

The common SCCP implementation did set the theme for the remaining refactoring:
make all other MSC code paths entirely RAN-implementation-agnostic.

ran_infra.c provides data structures that list RAN implementation specifics,
from logging to RAN de-/encoding to SCCP callbacks and timers. A ran_infra
pointer hence allows complete abstraction of RAN implementations:

- managing connected RAN peers (BSC, RNC) in ran_peer.c,
- classifying and de-/encoding RAN PDUs,
- recording connected LACs and cell IDs and sending out Paging requests to
  matching RAN peers.

* RAN RESET now also for RANAP

ran_peer.c absorbs the reset_fsm from a_reset.c; in consequence, RANAP also
supports proper RESET semantics now. Hence osmo-hnbgw now also needs to provide
proper RESET handling, which it so far duly ignores. (TODO)

* RAN de-/encoding abstraction

The RAN abstraction mentioned above serves not only to separate RANAP and BSSAP
implementations transparently, but also to be able to optionally handle RAN on
distinct levels. Before Handover, all RAN messages are handled by the MSC-A
role.  However, after an inter-MSC Handover, a standalone MSC-I will need to
decode RAN PDUs, at least in order to manage Assignment of RTP streams between
BSS/RNC and MNCC call forwarding.

ran_msg.h provides a common API with abstraction for:

- receiving events from RAN, i.e. passing RAN decode from the BSC/RNC and
  MS/UE: struct ran_dec_msg represents RAN messages decoded from either BSSMAP
  or RANAP;
- sending RAN events: ran_enc_msg is the counterpart to compose RAN messages
  that should be encoded to either BSSMAP or RANAP and passed down to the
  BSC/RNC and MS/UE.

The RAN-specific implementations are completely contained by ran_msg_a.c and
ran_msg_iu.c.

In particular, Assignment and Ciphering have so far been distinct code paths
for BSSAP and RANAP, with switch(via_ran){...} statements all over the place.
Using RAN_DEC_* and RAN_ENC_* abstractions, these are now completely unified.

Note that SGs does not qualify for RAN abstraction: the SGs interface always
remains with the MSC-A role, and SGs messages follow quite distinct semantics
from the fairly similar GERAN and UTRAN.

* MGW and RTP stream management

So far, managing MGW endpoints via MGCP was tightly glued in-between
GSM-04.08-CC on the one and MNCC on the other side. Prepare for switching RTP
streams between different RAN peers by moving to object-oriented
implementations: implement struct call_leg and struct rtp_stream with distinct
FSMs each. For MGW communication, use the osmo_mgcpc_ep API that has originated
from osmo-bsc and recently moved to libosmo-mgcp-client for this purpose.
Instead of implementing a sequence of events with code duplication for the RAN
and CN sides, the idea is to manage each RTP stream separately by firing and
receiving events as soon as codecs and RTP ports are negotiated, and letting
the individual FSMs take care of the MGW management "asynchronously". The
caller provides event IDs and an FSM instance that should be notified of RTP
stream setup progress. Hence it becomes possible to reconnect RTP streams from
one GSM-04.08-CC to another (inter-BSC Handover) or between CC and MNCC RTP
peers (inter-MSC Handover) without duplicating the MGCP code for each
transition.

The number of FSM implementations used for MGCP handling may seem a bit of an
overkill. But in fact, the number of perspectives on RTP forwarding are far
from trivial:
- an MGW endpoint is an entity with N connections, and MGCP "sessions" for
  configuring them by talking to the MGW;
- an RTP stream is a remote peer connected to one of the endpoint's
  connections, which is asynchronously notified of codec and RTP port choices;
- a call leg is the higher level view on either an MT or MO side of a voice
  call, a combination of two RTP streams to forward between two remote peers.

  BSC                 MGW                PBX
                CI          CI
                [MGW-endpoint]
  [--rtp_stream--]          [--rtp_stream--]
  [----------------call_leg----------------]

* Use counts

Introduce using the new osmo_use_count API added to libosmocore for this
purpose. Each use token has a distinct name in the logging, which can be a
globally constant name or ad-hoc, like the local __func__ string constant.  Use
in the new struct msc_a, as well as change vlr_subscr to the new osmo_use_count
API.

* FSM Timeouts

Introduce using the new osmo_tdef API, which provides a common VTY
implementation for all timer numbers, and FSM state transitions with the
correct timeout. Originated in osmo-bsc, recently moved to libosmocore.

Depends: Ife31e6798b4e728a23913179e346552a7dd338c0 (libosmocore)
         Ib9af67b100c4583342a2103669732dab2e577b04 (libosmocore)
	 Id617265337f09dfb6ddfe111ef5e578cd3dc9f63 (libosmocore)
	 Ie9e2add7bbfae651c04e230d62e37cebeb91b0f5 (libosmo-sccp)
	 I26be5c4b06a680f25f19797407ab56a5a4880ddc (osmo-mgw)
	 Ida0e59f9a1f2dd18efea0a51680a67b69f141efa (osmo-mgw)
	 I9a3effd38e72841529df6c135c077116981dea36 (osmo-mgw)
Change-Id: I27e4988e0371808b512c757d2b52ada1615067bd
changes/37/13137/20
Neels Hofmeyr 4 years ago
parent 56f90132b8
commit c4628a3ad4
  1. 1
      configure.ac
  2. 1
      doc/Makefile.am
  3. 35
      doc/sequence_charts/Makefile.am
  4. 36
      doc/sequence_charts/inter_bsc_ho.msc
  5. 82
      doc/sequence_charts/inter_msc_ho.msc
  6. 84
      doc/sequence_charts/mncc_fsm.msc
  7. 31
      include/osmocom/msc/Makefile.am
  8. 83
      include/osmocom/msc/a_iface.h
  9. 41
      include/osmocom/msc/a_iface_bssap.h
  10. 31
      include/osmocom/msc/a_reset.h
  11. 81
      include/osmocom/msc/call_leg.h
  12. 43
      include/osmocom/msc/cell_id_list.h
  13. 36
      include/osmocom/msc/e_link.h
  14. 37
      include/osmocom/msc/gsm_04_08.h
  15. 5
      include/osmocom/msc/gsm_04_11.h
  16. 7
      include/osmocom/msc/gsm_04_11_gsup.h
  17. 14
      include/osmocom/msc/gsm_04_14.h
  18. 15
      include/osmocom/msc/gsm_04_80.h
  19. 10
      include/osmocom/msc/gsm_09_11.h
  20. 41
      include/osmocom/msc/gsm_data.h
  21. 6
      include/osmocom/msc/gsm_data_shared.h
  22. 36
      include/osmocom/msc/gsm_subscriber.h
  23. 34
      include/osmocom/msc/gsup_client_mux.h
  24. 50
      include/osmocom/msc/iu_dummy.h
  25. 14
      include/osmocom/msc/iucs.h
  26. 7
      include/osmocom/msc/iucs_ranap.h
  27. 14
      include/osmocom/msc/mncc.h
  28. 140
      include/osmocom/msc/mncc_call.h
  29. 215
      include/osmocom/msc/msc_a.h
  30. 17
      include/osmocom/msc/msc_a_remote.h
  31. 39
      include/osmocom/msc/msc_common.h
  32. 104
      include/osmocom/msc/msc_ho.h
  33. 46
      include/osmocom/msc/msc_i.h
  34. 14
      include/osmocom/msc/msc_i_remote.h
  35. 39
      include/osmocom/msc/msc_ifaces.h
  36. 65
      include/osmocom/msc/msc_mgcp.h
  37. 387
      include/osmocom/msc/msc_roles.h
  38. 60
      include/osmocom/msc/msc_t.h
  39. 14
      include/osmocom/msc/msc_t_remote.h
  40. 79
      include/osmocom/msc/msub.h
  41. 68
      include/osmocom/msc/neighbor_ident.h
  42. 46
      include/osmocom/msc/paging.h
  43. 243
      include/osmocom/msc/ran_conn.h
  44. 31
      include/osmocom/msc/ran_infra.h
  45. 281
      include/osmocom/msc/ran_msg.h
  46. 45
      include/osmocom/msc/ran_msg_a.h
  47. 35
      include/osmocom/msc/ran_msg_iu.h
  48. 106
      include/osmocom/msc/ran_peer.h
  49. 64
      include/osmocom/msc/rtp_stream.h
  50. 280
      include/osmocom/msc/sccp_ran.h
  51. 9
      include/osmocom/msc/sgs_iface.h
  52. 20
      include/osmocom/msc/signal.h
  53. 13
      include/osmocom/msc/silent_call.h
  54. 1
      include/osmocom/msc/sms_queue.h
  55. 55
      include/osmocom/msc/transaction.h
  56. 42
      include/osmocom/msc/vlr.h
  57. 2
      include/osmocom/msc/vlr_sgs.h
  58. 38
      src/libmsc/Makefile.am
  59. 687
      src/libmsc/a_iface.c
  60. 730
      src/libmsc/a_iface_bssap.c
  61. 150
      src/libmsc/a_reset.c
  62. 348
      src/libmsc/call_leg.c
  63. 79
      src/libmsc/cell_id_list.c
  64. 372
      src/libmsc/e_link.c
  65. 1354
      src/libmsc/gsm_04_08.c
  66. 508
      src/libmsc/gsm_04_08_cc.c
  67. 168
      src/libmsc/gsm_04_11.c
  68. 59
      src/libmsc/gsm_04_11_gsup.c
  69. 36
      src/libmsc/gsm_04_14.c
  70. 24
      src/libmsc/gsm_04_80.c
  71. 216
      src/libmsc/gsm_09_11.c
  72. 216
      src/libmsc/gsm_subscriber.c
  73. 163
      src/libmsc/gsup_client_mux.c
  74. 99
      src/libmsc/iu_dummy.c
  75. 249
      src/libmsc/iucs.c
  76. 137
      src/libmsc/iucs_ranap.c
  77. 100
      src/libmsc/mncc.c
  78. 6
      src/libmsc/mncc_builtin.c
  79. 760
      src/libmsc/mncc_call.c
  80. 11
      src/libmsc/mncc_sock.c
  81. 1651
      src/libmsc/msc_a.c
  82. 392
      src/libmsc/msc_a_remote.c
  83. 879
      src/libmsc/msc_ho.c
  84. 383
      src/libmsc/msc_i.c
  85. 245
      src/libmsc/msc_i_remote.c
  86. 143
      src/libmsc/msc_ifaces.c
  87. 1254
      src/libmsc/msc_mgcp.c
  88. 126
      src/libmsc/msc_net_init.c
  89. 962
      src/libmsc/msc_t.c
  90. 226
      src/libmsc/msc_t_remote.c
  91. 226
      src/libmsc/msc_vty.c
  92. 590
      src/libmsc/msub.c
  93. 191
      src/libmsc/neighbor_ident.c
  94. 421
      src/libmsc/neighbor_ident_vty.c
  95. 227
      src/libmsc/osmo_msc.c
  96. 183
      src/libmsc/paging.c
  97. 908
      src/libmsc/ran_conn.c
  98. 118
      src/libmsc/ran_infra.c
  99. 160
      src/libmsc/ran_msg.c
  100. 1284
      src/libmsc/ran_msg_a.c
  101. Some files were not shown because too many files have changed in this diff Show More

@ -256,6 +256,7 @@ AC_OUTPUT(
doc/Makefile
doc/examples/Makefile
doc/manuals/Makefile
doc/sequence_charts/Makefile
contrib/Makefile
contrib/systemd/Makefile
Makefile)

@ -1,4 +1,5 @@
SUBDIRS = \
examples \
manuals \
sequence_charts \
$(NULL)

@ -0,0 +1,35 @@
all:
echo "built only on manual invocation, needs mscgen and dot (graphviz) programs: invoke 'make charts'"
charts: msc dot
EXTRA_DIST = \
inter_bsc_ho.msc \
inter_msc_ho.msc \
mncc_fsm.msc \
$(NULL)
CLEANFILES = \
inter_bsc_ho.png \
inter_msc_ho.png \
mncc_fsm.png \
$(NULL)
msc: \
$(builddir)/mncc_fsm.png \
$(builddir)/inter_bsc_ho.png \
$(builddir)/inter_msc_ho.png \
$(NULL)
dot: \
$(NULL)
$(builddir)/%.png: $(srcdir)/%.msc
mscgen -T png -o $@ $<
$(builddir)/%.png: $(srcdir)/%.dot
dot -Tpng $< > $@
.PHONY: poll
poll:
while true; do $(MAKE) msc dot; sleep 1; done

@ -0,0 +1,36 @@
msc {
hscale=2;
bsca [label="BSC-A"], i[label="MSC-I"], a[label="MSC-A"], t[label="MSC-T"], bscb[label="BSC-B"];
i note t [label="'MSC-A,I,T' are explained in 3GPP TS 49.008 '4.3 Roles of MSC-A, MSC-I and MSC-T'"];
i note i [label="I = Internal; the MSC that does BSSMAP to the BSC (may change to a remote MSC-B after HO)"];
a note a [label="A = first; the MSC that has MM control BSSMAP to the BSC (never changes)"];
t note t [label="T = transitory; the MSC that a handover is going towards (may be MSC-A for inter-BSC HO, may be a remote MSC-B)"];
bsca => i [label="BSSMAP Handover Required"];
i -> a [label="BSSMAP Handover Required"];
a -> t [label="MAP Prepare Handover"];
t => bscb [label="BSSMAP Handover Request"];
t <= bscb [label="BSSMAP Handover Request ACK"];
a <- t [label="MAP Prepare Handover Response"];
i <- a [label="MAP Prepare Handover Response"];
bsca <= i [label="BSSMAP Handover Command"];
--- [label="MS sends RACH to new cell"];
t <= bscb [label="BSSMAP Handover Detected"];
a <- t [label="MAP Access Signaling Request"];
t <= bscb [label="BSSMAP Handover Complete"];
a <- t [label="MAP Send End Signal"];
a abox a [label="MSC-A accepts the new BSC"];
i note t [label="previous MSC-I gets dropped, MSC-T becomes the new MSC-I"];
i abox i [label="discard"];
t abox t [label="MSC-I"];
bsca <= i [label="BSSMAP Clear Command"];
}

@ -0,0 +1,82 @@
msc {
hscale=2;
bsca [label="BSC-A"], ai[label="MSC-I (at MSC-A)"], a[label="MSC-A"], bt[label="MSC-T (at MSC-B)"], bi[label="MSC-I (at MSC-B)"], bscb[label="BSC-B"],
ct[label="MSC-T (at MSC-C)"], bscc[label="BSC-C"];
ai note bt [label="'MSC-A,I,T' are explained in 3GPP TS 49.008 '4.3 Roles of MSC-A, MSC-I and MSC-T'"];
ai note ai [label="I = Internal; the MSC that does BSSMAP to the BSC (may change to a remote MSC-B after HO)"];
a note a [label="A = first; the MSC that has MM control (never changes)"];
bt note bi [label="B = second; the MSC that acts as BSS relay for MSC-A"];
bt note bt [label="T = transitory; the MSC that a handover is going towards (may be MSC-A for inter-BSC HO, may be a remote MSC-B)"];
bsca => ai [label="BSSMAP Handover Required"];
ai -> a [label="BSSMAP Handover Required"];
a rbox a [label="MSC-A routes all MSC-T messages to remote MSC-B."];
a => bt [label="MAP Prepare Handover"];
a note bt [label="in Osmocom, MAP messages are actually sent as GSUP, to the HLR"];
bt rbox bt [label="MSC-B routes all MSC-A type messages back to MSC-A."];
bt rbox bt [label="MSC-B generates a Handover MSISDN"];
bt => bscb [label="BSSMAP Handover Request"];
bt <= bscb [label="BSSMAP Handover Request ACK"];
a <= bt [label="MAP Prepare Handover Response"];
a => bt [label="establish SIP call to Handover MSISDN via external MNCC"];
ai <- a [label="BSSMAP Handover Command"];
bsca <= ai [label="BSSMAP Handover Command"];
--- [label="MS sends RACH to new cell"];
bt <= bscb [label="BSSMAP Handover Detected"];
a <= bt [label="MAP Access Signaling Request"];
bt <= bscb [label="BSSMAP Handover Complete"];
a <= bt [label="MAP Send End Signal"];
bt rbox bt [label="MSC-B drops the generated Handover MSISDN"];
a abox a [label="MSC-A accepts the new MSC-B and BSC"];
ai note bt [label="previous MSC-I (A) gets dropped, MSC-T (B) becomes the new MSC-I"];
ai rbox a [label="MSC-A performs all MSC-I tasks via MAP at remote MSC-B's MSC-I."];
bt abox bi [label="MSC-I"];
ai abox ai [label="discard"];
bsca <= ai [label="BSSMAP Clear Command"];
...;
...;
--- [label="Another inter-MSC handover"];
a note bi [label="MSC-A remains in charge"];
bscb => bi [label="BSSMAP Handover Required"];
bi => a [label="BSSMAP Handover Required"];
a rbox a [label="MSC-A routes all MSC-T messages to remote MSC-C."];
a => ct [label="MAP Prepare Handover"];
ct rbox ct [label="MSC-C routes all MSC-A type messages back to MSC-A."];
ct => bscc [label="BSSMAP Handover Request"];
ct <= bscc [label="BSSMAP Handover Request ACK"];
a <= ct [label="MAP Prepare Handover Response"];
a => bi [label="MAP Prepare Handover Response"];
bscb <= bi [label="BSSMAP Handover Command"];
--- [label="MS sends RACH to new cell"];
ct <= bscc [label="BSSMAP Handover Detected"];
a <= ct [label="MAP Access Signaling Request"];
ct <= bscc [label="BSSMAP Handover Complete"];
a <= ct [label="MAP Send End Signal"];
a abox a [label="MSC-A accepts the new MSC-C and BSC"];
bi note ct [label="previous MSC-I (B) gets dropped, MSC-T (B) becomes the new MSC-I"];
ai rbox a [label="MSC-A performs all MSC-I tasks via MAP at remote MSC-C's MSC-I."];
ct abox ct [label="MSC-I"];
bi abox bi [label="discard"];
bscb <= bi [label="BSSMAP Clear Command"];
}

@ -0,0 +1,84 @@
msc {
hscale=2;
msc1[label="osmo-msc"], mncc1[label="MNCC FSM"], pbx[label="MNCC server (osmo-sip-connector)"], mncc2[label="MNCC FSM"], msc2[label="osmo-msc"];
mncc1 note mncc1 [label="The typical progression of an outgoing call, i.e. a call initiated by osmo-msc, as
implemented in mncc_fsm.h, mncc_fsm.c"];
mncc2 note mncc2 [label="The typical progression of an incoming call, i.e. a call initiated by the PBX, as
implemented in mncc_fsm.h, mncc_fsm.c"];
mncc1 abox mncc1 [label="MNCC_ST_NOT_STARTED"];
msc1 rbox msc1 [label="mncc_outgoing_start()"];
msc1 -> mncc1 [label="MNCC_EV_OUTGOING_START"];
mncc1 abox mncc1 [label="MNCC_ST_OUTGOING_WAIT_PROCEEDING"];
mncc1 => pbx [label="MNCC_SETUP_IND
\n callref, IMSI, called and calling number"];
mncc1 <= pbx [label="MNCC_RTP_CREATE
\n callref"];
mncc1 rbox mncc1 [label="mncc_rx_rtp_create()"];
mncc1 => pbx [label="MNCC_RTP_CREATE
\n callref, RTP IP address and port"];
mncc1 <= pbx [label="MNCC_CALL_PROC_REQ
\n callref, RTP IP address and port"];
mncc1 abox mncc1 [label="MNCC_ST_OUTGOING_WAIT_COMPLETE"];
msc2 <= pbx [label="MNCC_SETUP_REQ
\n callref, called and calling number"];
mncc2 abox mncc2 [label="MNCC_ST_NOT_STARTED"];
msc2 rbox msc2 [label="mncc_incoming_start()"];
msc2 -> mncc2 [label="MNCC_EV_INCOMING_START"];
mncc2 abox mncc2 [label="MNCC_ST_INCOMING_WAIT_COMPLETE"];
mncc2 => pbx [label="MNCC_CALL_CONF_IND
\n callref, bearer capabilities, cccap and IMSI"];
mncc2 <= pbx [label="MNCC_RTP_CREATE
\n callref"];
mncc2 rbox mncc2 [label="mncc_rx_rtp_create()"];
mncc2 => pbx [label="MNCC_RTP_CREATE
\n callref, RTP IP address and port"];
mncc2 => pbx [label="MNCC_ALERT_IND
\n callref"];
mncc1 <= pbx [label="MNCC_ALERT_REQ
\n callref and progress"];
mncc2 => pbx [label="MNCC_SETUP_CNF
\n callref, imsi and connected number"];
mncc2 <= pbx [label="MNCC_RTP_CONNECT
\n callref, RTP IP and port"];
mncc2 rbox mncc2 [label="mncc_rx_rtp_connect()"];
mncc2 <= pbx [label="MNCC_SETUP_COMPL_REQ
\n callref"];
mncc2 abox mncc2 [label="MNCC_ST_TALKING"];
mncc1 <= pbx [label="MNCC_RTP_CONNECT
\n callref, RTP IP and port"];
mncc1 rbox mncc1 [label="mncc_rx_rtp_connect()"];
msc1 <- mncc1 [label="rtp_stream_set_remote_addr()"];
mncc1 <= pbx [label="MNCC_SETUP_RSP
\n callref"];
mncc1 => pbx [label="MNCC_SETUP_COMPL_IND
\n callref"];
mncc1 abox mncc1 [label="MNCC_ST_TALKING"];
...;
... [label="Call goes on for a while..."];
...;
mncc1 rbox mncc1 [label="mncc_release()"];
mncc1 => pbx [label="MNCC_DISC_IND
\n callref and cause"];
mncc1 abox mncc1 [label="MNCC_ST_WAIT_RELEASE_ACK"];
mncc1 <= pbx [label="MNCC_REL_REQ
\n callref and cause"];
mncc2 <= pbx [label="MNCC_DISC_REQ
\n callref and cause"];
mncc2 => pbx [label="MNCC_REL_IND
\n callref and cause"];
mncc2 abox mncc2 [label="terminated"];
mncc1 => pbx [label="MNCC_REL_CNF
\n callref"];
mncc1 abox mncc1 [label="terminated"];
}

@ -1,8 +1,9 @@
noinst_HEADERS = \
a_iface.h \
a_iface_bssap.h \
call_leg.h \
cell_id_list.h \
db.h \
debug.h \
e_link.h \
gsm_04_08.h \
gsm_04_11.h \
gsm_04_11_gsup.h \
@ -12,17 +13,31 @@ noinst_HEADERS = \
gsm_data.h \
gsm_data_shared.h \
gsm_subscriber.h \
iucs.h \
iucs_ranap.h \
iu_dummy.h \
gsup_client_mux.h \
mncc.h \
mncc_call.h \
mncc_int.h \
msc_a.h \
msc_a_remote.h \
msc_common.h \
msc_ifaces.h \
msc_mgcp.h \
a_reset.h \
msc_ho.h \
msc_i.h \
msc_i_remote.h \
msc_roles.h \
msc_t.h \
msc_t_remote.h \
msub.h \
neighbor_ident.h \
paging.h \
ran_conn.h \
ran_infra.h \
ran_msg.h \
ran_msg_a.h \
ran_msg_iu.h \
ran_peer.h \
rrlp.h \
rtp_stream.h \
sccp_ran.h \
sgs_iface.h \
sgs_server.h \
sgs_vty.h \

@ -1,83 +0,0 @@
/* (C) 2017 by Sysmocom s.f.m.c. GmbH
* All Rights Reserved
*
* Author: Philipp Maier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <osmocom/msc/a_reset.h>
#include <osmocom/msc/transaction.h>
#include <osmocom/msc/vlr.h>
#include <osmocom/gsm/protocol/gsm_08_08.h>
/* A struct to keep a context information about the BSCs we are associated with */
struct bsc_context {
struct llist_head list;
/* Holds a copy of the sccp address of the BSC,
* this address will become known as soon as
* a remote BSC tries to make a connection or
* sends a RESET request via UNIDATA */
struct osmo_sccp_addr bsc_addr;
/* Holds a copy of the our local MSC address,
* this will be the sccp-address that is associated
* with the A interface */
struct osmo_sccp_addr msc_addr;
/* A pointer to the reset handler FSM, the
* state machine is allocated when the BSC
* is registerd. */
struct osmo_fsm_inst *reset_fsm;
/* A pointer to the sccp_user that is associated
* with the A interface. We need this information
* to send the resets and to send paging requests */
struct osmo_sccp_user *sccp_user;
};
/* Initalize A interface connection between to MSC and BSC */
int a_init(struct osmo_sccp_instance *sccp, struct gsm_network *network);
/* Send DTAP message via A-interface, take ownership of msg */
int a_iface_tx_dtap(struct msgb *msg);
/* Send Cipher mode command via A-interface */
int a_iface_tx_cipher_mode(const struct ran_conn *conn,
struct gsm0808_encrypt_info *ei, int include_imeisv);
/* Page a subscriber via A-interface */
int a_iface_tx_paging(const char *imsi, uint32_t tmsi, uint16_t lac);
/* Send assignment request via A-interface */
int a_iface_tx_assignment(const struct gsm_trans *trans);
/* Send clear command via A-interface */
int a_iface_tx_clear_cmd(const struct ran_conn *conn);
int a_iface_tx_classmark_request(const struct ran_conn *conn);
/* Clear all RAN connections on a specified BSC
* (Helper function for a_iface_bssap.c) */
void a_clear_all(struct osmo_sccp_user *scu, const struct osmo_sccp_addr *bsc_addr);
void a_start_reset(struct bsc_context *bsc_ctx, bool already_connected);
/* Delete info of a closed connection from the active connection list
* (Helper function for a_iface_bssap.c) */
void a_delete_bsc_con(uint32_t conn_id);

@ -1,41 +0,0 @@
/* (C) 2017 by sysmocom s.f.m.c. GmbH
* All Rights Reserved
*
* Author: Philipp Maier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include <osmocom/msc/a_iface.h>
/* Note: The structs and functions presented in this header file are intended
* to be used only by a_iface.c. */
/* A structure to hold tha most basic information about a sigtran connection
* we use this struct internally here to pass connection data around */
struct a_conn_info {
struct bsc_context *bsc;
uint32_t conn_id;
struct gsm_network *network;
};
/* Receive incoming connection less data messages via sccp */
void a_sccp_rx_udt(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg);
/* Receive incoming connection oriented data messages via sccp */
int a_sccp_rx_dt(struct osmo_sccp_user *scu, const struct a_conn_info *a_conn_info, struct msgb *msg);

@ -1,31 +0,0 @@
/* (C) 2017 by sysmocom s.f.m.c. GmbH
* All Rights Reserved
*
* Author: Philipp Maier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
/* Create and start state machine which handles the reset/reset-ack procedure */
struct osmo_fsm_inst *a_reset_alloc(void *ctx, const char *name, void *cb,
void *priv, bool already_connected);
/* Confirm that we sucessfully received a reset acknowlege message */
void a_reset_ack_confirm(struct osmo_fsm_inst *reset_fsm);
/* Check if we have a connection to a specified msc */
bool a_reset_conn_ready(struct osmo_fsm_inst *reset_fsm);

@ -0,0 +1,81 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <osmocom/core/tdef.h>
struct osmo_fsm_inst;
struct osmo_sockaddr_str;
struct osmo_mgcpc_ep;
struct gsm_network;
struct gsm_trans;
struct rtp_stream;
enum rtp_direction;
extern struct osmo_tdef g_mgw_tdefs[];
/* All sides of an MGW endpoint, connecting remote RTP peers via the MGW.
*
* BSC MGW PBX
* CI CI
* [MGW-endpoint]
* [--rtp_stream--] [--rtp_stream--]
* [----------------call_leg----------------]
*
*/
struct call_leg {
struct osmo_fsm_inst *fi;
struct osmo_mgcpc_ep *mgw_endpoint;
/* Array indexed by enum rtp_direction. */
struct rtp_stream *rtp[2];
/* Array indexed by enum rtp_direction. */
enum mgcp_connection_mode crcx_conn_mode[2];
uint32_t parent_event_rtp_addr_available;
uint32_t parent_event_rtp_complete;
uint32_t parent_event_rtp_released;
/* For internal MNCC, if RTP addresses for endpoints become assigned by the MGW, implicitly notify the other
* call leg's RTP_TO_CN side rtp_stream with rtp_stream_remote_addr_available(). */
struct call_leg *local_bridge;
/* Prevent events from deallocating for certain release code paths, to prevent use-after-free problems. */
bool deallocating;
};
enum call_leg_event {
CALL_LEG_EV_RTP_STREAM_ADDR_AVAILABLE,
CALL_LEG_EV_RTP_STREAM_ESTABLISHED,
CALL_LEG_EV_RTP_STREAM_GONE,
CALL_LEG_EV_MGW_ENDPOINT_GONE,
};
void call_leg_init(struct gsm_network *net);
struct call_leg *call_leg_alloc(struct osmo_fsm_inst *parent_fi,
uint32_t parent_event_term,
uint32_t parent_event_rtp_addr_available,
uint32_t parent_event_rtp_complete,
uint32_t parent_event_rtp_released);
void call_leg_reparent(struct call_leg *cl,
struct osmo_fsm_inst *parent_fi,
uint32_t parent_event_term,
uint32_t parent_event_rtp_addr_available,
uint32_t parent_event_rtp_complete,
uint32_t parent_event_rtp_released);
int call_leg_local_bridge(struct call_leg *cl1, uint32_t call_id1, struct gsm_trans *trans1,
struct call_leg *cl2, uint32_t call_id2, struct gsm_trans *trans2);
int call_leg_ensure_rtp_alloc(struct call_leg *cl, enum rtp_direction dir, uint32_t call_id,
struct gsm_trans *for_trans);
int call_leg_ensure_ci(struct call_leg *cl, enum rtp_direction dir, uint32_t call_id, struct gsm_trans *for_trans,
const enum mgcp_codecs *codec_if_known, const struct osmo_sockaddr_str *remote_port_if_known);
struct osmo_sockaddr_str *call_leg_local_ip(struct call_leg *cl, enum rtp_direction dir);
void call_leg_rtp_stream_gone(struct call_leg *cl, struct rtp_stream *rtps);
void call_leg_release(struct call_leg *cl);

@ -0,0 +1,43 @@
/* Manage a list of struct gsm0808_cell_id */
/*
* (C) 2019 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* Author: Neels Hofmeyr
*
* SPDX-License-Identifier: GPL-2.0+
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include <osmocom/core/linuxlist.h>
#include <osmocom/gsm/gsm0808_utils.h>
struct cell_id_list_entry {
struct llist_head entry;
struct gsm0808_cell_id cell_id;
};
int cell_id_list_add_cell(void *talloc_ctx, struct llist_head *list, const struct gsm0808_cell_id *cid);
int cell_id_list_add_list(void *talloc_ctx, struct llist_head *list, const struct gsm0808_cell_id_list2 *cil);
struct cell_id_list_entry *cell_id_list_find(struct llist_head *list,
const struct gsm0808_cell_id *id,
unsigned int match_nr,
bool exact_match);
void cell_id_list_del_entry(struct cell_id_list_entry *e);

@ -0,0 +1,36 @@
/* E-interface messaging over a GSUP connection */
#pragma once
#include <osmocom/gsm/gsup.h>
#include <osmocom/msc/msc_roles.h>
struct osmo_fsm_inst;
struct gsm_network;
struct vlr_instance;
/* E-interface: connection to a remote MSC via GSUP */
struct e_link {
struct osmo_fsm_inst *msc_role;
struct gsup_client_mux *gcm;
uint8_t *remote_name;
size_t remote_name_len;
};
struct e_link *e_link_alloc(struct gsup_client_mux *gcm, struct osmo_fsm_inst *msc_role,
const uint8_t *remote_name, size_t remote_name_len);
void e_link_assign(struct e_link *e, struct osmo_fsm_inst *msc_role);
void e_link_free(struct e_link *e);
int e_prep_gsup_msg(struct e_link *e, struct osmo_gsup_message *gsup_msg);
int e_tx(struct e_link *e, const struct osmo_gsup_message *gsup_msg);
const char *e_link_name(struct e_link *e);
void msc_a_i_t_gsup_init(struct gsm_network *net);
enum osmo_gsup_entity msc_role_to_gsup_entity(enum msc_role role);
enum msc_role gsup_entity_to_msc_role(enum osmo_gsup_entity entity);
int gsup_msg_assign_an_apdu(struct osmo_gsup_message *gsup_msg, struct an_apdu *an_apdu);
struct msgb *gsup_msg_to_msgb(const struct osmo_gsup_message *gsup_msg);
void gsup_msg_to_an_apdu(struct an_apdu *an_apdu, const struct osmo_gsup_message *gsup_msg);

@ -4,6 +4,7 @@
#include <osmocom/gsm/gsm48.h>
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/msc/transaction.h>
struct msgb;
struct gsm_bts;
@ -12,6 +13,7 @@ struct gsm_trans;
struct ran_conn;
struct amr_multirate_conf;
struct amr_mode;
struct msc_a;
#define GSM48_ALLOC_SIZE 2048
#define GSM48_ALLOC_HEADROOM 256
@ -22,33 +24,26 @@ static inline struct msgb *gsm48_msgb_alloc_name(const char *name)
name);
}
void cm_service_request_concludes(struct ran_conn *conn,
struct msgb *msg);
void cm_service_request_concludes(struct msc_a *msc_a, struct msgb *msg, enum osmo_cm_service_type type);
/* config options controlling the behaviour of the lower leves */
void gsm0408_clear_all_trans(struct gsm_network *net, int protocol);
int gsm0408_dispatch(struct ran_conn *conn, struct msgb *msg);
void gsm0408_clear_all_trans(struct gsm_network *net, enum trans_type type);
int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id);
/* don't use "enum gsm_chreq_reason_t" to avoid circular dependency */
void gsm_net_update_ctype(struct gsm_network *net);
int gsm48_tx_simple(struct ran_conn *conn,
uint8_t pdisc, uint8_t msg_type);
int gsm48_tx_mm_info(struct ran_conn *conn);
int gsm48_tx_mm_auth_req(struct ran_conn *conn, uint8_t *rand,
uint8_t *autn, int key_seq);
int gsm48_tx_mm_auth_rej(struct ran_conn *conn);
int gsm48_tx_mm_serv_ack(struct ran_conn *conn);
int gsm48_tx_mm_serv_rej(struct ran_conn *conn,
enum gsm48_reject_value value);
int gsm48_tx_simple(struct msc_a *msc_a, uint8_t pdisc, uint8_t msg_type);
int gsm48_tx_mm_info(struct msc_a *msc_a);
int gsm48_tx_mm_auth_req(struct msc_a *msc_a, uint8_t *rand, uint8_t *autn, int key_seq);
int gsm48_tx_mm_auth_rej(struct msc_a *msc_a);
int gsm48_tx_mm_serv_ack(struct msc_a *msc_a);
int gsm48_tx_mm_serv_rej(struct msc_a *msc_a, enum gsm48_reject_value value);
int gsm48_send_rr_release(struct gsm_lchan *lchan);
int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv);
int gsm48_send_rr_app_info(struct ran_conn *conn, uint8_t apdu_id,
uint8_t apdu_len, const uint8_t *apdu);
int gsm48_send_rr_app_info(struct msc_a *msc_a, uint8_t apdu_id, uint8_t apdu_len, const uint8_t *apdu);
int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, uint8_t power_class);
int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan,
uint8_t power_command, uint8_t ho_ref);
int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan, uint8_t power_command, uint8_t ho_ref);
int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg);
@ -79,4 +74,12 @@ int gsm48_tch_rtp_create(struct gsm_trans *trans);
int gsm48_conn_sendmsg(struct msgb *msg, struct ran_conn *conn, struct gsm_trans *trans);
struct msgb *gsm48_create_mm_info(struct gsm_network *net);
int gsm0408_rcv_cc(struct msc_a *msc_a, struct msgb *msg);
int gsm0408_rcv_mm(struct msc_a *msc_a, struct msgb *msg);
int gsm0408_rcv_rr(struct msc_a *msc_a, struct msgb *msg);
int msc_vlr_tx_cm_serv_acc(void *msc_conn_ref, enum osmo_cm_service_type cm_service_type);
int compl_l3_msg_is_r99(const struct msgb *msg);
#endif

@ -7,6 +7,7 @@
struct vlr_subscr;
struct ran_conn;
struct gsm_trans;
struct msc_a;
#define UM_SAPI_SMS 3 /* See GSM 04.05/04.06 */
@ -31,7 +32,7 @@ struct sms_deliver {
struct gsm_network;
struct msgb;
int gsm0411_rcv_sms(struct ran_conn *conn, struct msgb *msg);
int gsm0411_rcv_sms(struct msc_a *msc_a, struct msgb *msg);
struct gsm_sms *sms_alloc(void);
void sms_free(struct gsm_sms *sms);
@ -46,7 +47,7 @@ int gsm411_send_rp_data(struct gsm_network *net, struct vlr_subscr *vsub,
size_t sm_rp_oa_len, const uint8_t *sm_rp_oa,
size_t sm_rp_ud_len, const uint8_t *sm_rp_ud);
void gsm411_sapi_n_reject(struct ran_conn *conn);
void gsm411_sapi_n_reject(struct msc_a *msc_a);
int gsm411_send_rp_ack(struct gsm_trans *trans, uint8_t msg_ref);
int gsm411_send_rp_error(struct gsm_trans *trans, uint8_t msg_ref,

@ -2,6 +2,7 @@
#include <stdint.h>
struct gsup_client_mux;
struct osmo_gsup_message;
struct vlr_subscr;
struct gsm_trans;
@ -10,11 +11,9 @@ struct msgb;
int gsm411_gsup_mo_ready_for_sm_req(struct gsm_trans *trans, uint8_t sm_rp_mr);
int gsm411_gsup_mo_fwd_sm_req(struct gsm_trans *trans, struct msgb *msg,
uint8_t sm_rp_mr, uint8_t *sm_rp_da, uint8_t sm_rp_da_len);
int gsm411_gsup_mo_handler(struct vlr_subscr *vsub,
struct osmo_gsup_message *gsup_msg);
int gsm411_gsup_mt_fwd_sm_res(struct gsm_trans *trans, uint8_t sm_rp_mr);
int gsm411_gsup_mt_fwd_sm_err(struct gsm_trans *trans,
uint8_t sm_rp_mr, uint8_t cause);
int gsm411_gsup_mt_handler(struct vlr_subscr *vsub,
struct osmo_gsup_message *gsup_msg);
int gsm411_gsup_rx(struct gsup_client_mux *gcm, void *data, const struct osmo_gsup_message *gsup_msg);

@ -2,14 +2,16 @@
#include <osmocom/gsm/protocol/gsm_04_14.h>
int gsm0414_tx_close_tch_loop_cmd(struct ran_conn *conn,
struct msc_a;
int gsm0414_tx_close_tch_loop_cmd(struct msc_a *msc_a,
enum gsm414_tch_loop_mode loop_mode);
int gsm0414_tx_open_loop_cmd(struct ran_conn *conn);
int gsm0414_tx_act_emmi_cmd(struct ran_conn *conn);
int gsm0414_tx_test_interface(struct ran_conn *conn,
int gsm0414_tx_open_loop_cmd(struct msc_a *msc_a);
int gsm0414_tx_act_emmi_cmd(struct msc_a *msc_a);
int gsm0414_tx_test_interface(struct msc_a *msc_a,
uint8_t tested_devs);
int gsm0414_tx_reset_ms_pos_store(struct ran_conn *conn,
int gsm0414_tx_reset_ms_pos_store(struct msc_a *msc_a,
uint8_t technology);
int gsm0414_rcv_test(struct ran_conn *conn,
int gsm0414_rcv_test(struct msc_a *msc_a,
struct msgb *msg);

@ -2,16 +2,13 @@
#include <stdint.h>
struct ran_conn;
struct msc_a;
int msc_send_ussd_reject(struct ran_conn *conn,
uint8_t transaction_id, int invoke_id,
uint8_t problem_tag, uint8_t problem_code);
int msc_send_ussd_reject(struct msc_a *msc_a, uint8_t transaction_id, int invoke_id,
uint8_t problem_tag, uint8_t problem_code);
int msc_send_ussd_notify(struct ran_conn *conn, int level,
const char *text);
int msc_send_ussd_release_complete(struct ran_conn *conn,
uint8_t transaction_id);
int msc_send_ussd_release_complete_cause(struct ran_conn *conn,
int msc_send_ussd_notify(struct msc_a *msc_a, int level, const char *text);
int msc_send_ussd_release_complete(struct msc_a *msc_a, uint8_t transaction_id);
int msc_send_ussd_release_complete_cause(struct msc_a *msc_a,
uint8_t transaction_id,
uint8_t cause_loc, uint8_t cause_val);

@ -1,7 +1,9 @@
#pragma once
#include <osmocom/core/msgb.h>
#include <osmocom/gsm/gsup.h>
struct msc_a;
struct mgsb;
struct gsup_client_mux;
struct osmo_gsup_message;
int gsm0911_rcv_nc_ss(struct ran_conn *conn, struct msgb *msg);
int gsm0911_gsup_handler(struct vlr_subscr *vsub, struct osmo_gsup_message *gsup);
int gsm0911_rcv_nc_ss(struct msc_a *msc_a, struct msgb *msg);
int gsm0911_gsup_rx(struct gsup_client_mux *gcm, void *data, const struct osmo_gsup_message *msg);

@ -16,23 +16,17 @@
#include <osmocom/mgcp_client/mgcp_client.h>
#include <osmocom/msc/msc_common.h>
#include <osmocom/msc/neighbor_ident.h>
#include "gsm_data_shared.h"
/* TS 48.008 DLCI containing DCCH/ACCH + SAPI */
#define OMSC_LINKID_CB(__msgb) (__msgb)->cb[3]
#include "../../bscconfig.h"
#if BUILD_IU
#include <osmocom/ranap/iu_client.h>
#endif
/** annotations for msgb ownership */
#define __uses
struct mncc_sock_state;
struct vlr_instance;
struct vlr_subscr;
struct gsup_client_mux;
#define tmsi_from_string(str) strtoul(str, NULL, 10)
@ -144,6 +138,7 @@ struct gsm_network {
struct mncc_sock_state *mncc_state;
mncc_recv_cb_t mncc_recv;
struct llist_head upqueue;
struct osmo_tdef *mncc_tdefs;
/*
* TODO: Move the trans_list into the RAN connection and
* create a pending list for MT transactions. These exist before
@ -171,9 +166,6 @@ struct gsm_network {
/* control interface */
struct ctrl_handle *ctrl;
/* all active RAN connections. */
struct llist_head ran_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
@ -184,6 +176,7 @@ struct gsm_network {
/* MSC: GSUP server address of the HLR */
const char *gsup_server_addr_str;
uint16_t gsup_server_port;
struct gsup_client_mux *gcm;
struct vlr_instance *vlr;
@ -196,28 +189,30 @@ struct gsm_network {
int ncss_guard_timeout;
struct {
struct osmo_tdef *tdefs;
struct mgcp_client_conf conf;
struct mgcp_client *client;
} mgw;
#if BUILD_IU
struct {
/* CS7 instance id number (set via VTY) */
uint32_t cs7_instance;
enum ranap_nsap_addr_enc rab_assign_addr_enc;
struct osmo_sccp_instance *sccp;
enum nsap_addr_enc rab_assign_addr_enc;
struct sccp_ran_inst *sri;
} iu;
#endif
struct {
/* CS7 instance id number (set via VTY) */
uint32_t cs7_instance;
/* A list with the context information about
* all BSCs we have connections with */
struct llist_head bscs;
struct osmo_sccp_instance *sccp;
struct sccp_ran_inst *sri;
} a;
/* A list of neighbor BSCs. This list is defined statically via VTY and does not
* necessarily correspond to BSCs attached to the A interface at a given moment. */
struct neighbor_ident_list *neighbor_list;
struct {
/* MSISDN to which to route MO emergency calls */
char *route_to_msisdn;
@ -228,6 +223,14 @@ struct gsm_network {
* If no name is set, the IPA Serial Number will be the same as the Unit Name,
* and will be of the form 'MSC-00-00-00-00-00-00' */
char *msc_ipa_name;
struct llist_head neighbor_ident_list;
struct {
uint64_t range_start;
uint64_t range_end;
uint64_t next;
} handover_number;
};
struct osmo_esme;

@ -31,10 +31,4 @@ enum gsm_hooks {
GSM_HOOK_RR_SECURITY,
};
enum gsm_paging_event {
GSM_PAGING_SUCCEEDED,
GSM_PAGING_EXPIRED,
GSM_PAGING_BUSY,
};
#endif

@ -12,40 +12,4 @@
struct ran_conn;
struct msgb;
typedef int gsm_cbfn(unsigned int hooknum, unsigned int event, struct msgb *msg,
void *data, void *param);
/*
* 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;
/* human readable label to be able to log pending request kinds */
const char *label;
/* the callback data */
gsm_cbfn *cbfn;
void *param;
};
/*
* Paging handling with authentication
*/
struct subscr_request *subscr_request_conn(struct vlr_subscr *vsub,
gsm_cbfn *cbfn, void *param,
const char *label,
enum sgsap_service_ind serv_ind);
void subscr_remove_request(struct subscr_request *req);
void subscr_paging_cancel(struct vlr_subscr *vsub, enum gsm_paging_event event);
int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
struct msgb *msg, void *data, void *param);
/* Find an allocated channel for a specified subscriber */
struct ran_conn *connection_for_subscr(struct vlr_subscr *vsub);
#endif /* _GSM_SUBSCR_H */

@ -0,0 +1,34 @@
#pragma once
#include <osmocom/gsm/gsup.h>
#include <osmocom/msc/gsup_client_mux.h>
struct gsup_client_mux;
struct ipaccess_unit;
struct gsup_client_mux_rx_cb {
int (* func )(struct gsup_client_mux *gcm, void *data, const struct osmo_gsup_message *gsup_msg);
void *data;
};
/* A GSUP client shared between code paths for various GSUP Message Classes.
* The main task is to dispatch GSUP messages to code paths corresponding to the respective Message Class, i.e.
* subscriber management, SMS, SS/USSD and inter-MSC messaging.
* If a GSUP Message Class IE is present in the message, the received message is dispatched directly to the rx_cb entry
* for that Message Class. Otherwise, the Message Class is determined by a switch() on the Message Type.*/
struct gsup_client_mux {
struct osmo_gsup_client *gsup_client;
/* Target clients by enum osmo_gsup_message_class */
struct gsup_client_mux_rx_cb rx_cb[OSMO_GSUP_MESSAGE_CLASS_ARRAYSIZE];
};
struct gsup_client_mux *gsup_client_mux_alloc(void *talloc_ctx);
int gsup_client_mux_start(struct gsup_client_mux *gcm, const char *gsup_server_addr_str, uint16_t gsup_server_port,
struct ipaccess_unit *ipa_dev);
int gsup_client_mux_tx(struct gsup_client_mux *gcm, const struct osmo_gsup_message *gsup_msg);
void gsup_client_mux_tx_error_reply(struct gsup_client_mux *gcm, const struct osmo_gsup_message *gsup_orig,
enum gsm48_gmm_cause cause);
int gsup_client_mux_rx(struct osmo_gsup_client *gsup_client, struct msgb *msg);

@ -1,50 +0,0 @@
/* Trivial switch-off of external Iu dependencies,
* allowing to run full unit tests even when built without Iu support. */
/*
* (C) 2016,2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
*
* Author: Neels Hofmeyr <nhofmeyr@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 <stdint.h>
#include <stdbool.h>
#include <osmocom/core/linuxlist.h>
struct msgb;
struct RANAP_Cause;
struct osmo_auth_vector;
struct ranap_ue_conn_ctx {
struct llist_head list;
uint32_t conn_id;
};
int ranap_iu_tx(struct msgb *msg, uint8_t sapi);
int ranap_iu_tx_sec_mode_cmd(struct ranap_ue_conn_ctx *uectx, struct osmo_auth_vector *vec,
int send_ck);
int ranap_iu_page_cs(const char *imsi, const uint32_t *tmsi, uint16_t lac);
int ranap_iu_page_ps(const char *imsi, const uint32_t *ptmsi, uint16_t lac, uint8_t rac);
struct msgb *ranap_new_msg_rab_assign_voice(uint8_t rab_id, uint32_t rtp_ip,
uint16_t rtp_port,
bool use_x213_nsap);
int ranap_iu_rab_act(struct ranap_ue_conn_ctx *ue_ctx, struct msgb *msg);
int ranap_iu_tx_common_id(struct ranap_ue_conn_ctx *uectx, const char *imsi);
int ranap_iu_tx_release(struct ranap_ue_conn_ctx *ctx, const struct RANAP_Cause *cause);

@ -1,14 +0,0 @@
#pragma once
#include <osmocom/msc/transaction.h>
struct ranap_ue_conn_ctx;
int gsm0408_rcvmsg_iucs(struct gsm_network *network, struct msgb *msg,
uint16_t *lac);
struct ran_conn *ran_conn_lookup_iu(struct gsm_network *network,
struct ranap_ue_conn_ctx *ue);
int iu_rab_act_cs(struct gsm_trans *trans);
uint32_t iu_get_conn_id(const struct ranap_ue_conn_ctx *ue);

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

@ -1,4 +1,4 @@
/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface
/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface
* 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
@ -31,6 +31,7 @@
struct gsm_network;
struct msgb;
struct gsm0808_channel_type;
/* One end of a call */
@ -196,6 +197,15 @@ struct gsm_mncc_bridge {
uint32_t callref[2];
};
union mncc_msg {
uint32_t msg_type;
struct gsm_mncc signal;
struct gsm_mncc_hello hello;
struct gsm_data_frame data_frame;
struct gsm_mncc_rtp rtp;
struct gsm_mncc_bridge bridge;
};
const char *get_mncc_name(int value);
void mncc_set_cause(struct gsm_mncc *data, int loc, int val);
void cc_tx_to_mncc(struct gsm_network *net, struct msgb *msg);
@ -217,4 +227,6 @@ int mncc_sock_init(struct gsm_network *net, const char *sock_path);
int mncc_prim_check(const struct gsm_mncc *mncc_prim, unsigned int len);
int mncc_bearer_cap_to_channel_type(struct gsm0808_channel_type *ct, const struct gsm_mncc_bearer_cap *bc);
#endif

@ -0,0 +1,140 @@
/* Handle an MNCC managed call (external MNCC). */
/*
* (C) 2019 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* SPDX-License-Identifier: AGPL-3.0+
*
* Author: Neels Hofmeyr
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <osmocom/msc/mncc.h>
#include <osmocom/msc/mncc_call.h>
struct osmo_fsm_inst;
struct rtp_stream;
#define LOG_MNCC_CALL(MNCC, LEVEL, FMT, ARGS...) \
LOGPFSML((MNCC) ? (MNCC)->fi : NULL, LEVEL, FMT, ##ARGS)
enum mncc_call_fsm_event {
/* An MNCC message was received from the MNCC socket. The data argument is a const union mncc_msg* pointing at
* the message contents. */
MNCC_CALL_EV_RX_MNCC_MSG,
/* The user has invoked mncc_call_outgoing_start(); this event exists to ensure that the FSM is in a state that
* allows starting a new outgoing call. */
MNCC_CALL_EV_OUTGOING_START,
/* The MNCC server has sent an MNCC_ALERT_REQ. */
MNCC_CALL_EV_OUTGOING_ALERTING,
/* The MNCC server has confirmed call setup with an MNCC_SETUP_RSP, we have sent an MNCC_SETUP_COMPL_IND. */
MNCC_CALL_EV_OUTGOING_SETUP_COMPLETE,
/* The user has invoked mncc_call_incoming_start(); this event exists to ensure that the FSM is in a state that
* allows starting a new incoming call. */
MNCC_CALL_EV_INCOMING_START,
/* MNCC server sent an MNCC_SETUP_REQ */
MNCC_CALL_EV_INCOMING_SETUP,
/* MNCC server confirmed call setup with an MNCC_SETUP_COMPL_REQ */
MNCC_CALL_EV_INCOMING_SETUP_COMPLETE,
/* MNCC server requests call release (Rx MNCC_DISC_REQ) */
MNCC_CALL_EV_CN_RELEASE,
/* osmo-msc should request call release (Tx MNCC_DISC_IND) */
MNCC_CALL_EV_MS_RELEASE,
};
/* The typical progression of outgoing and incoming calls via MNCC is shown by doc/sequence_charts/mncc_call_fsm.msc */
enum mncc_call_fsm_state {
MNCC_CALL_ST_NOT_STARTED = 0,
MNCC_CALL_ST_OUTGOING_WAIT_PROCEEDING,
MNCC_CALL_ST_OUTGOING_WAIT_COMPLETE,
MNCC_CALL_ST_INCOMING_WAIT_COMPLETE,
MNCC_CALL_ST_TALKING,
MNCC_CALL_ST_WAIT_RELEASE_ACK,
};
struct mncc_call_incoming_req {
bool bearer_cap_present;
struct gsm_mncc_bearer_cap bearer_cap;
bool cccap_present;
struct gsm_mncc_cccap cccap;
struct gsm_mncc setup_req_msg;
};
struct mncc_call;
typedef void (* mncc_call_message_cb_t )(struct mncc_call *mncc_call, const union mncc_msg *mncc_msg, void *data);
struct mncc_call {
struct llist_head entry;
struct osmo_fsm_inst *fi;
struct vlr_subscr *vsub;
struct gsm_network *net;
/* Details originally passed to mncc_call_outgoing_start(), if any. */
struct gsm_mncc outgoing_req;
uint32_t callref;
bool remote_msisdn_present;
struct gsm_mncc_number remote_msisdn;
bool local_msisdn_present;
struct gsm_mncc_number local_msisdn;
struct rtp_stream *rtps;
bool received_rtp_create;
mncc_call_message_cb_t message_cb;
void *forward_cb_data;
/* Event to dispatch to the FSM inst parent when the call is complete. Omit event dispatch when negative. See
* mncc_call_alloc()'s arg of same name. */
int parent_event_call_setup_complete;
};
void mncc_call_fsm_init(struct gsm_network *net);
struct mncc_call *mncc_call_alloc(struct vlr_subscr *vsub,
struct osmo_fsm_inst *parent,
int parent_event_call_setup_complete,
uint32_t parent_event_call_released,
mncc_call_message_cb_t message_cb, void *forward_cb_data);
void mncc_call_reparent(struct mncc_call *mncc_call,
struct osmo_fsm_inst *new_parent,
int parent_event_call_setup_complete,
uint32_t parent_event_call_released,
mncc_call_message_cb_t message_cb, void *forward_cb_data);
int mncc_call_outgoing_start(struct mncc_call *mncc_call, const struct gsm_mncc *outgoing_req);
int mncc_call_incoming_start(struct mncc_call *mncc_call, const struct mncc_call_incoming_req *incoming_req);
int mncc_call_incoming_tx_setup_cnf(struct mncc_call *mncc_call, const struct gsm_mncc_number *connected_number);
int mncc_call_set_rtp_stream(struct mncc_call *mncc_call, struct rtp_stream *rtps);
void mncc_call_detach_rtp_stream(struct mncc_call *mncc_call);
void mncc_call_rx(struct mncc_call *mncc_call, const union mncc_msg *mncc_msg);
int mncc_call_tx(struct mncc_call *mncc_call, union mncc_msg *mncc_msg);
int mncc_call_tx_msgt(struct mncc_call *mncc_call, uint32_t msg_type);
struct mncc_call *mncc_call_find_by_callref(uint32_t callref);
void mncc_call_release(struct mncc_call *mncc_call);

@ -0,0 +1,215 @@
/* MSC-A role: main subscriber management */
/*
* (C) 2019 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
* All Rights Reserved
*
* SPDX-License-Identifier: AGPL-3.0+
*
* Author: Neels Hofmeyr
*
* 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,