aboutsummaryrefslogtreecommitdiffstats
path: root/include/osmocom/msc/ran_msg.h
blob: 5fdb90cdaff9c10271991ea7115c7041e73c6806 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
/* API to forward upcoming NAS events, e.g. from BSSAP and RANAP, to be handled by MSC-A or MSC-I. */
/*
 * (C) 2019 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
 *
 * Author: Neels Hofmeyr <neels@hofmeyr.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/>.
 */
#pragma once

#include <osmocom/core/utils.h>
#include <osmocom/core/fsm.h>
#include <osmocom/core/sockaddr_str.h>
#include <osmocom/gsm/protocol/gsm_08_08.h>
#include <osmocom/mgcp_client/mgcp_client.h>

#include <osmocom/msc/msc_common.h>

struct msgb;
struct osmo_fsm_inst;

#define LOG_RAN_DEC(NAS_DEC, subsys, level, fmt, args...) \
	LOGPFSMSL((NAS_DEC)? (NAS_DEC)->caller_fi : NULL, subsys, level, "RAN decode: " fmt, ## args)

#define LOG_RAN_ENC(FI, subsys, level, fmt, args...) \
	LOGPFSMSL(FI, subsys, level, "RAN encode: " fmt, ## args)

/* These message types are named after the BSSAP procedures in nas_a.h; most are also used for RANAP procedures of
 * similar meaning in nas_iu.h. */
enum ran_msg_type {
	RAN_MSG_NONE = 0,
	RAN_MSG_COMPL_L3,
	RAN_MSG_DTAP,
	RAN_MSG_CLEAR_COMMAND,
	RAN_MSG_CLEAR_REQUEST,
	RAN_MSG_CLEAR_COMPLETE,
	RAN_MSG_CLASSMARK_REQUEST,
	RAN_MSG_CLASSMARK_UPDATE,
	RAN_MSG_CIPHER_MODE_COMMAND,
	RAN_MSG_CIPHER_MODE_COMPLETE,
	RAN_MSG_CIPHER_MODE_REJECT,
	RAN_MSG_COMMON_ID,
	RAN_MSG_ASSIGNMENT_COMMAND,
	RAN_MSG_ASSIGNMENT_COMPLETE,
	RAN_MSG_ASSIGNMENT_FAILURE,
	RAN_MSG_SAPI_N_REJECT,
	RAN_MSG_LCLS_STATUS,
	RAN_MSG_LCLS_BREAK_REQ,
	RAN_MSG_HANDOVER_COMMAND,
	RAN_MSG_HANDOVER_PERFORMED,
	RAN_MSG_HANDOVER_REQUIRED,
	RAN_MSG_HANDOVER_REQUIRED_REJECT,
	RAN_MSG_HANDOVER_REQUEST,
	RAN_MSG_HANDOVER_REQUEST_ACK,
	RAN_MSG_HANDOVER_DETECT,
	RAN_MSG_HANDOVER_SUCCEEDED,
	RAN_MSG_HANDOVER_COMPLETE,
	RAN_MSG_HANDOVER_FAILURE,
};

extern const struct value_string ran_msg_type_names[];
static inline const char *ran_msg_type_name(enum ran_msg_type val)
{ return get_value_string(ran_msg_type_names, val); }

struct ran_clear_command {
	enum gsm0808_cause gsm0808_cause;
	bool csfb_ind;
};

struct ran_assignment_command {
	const struct osmo_sockaddr_str *cn_rtp;
	const struct gsm0808_channel_type *channel_type;
	enum nsap_addr_enc rab_assign_addr_enc;
	bool osmux_present;
	uint8_t osmux_cid;
	bool call_id_present;
	uint32_t call_id;
	struct osmo_lcls *lcls;
};

struct ran_cipher_mode_command {
	const struct osmo_auth_vector *vec;
	const struct osmo_gsm48_classmark *classmark;
	struct {
		bool umts_aka;
		bool retrieve_imeisv;
		uint8_t a5_encryption_mask;

		/* out-argument to return the key to the caller, pass NULL if not needed. */
		struct geran_encr *chosen_key;
	} geran;
};

struct ran_handover_request {
	const char *imsi;
	const struct osmo_gsm48_classmark *classmark;
	/* A Handover Request on GERAN-A sends separate IEs for
	 * - permitted algorithms, here composed from the a5_encryption_mask,
	 * - the key, here taken from chosen_encryption->key iff chosen_encryption is present,
	 * - the actually chosen algorithm ("Serving"), here taken from chosen_encryption->alg_id.
	 */
	struct {
		struct gsm0808_channel_type *channel_type;
		uint8_t a5_encryption_mask;
		/*! chosen_encryption->alg_id is in encoded format:
		 * alg_id == 1 means A5/0 i.e. no encryption, alg_id == 4 means A5/3.
		 * alg_id == 0 means no such IE was present. */
		struct geran_encr *chosen_encryption;
	} geran;
	struct gsm0808_cell_id cell_id_serving;
	struct gsm0808_cell_id cell_id_target;

	enum gsm0808_cause bssap_cause;

	bool current_channel_type_1_present;
	uint8_t current_channel_type_1;

	enum gsm0808_permitted_speech speech_version_used;

	const uint8_t *old_bss_to_new_bss_info_raw;
	uint8_t old_bss_to_new_bss_info_raw_len;

	struct osmo_sockaddr_str *rtp_ran_local;

	struct gsm0808_speech_codec_list *codec_list_msc_preferred;

	bool call_id_present;
	uint32_t call_id;

	const uint8_t *global_call_reference;
	uint8_t global_call_reference_len;
};

struct ran_handover_request_ack {
	const uint8_t *rr_ho_command;
	uint8_t rr_ho_command_len;
	bool chosen_channel_present;
	uint8_t chosen_channel;
	/*! chosen_encr_alg is in encoded format:
	 * chosen_encr_alg == 1 means A5/0 i.e. no encryption, chosen_encr_alg == 4 means A5/3.
	 * chosen_encr_alg == 0 means no such IE was present. */
	uint8_t chosen_encr_alg;

	/* chosen_speech_version == 0 means "not present" */
	enum gsm0808_permitted_speech chosen_speech_version;

	struct osmo_sockaddr_str remote_rtp;
	bool codec_present;
	enum mgcp_codecs codec;
};

struct ran_handover_command {
	const uint8_t *rr_ho_command;
	uint8_t rr_ho_command_len;

	const uint8_t *new_bss_to_old_bss_info_raw;
	uint8_t new_bss_to_old_bss_info_raw_len;
};

struct ran_handover_required {
	uint16_t cause;
	struct gsm0808_cell_id_list2 cil;

	bool current_channel_type_1_present;
	/*! See gsm0808_chosen_channel() */
	uint8_t current_channel_type_1;

	enum gsm0808_permitted_speech speech_version_used;

	uint8_t *old_bss_to_new_bss_info_raw;
	size_t old_bss_to_new_bss_info_raw_len;
};

struct ran_msg {
	enum ran_msg_type msg_type;

	/* Since different RAN implementations feed these messages, they should place here an implementation specific
	 * string constant to name the actual message (e.g. "BSSMAP Assignment Complete" vs. "RANAP RAB Assignment
	 * Response") */
	const char *msg_name;

	union {
		struct {
			const struct gsm0808_cell_id *cell_id;
			const struct gsm0808_speech_codec_list *codec_list_bss_supported;
			struct msgb *msg;
		} compl_l3;
		struct msgb *dtap;
		struct {
			enum gsm0808_cause bssap_cause;
#define RAN_MSG_BSSAP_CAUSE_UNSET 0xffff
		} clear_request;
		struct ran_clear_command clear_command;
		struct {
			const struct osmo_gsm48_classmark *classmark;
		} classmark_update;
		struct ran_cipher_mode_command cipher_mode_command;
		struct {
			/*! alg_id is in encoded format:
			 * alg_id == 1 means A5/0 i.e. no encryption, alg_id == 4 means A5/3.
			 * alg_id == 0 means no such IE was present. */
			uint8_t alg_id;
			const char *imeisv;
			const struct tlv_p_entry *l3_msg;
		} cipher_mode_complete;
		struct {
			enum gsm0808_cause bssap_cause;
		} cipher_mode_reject;
		struct {
			const char *imsi;
		} common_id;
		struct {
			enum gsm48_reject_value cause;
		} cm_service_reject;
		struct ran_assignment_command assignment_command;
		struct {
			struct osmo_sockaddr_str remote_rtp;
			bool codec_present;
			enum mgcp_codecs codec;
			const struct gsm0808_speech_codec_list *codec_list_bss_supported;
			bool osmux_present;
			uint8_t osmux_cid;
		} assignment_complete;
		struct {
			enum gsm0808_cause bssap_cause;
			uint8_t rr_cause;
			const struct gsm0808_speech_codec_list *scl_bss_supported;
		} assignment_failure;
		struct {
			enum gsm0808_cause bssap_cause;
			uint8_t dlci;
		} sapi_n_reject;
		struct {
			enum gsm0808_lcls_status status;
		} lcls_status;
		struct {
			int todo;
		} lcls_break_req;
		struct ran_handover_required handover_required;
		struct gsm0808_handover_required_reject handover_required_reject;
		struct ran_handover_command handover_command;
		struct {
			enum gsm0808_cause cause;
		} handover_failure;
		struct ran_handover_request handover_request;
		struct ran_handover_request_ack handover_request_ack;
	};
};

/* MSC-A/I/T roles implement this to receive decoded NAS messages, upon feeding an L2 msgb to a ran_dec_l2_t matching the
 * RAN type implementation. */
typedef int (* ran_decode_cb_t )(struct osmo_fsm_inst *caller_fi, void *caller_data, const struct ran_msg *msg);

struct ran_dec {
	/* caller provided osmo_fsm_inst, used both for logging from within decoding of NAS events, as well as caller's
	 * context in decode_cb(). */
	struct osmo_fsm_inst *caller_fi;
	void *caller_data;

	/* Callback receives the decoded NAS messages */
	ran_decode_cb_t decode_cb;
};

/* NAS decoders (BSSAP/RANAP) implement this to turn a msgb into a struct ran_msg.
 * An implementation typically calls ran_decoded() when done decoding.
 * NAS decoding is modeled with a callback instead of a plain decoding, because some L2 messages by design contain more
 * than one NAS event, e.g. Ciphering Mode Complete may include another L3 message for Identity Response, and LCLS
 * Information messages can contain Status and Break Req events. */
typedef int (* ran_dec_l2_t )(struct ran_dec *ran_dec, struct msgb *l2);

int ran_decoded(struct ran_dec *ran_dec, struct ran_msg *msg);

/* An MSC-A/I/T role that receives NAS events containing DTAP buffers may use this to detect DTAP duplicates as in TS
 * 24.007 11.2.3.2 Message Type Octet / Duplicate Detection */
bool ran_dec_dtap_undup_is_duplicate(struct osmo_fsm_inst *log_fi, uint8_t *n_sd_next, bool is_r99, struct msgb *l3);

/* Implemented by individual RAN implementations, see ran_a_encode() and ran_iu_encode(). */
typedef struct msgb *(* ran_encode_t )(struct osmo_fsm_inst *caller_fi, const struct ran_msg *ran_enc_msg);