blob: f190d91e3291d9ebfb65eec31d23d5ed55972264 [file] [log] [blame]
Neels Hofmeyrc4628a32018-12-07 14:47:34 +01001/* The RAN (Radio Access Network) side of an A- or Iu-connection, which is closely tied to an SCCP connection.
2 * (as opposed to the NAS side.)
3 *
4 * The SCCP connection is located with the MSC-I role, while the MSC-A responsible for subscriber management may be at a
5 * remote MSC behind an E-interface connection. In that case we need to forward the L2 messages over the E-interface and
6 * the BSSAP or RANAP messages get decoded and interpreted at MSC-A.
7 *
8 * The life cycle of a DTAP message from RAN to MSC-A -- starting from the bottom left:
9 *
10 * ------------------>[ 3GPP TS 24.008 ]------------------->|
11 * ^ (Request) (Response) |
12 * | v
13 * msc_a_up_l3() msc_a_tx_dtap_to_i(dtap_msgb)
14 * ^ |
15 * | v
Neels Hofmeyrf8399672019-05-09 12:56:45 +020016 * msc_a_ran_decode_cb(struct ran_dec_msg) msc_a_ran_enc(struct ran_enc_msg)
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010017 * ^ ^ . |
18 * | -Decode NAS- | . NAS v
Neels Hofmeyrf8399672019-05-09 12:56:45 +020019 * | | . ran_infra[type]->ran_encode(struct ran_enc_msg)
20 * ran_a_decode_l2() ran_iu_decode_l2() . | |
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010021 * ^ ^ . v v
Neels Hofmeyrf8399672019-05-09 12:56:45 +020022 * | | . ran_a_encode() ran_iu_encode()
23 * ran_infra[type]->ran_dec_l2() | |
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010024 * ^ | -Encode BSSAP/RANAP- |
25 * | v v
Neels Hofmeyrf8399672019-05-09 12:56:45 +020026 * msc_a_ran_dec() msub_tx_an_apdu(from MSC_ROLE_A to MSC_ROLE_I)
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010027 * ^ |
28 * | MSC-A v
29 * . msc_a FSM . . . . . . . . . . . . . . . . msc_a FSM . . . . . . . . . .
30 * ^ |
31 * | MSC_A_EV_FROM_I_PROCESS_ACCESS_SIGNALLING_REQUEST v
32 * | data = an_apdu [possibly
33 * | via GSUP
34 * [possibly from remote MSC-A]
35 * via GSUP |
36 * to remote MSC-A] | MSC_I_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST
37 * ^ | data = an_apdu
38 * | v
39 * . msc_i FSM . . . . . . . . . . . . . . . . msc_i FSM . . . . . . . . . .
40 * ^ MSC-I |
41 * | MSC_EV_FROM_RAN_UP_L2 V
42 * | data = an_apdu msc_i_down_l2(an_apdu->msg)
43 * | |
44 * ran_peer FSM V
45 * ^ ran_conn_down_l2_co();
46 * | RAN_PEER_EV_MSG_UP_CO |
47 * | data = struct ran_peer_ev_ctx | RAN_PEER_EV_MSG_DOWN_CO
48 * | | data = struct ran_peer_ev_ctx
49 * ran_peer_up_l2() V
50 * (ran_infa->sccp_ran_ops.up_l2) ran_peer FSM
51 * ^ ^ |
52 * | | v
53 * sccp_ran_sap_up() sccp_ran_down_l2_co(conn_id, msg)
54 * ^ ^ | |
55 * | | |SCCP|
56 * |SCCP| v v
57 * | | <------------------------------------------------------
58 * BSC RNC
59 * | |
60 * BTS NodeB
61 * | |
62 * MS UE
63 *
64 * sccp_ran:
65 * - handles receiving of SCCP primitives from the SCCP layer.
66 * - extracts L2 msg
67 * - passes on L2 msg and conn_id by calling sccp_ran_ops.up_l2 == ran_peer_up_l2().
68 *
69 * On Connection-Oriented *Initial* message
70 * ========================================
71 *
72 * ran_peer_up_l2()
73 * - notices an unknown, new osmo_rat_type:conn_id and
74 * - first creates an "empty" msub with new local MSC-I and MSC-A roles;
75 * in this case always a *local* MSC-A (never remote on Initial messages).
76 * - Passes the L2 msgb containing the BSSAP or RANAP as AN-APDU
77 * in MSC_A_EV_FROM_I_COMPLETE_LAYER_3 to the MSC-A role FSM instance.
78 *
79 * MSC-A:
80 * - Receives MSC_A_EV_FROM_I_COMPLETE_LAYER_3 AN-APDU, notices an_proto indicating BSSAP or RANAP.
Neels Hofmeyrf8399672019-05-09 12:56:45 +020081 * - Passes L2 message to ran_infra[]->ran_dec_l2(), which decodes the BSSAP or RANAP.
82 * - contained information is passed to msc_a_ran_decode_cb().
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010083 * - which msc_a starts Complete-L3 and VLR procedures,
84 * - associates msub with a vlr_subscr,
85 * - sends DTAP requests back down by calling msc_a_tx_dtap_to_i() (possibly other more specialized tx functions)
Neels Hofmeyrf8399672019-05-09 12:56:45 +020086 * - according to ran_infra[]->ran_encode(), the ran_enc_msg gets encoded as BSSAP or RANAP.
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010087 * - passes as AN-APDU to MSC-I in MSC_I_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST signal.
88 *
89 * MSC-I, receiving AN-APDU from local MSC-A:
90 * - feeds L2 msgb to the ran_peer FSM as RAN_PEER_EV_MSG_DOWN_CO, passing the SCCP conn_id.
91 *
92 * sccp_ran_down_l2_co()
93 * - wraps in SCCP prim,
94 * - sends down.
95 *
96 *
97 * On (non-Initial) Connection-Oriented DTAP
98 * =========================================
99 *
100 * ran_peer_up_l2()
101 * - notices an already known conn_id by looking up a matching osmo_rat_type:ran_conn.
102 * - ran_conn already associated with an MSC-I role.
103 * - Now forwards AN-APDU like above, only using MSC_A_EV_FROM_I_PROCESS_ACCESS_SIGNALLING_REQUEST.
104 *
105 *
106 * MSC-A and MSC-I roles on separate MSC instances
107 * ===============================================
108 *
109 * After inter-MSC handover, the MSC-I and MSC-A roles can be on separate MSC instances, typically physically distant /
110 * possibly belonging to a different operator. This will never see Complete-L3.
111 * Assuming that both instances are osmo-msc, then:
112 *
113 * At MSC-B:
114 * initially, via GSUP:
115 * - receives Handover Request from remote MSC-A,
116 * - creates msub with local MSC-T role,
117 * - sets up the ran_conn with a new SCCP conn_id, and waits for the MS/UE to show up.
118 * - (fast-forward to successful Handover)
119 * - MSC-T role becomes MSC-I for the remote MSC-A.
120 *
121 * Then for DTAP from the MS:
122 *
123 * sccp_ran:
124 * - receives SCCP,
125 * - extracts L2 and passes on to ran_peer_up_l2().
126 *
127 * ran_peer_up_l2()
128 * - notices an already known conn_id by looking up a matching ran_conn.
129 * - ran_conn already associated with an MSC-I role and an msub.
130 * - forwards AN-APDU in MSC_A_EV_FROM_I_PROCESS_ACCESS_SIGNALLING_REQUEST to the MSC-A role.
131 *
132 * At MSC-B, the "MSC-A role" is a *remote* implementation,
133 * meaning there is an msc_a_remote FSM instance in MSC-B's msub:
134 *
135 * MSC-A-Remote:
136 * - msc_a_remote receives MSC_A_EV_FROM_I_PROCESS_ACCESS_SIGNALLING_REQUEST,
137 * - wraps AN-APDU in GSUP message,
138 * - sends to remote MSC-A.
139 *
140 * At MSC-A:
141 * Here, msub has a *remote* MSC-I role,
142 * meaning it is an msc_i_remote FSM instance:
143 *
144 * MSC-I-Remote:
145 * - msc_i_remote receives and decodes GSUP message,
146 * - passes AN-APDU to MSC-A FSM instance via MSC_A_EV_FROM_I_PROCESS_ACCESS_SIGNALLING_REQUEST.
147 *
148 * MSC-A role:
149 * - Receives MSC_A_EV_FROM_I_PROCESS_ACCESS_SIGNALLING_REQUEST, notices an_proto indicating BSSAP or RANAP.
Neels Hofmeyrf8399672019-05-09 12:56:45 +0200150 * - Passes L2 message to ran_infra[]->ran_dec_l2(), which decodes the BSSAP or RANAP.
151 * - contained information is passed to msc_a_ran_decode_cb().
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100152 * - sends DTAP requests back down by calling msc_a_tx_dtap_to_i() (possibly other more specialized tx functions)
Neels Hofmeyrf8399672019-05-09 12:56:45 +0200153 * - according to ran_infra[]->ran_encode(), the ran_enc_msg gets encoded as BSSAP or RANAP.
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100154 * - passes as AN-APDU to MSC-I in MSC_I_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST signal.
155 *
156 * MSC-I-Remote:
157 * - msc_i_remote wraps AN-APDU in GSUP message,
158 * - sends to MSC-B
159 *
160 * At MSC-B:
161 * MSC-A-Remote:
162 * - msc_a_remote receives GSUP message,
163 * - passes AN-APDU to msc_i in MSC_I_EV_FROM_A_FORWARD_ACCESS_SIGNALLING_REQUEST.
164 *
165 * MSC-I:
166 * - BSSAP or RANAP is indicated both by the AN-APDU an_proto, as well as the ran_conn state for that subscriber.
167 * - feeds L2 msgb to the ran_peer FSM as RAN_PEER_EV_MSG_DOWN_CO, passing the SCCP conn_id.
168 *
169 * sccp_ran_down_l2_co()
170 * - wraps in SCCP prim,
171 * - sends down.
172 *
173 */
174
175#pragma once
176
177#include <stdint.h>
178
179#include <osmocom/core/tdef.h>
180#include <osmocom/gsm/gsm_utils.h>
181#include <osmocom/gsm/gsm0808_utils.h>
182#include <osmocom/sigtran/sccp_sap.h>
183
184#include <osmocom/msc/paging.h>
185
186struct msgb;
187struct ran_infra;
188struct sccp_ran_inst;
189
190#define LOG_SCCP_RAN_CO(sri, peer_addr, conn_id, level, fmt, args...) \
191 LOGP((sri) && (sri)->ran? (sri)->ran->log_subsys : DMSC, level, "(%s-%u%s%s) " fmt, \
192 osmo_rat_type_name((sri) && (sri)->ran? (sri)->ran->type : -1), conn_id, \
193 peer_addr ? " from " : "", \
194 peer_addr ? osmo_sccp_inst_addr_name((sri)->sccp, peer_addr) : "", \
195 ## args)
196
197#define LOG_SCCP_RAN_CL_CAT(sri, peer_addr, subsys, level, fmt, args...) \
198 LOGP(subsys, level, "(%s%s%s) " fmt, \
199 osmo_rat_type_name((sri) && (sri)->ran? (sri)->ran->type : -1), \
200 peer_addr ? " from " : "", \
201 peer_addr ? osmo_sccp_inst_addr_name((sri)->sccp, peer_addr) : "", \
202 ## args)
203
204#define LOG_SCCP_RAN_CL(sri, peer_addr, level, fmt, args...) \
205 LOG_SCCP_RAN_CL_CAT(sri, peer_addr, (sri) && (sri)->ran? (sri)->ran->log_subsys : DMSC, level, fmt, ##args)
206
207#define LOG_SCCP_RAN_CAT(sri, subsys, level, fmt, args...) \
208 LOG_SCCP_RAN_CL_CAT(sri, NULL, subsys, level, fmt, ##args)
209
210#define LOG_SCCP_RAN(sri, level, fmt, args...) \
211 LOG_SCCP_RAN_CL(sri, NULL, level, fmt, ##args)
212
213extern struct osmo_tdef g_sccp_tdefs[];
214
215enum reset_msg_type {
216 SCCP_RAN_MSG_NON_RESET = 0,
217 SCCP_RAN_MSG_RESET,
218 SCCP_RAN_MSG_RESET_ACK,
219};
220
221struct sccp_ran_ops {
222 /* Implemented to receive L2 messages (e.g. BSSAP or RANAP passed to ran_peer).
223 * - ConnectionLess messages: co = false, calling_addr != NULL, conn_id == 0;
224 * - ConnectionOriented Initial messages: co = true, calling_addr != NULL;
225 * - ConnectionOriented non-Initial messages: co = true, calling_addr == NULL;
226 */
227 int (* up_l2 )(struct sccp_ran_inst *sri, const struct osmo_sccp_addr *calling_addr, bool co, uint32_t conn_id,
228 struct msgb *l2);
229
230 /* Implemented to finally remove a connection state. Last event in a connection-oriented exchange. If the
231 * N-DISCONNECT contained l2 data, it was dispatched via up_l2() before this is called. */
232 void (* disconnect )(struct sccp_ran_inst *sri, uint32_t conn_id);
233
234 /* Return whether the given l2_cl message is a RESET, RESET ACKNOWLEDGE, or RESET-unrelated message.
235 * This callback is stored in struct sccp_ran_inst to provide RESET handling to the caller (ran_peer),
236 * it is not used in sccp_ran.c. */
237 enum reset_msg_type (* is_reset_msg )(const struct sccp_ran_inst *sri, const struct msgb *l2_cl);
238
239 /* Return a RESET or RESET ACK message for this RAN type.
240 * This callback is stored in struct sccp_ran_inst to provide RESET handling to the caller (ran_peer),
241 * it is not used in sccp_ran.c. */
242 struct msgb* (* make_reset_msg )(const struct sccp_ran_inst *sri, enum reset_msg_type);
243
244 /* Return a PAGING message towards the given Cell Identifier, to page for the given TMSI or IMSI.
245 * Page for TMSI if TMSI != GSM_RESERVED_TMSI, otherwise page for IMSI. */
246 struct msgb* (* make_paging_msg )(const struct sccp_ran_inst *sri, const struct gsm0808_cell_id *page_cell_id,
247 const char *imsi, uint32_t tmsi, enum paging_cause cause);
248
249 /* Return a human printable name for the msgb */
250 const char* (* msg_name )(const struct sccp_ran_inst *sri, const struct msgb *l2);
251};
252
253struct sccp_ran_inst {
254 struct ran_infra *ran;
255
256 struct osmo_sccp_instance *sccp;
257 struct osmo_sccp_user *scu;
258 struct osmo_sccp_addr local_sccp_addr;
259
260 struct llist_head ran_peers;
261 struct llist_head ran_conns;
262
263 void *user_data;
264
265 /* Compatibility with legacy osmo-hnbgw that was unable to properly handle RESET messages. Set to 'false' to
266 * require proper RESET procedures, set to 'true' to implicitly put a ran_peer in RAN_PEER_ST_READY upon the
267 * first CO message. Default is false = be strict. */
268 bool ignore_missing_reset;
269};
270
271struct sccp_ran_inst *sccp_ran_init(void *talloc_ctx, struct osmo_sccp_instance *sccp, enum osmo_sccp_ssn ssn,
272 const char *sccp_user_name, struct ran_infra *ran, void *user_data);
273
274int sccp_ran_down_l2_co_initial(struct sccp_ran_inst *sri,
275 const struct osmo_sccp_addr *called_addr,
276 uint32_t conn_id, struct msgb *l2);
277int sccp_ran_down_l2_co(struct sccp_ran_inst *sri, uint32_t conn_id, struct msgb *l2);
278int sccp_ran_down_l2_cl(struct sccp_ran_inst *sri, const struct osmo_sccp_addr *called_addr, struct msgb *l2);
279
280int sccp_ran_disconnect(struct sccp_ran_inst *ran, uint32_t conn_id, uint32_t cause);