Osmocom Mobile Switching Centre
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

241 lines
7.6 KiB

#pragma once
/* MSC RAN connection implementation */
#include <stdint.h>
#include <osmocom/gsm/protocol/gsm_04_08.h>
#include <osmocom/sigtran/sccp_sap.h>
#include <osmocom/mgcp_client/mgcp_client.h>
#include <osmocom/gsm/gsm_utils.h>
#define LOG_RAN_CONN(conn, level, fmt, args ...) \
LOG_RAN_CONN_CAT(conn, (conn) ? (conn)->log_subsys : DMSC, level, fmt, ## args)
#define LOG_RAN_CONN_CAT(conn, subsys, level, fmt, args ...) \
LOGPFSMSL((conn)? (conn)->fi : NULL, subsys, level, fmt, ## args)
#define VSUB_USE_CONN "conn"
enum ran_conn_fsm_event {
/* Accepted the initial Complete Layer 3 (starting to evaluate Authentication and Ciphering) */
/* Received Classmark Update, typically neede for Ciphering Mode Command */
/* LU or Process Access FSM has determined that this conn is good */
/* received first reply from MS in "real" CC, SMS, USSD communication */
/* Some async action has completed, check again whether all is done */
/* MS/BTS/BSC originated close request */
/* MSC originated close request, e.g. failed authentication */
/* The usage count for the conn has reached zero */
enum ran_conn_fsm_state {
enum integrity_protection_state {
enum complete_layer3_type {
#define MAX_A5_KEY_LEN (128/8)
struct geran_encr {
uint8_t alg_id;
uint8_t key_len;
uint8_t key[MAX_A5_KEY_LEN];
extern const struct value_string complete_layer3_type_names[];
static inline const char *complete_layer3_type_name(enum complete_layer3_type val)
return get_value_string(complete_layer3_type_names, val);
struct gsm_classmark {
bool classmark1_set;
struct gsm48_classmark1 classmark1;
uint8_t classmark2_len;
uint8_t classmark2[3];
uint8_t classmark3_len;
uint8_t classmark3[14]; /* if cm3 gets extended by spec, it will be truncated */
/* active radio connection of a mobile subscriber */
struct ran_conn {
/* global linked list of ran_conn instances */
struct llist_head entry;
/* FSM instance to control the RAN connection's permissions and lifetime. */
struct osmo_fsm_inst *fi;
enum complete_layer3_type complete_layer3_type;
/* usage count. If this drops to zero, we start the release
* towards A/Iu */
uint32_t use_count;
uint32_t use_tokens;
/* The MS has opened the conn with a CM Service Request, and we shall
* keep it open for an actual request (or until timeout). */
bool received_cm_service_request;
/* libmsc/libvlr subscriber information (if available) */
struct vlr_subscr *vsub;
/* LU expiration handling */
uint8_t expire_timer_stopped;
/* Are we part of a special "silent" call */
int silent_call;
/* back pointers */
struct gsm_network *network;
/* connected via 2G or 3G? */
enum osmo_rat_type via_ran;
/* whether to log on DBSSAP, DIUCS, ... */
int log_subsys;
uint16_t lac;
struct geran_encr geran_encr;
/* "Temporary" storage for the case the VLR asked for Cipher Mode Command, but the MSC still
* wants to request a Classmark Update first. */
struct {
bool umts_aka;
bool retrieve_imeisv;
} geran_set_cipher_mode;
/* N(SD) expected in the received frame, per flow (TS 24.007 */
uint8_t n_sd_next[4];
struct {
struct mgcp_ctx *mgcp_ctx;
unsigned int mgcp_rtp_endpoint;
uint16_t local_port_ran;
char local_addr_ran[INET_ADDRSTRLEN];
uint16_t remote_port_ran;
char remote_addr_ran[INET_ADDRSTRLEN];
enum mgcp_codecs codec_ran;
uint16_t local_port_cn;
char local_addr_cn[INET_ADDRSTRLEN];
uint16_t remote_port_cn;
char remote_addr_cn[INET_ADDRSTRLEN];
enum mgcp_codecs codec_cn;
} rtp;
/* which Iu-CS connection, if any. */
struct {
struct ranap_ue_conn_ctx *ue_ctx;
uint8_t rab_id;
bool waiting_for_release_complete;
} iu;
struct {
/* A pointer to the SCCP user that handles
* the SCCP connections for this subscriber
* connection */
struct osmo_sccp_user *scu;
/* The address of the BSC that is associated
* with this RAN connection */
struct osmo_sccp_addr bsc_addr;
/* The connection identifier that is used
* to reference the SCCP connection that is
* associated with this RAN connection */
uint32_t conn_id;
bool waiting_for_clear_complete;
} a;
/* Temporary storage for Classmark Information for times when a connection has no VLR subscriber
* associated yet. It will get copied to the VLR subscriber upon msc_vlr_subscr_assoc(). */
struct gsm_classmark temporary_classmark;
struct ran_conn *ran_conn_alloc(struct gsm_network *network, enum osmo_rat_type via_ran, uint16_t lac);
refactor log ctx for vlr_subscr and ran_conn ran_conn_get_conn_id(): instead of a talloc allocated string, return a static buffer in ran_conn_get_conn_id(). So far this function had no callers. Refactor ran_conn_update_id() API: during early L3-Complete, when no subscriber is associated yet, update the FSM Id by the MI type seen in the L3 Complete message: ran_conn_update_id_from_mi(). Later on set the vsub and re-update. Call vlr.ops->subscr_update when the TMSI is updated, so that log context includes the TMSI from then on. Enrich context for vlr_subscr_name and ran_conn fi name. Include all available information in vlr_subscr_name(); instead of either IMSI or MSISDN or TMSI, print all of them when present. Instead of a short log, rather have more valuable context. A context info would now look like: Process_Access_Request_VLR(IMSI-901700000014706:MSISDN-2023:TMSI-0x08BDE4EC:GERAN-A-3:PAGING_RESP) It does get quite long, but ensures easy correlation of any BSSAP / IuCS messages with log output, especially if multiple subscribers are busy at the same time. Print TMSI and TMSInew in uppercase hexadecimal, which is the typical representation in the telecom world. When showing the RAN conn id GERAN_A-00000017 becomes GERAN-A-23 - We usually write the conn_id in decimal. - Leading zeros are clutter and might suggest hexadecimal format. - 'GERAN-A' and 'UTRAN-Iu' are the strings defined by osmo_rat_type_name(). Depends: I7798c3ef983c2e333b2b9cbffef6f366f370bd81 (libosmocore) Depends: Ica25919758ef6cba8348da199b0ae7e0ba628798 (libosmocore) Change-Id: I66a68ce2eb8957a35855a3743d91a86299900834
4 years ago
void ran_conn_update_id_from_mi(struct ran_conn *conn, const uint8_t *mi, uint8_t mi_len);
void ran_conn_update_id(struct ran_conn *conn);
const char *ran_conn_get_conn_id(struct ran_conn *conn);
void ran_conn_update_id_for_vsub(struct vlr_subscr *for_vsub);
void ran_conn_complete_layer_3(struct ran_conn *conn);
void ran_conn_sapi_n_reject(struct ran_conn *conn, int dlci);
int ran_conn_clear_request(struct ran_conn *conn, uint32_t cause);
void ran_conn_compl_l3(struct ran_conn *conn,
struct msgb *msg, uint16_t chosen_channel);
void ran_conn_dtap(struct ran_conn *conn, struct msgb *msg);
int ran_conn_classmark_request_then_cipher_mode_cmd(struct ran_conn *conn, bool umts_aka,
bool retrieve_imeisv);
int ran_conn_geran_set_cipher_mode(struct ran_conn *conn, bool umts_aka, bool retrieve_imeisv);
void ran_conn_cipher_mode_compl(struct ran_conn *conn, struct msgb *msg, uint8_t alg_id);
void ran_conn_rx_sec_mode_compl(struct ran_conn *conn);
void ran_conn_classmark_chg(struct ran_conn *conn,
const uint8_t *cm2, uint8_t cm2_len,
const uint8_t *cm3, uint8_t cm3_len);
void ran_conn_assign_fail(struct ran_conn *conn, uint8_t cause, uint8_t *rr_cause);
void ran_conn_init(void);
bool ran_conn_is_accepted(const struct ran_conn *conn);
bool ran_conn_is_establishing_auth_ciph(const struct ran_conn *conn);
void ran_conn_communicating(struct ran_conn *conn);
void ran_conn_close(struct ran_conn *conn, uint32_t cause);
void ran_conn_mo_close(struct ran_conn *conn, uint32_t cause);
bool ran_conn_in_release(struct ran_conn *conn);
void ran_conn_rx_bssmap_clear_complete(struct ran_conn *conn);
void ran_conn_rx_iu_release_complete(struct ran_conn *conn);
void ran_conn_sgs_release_sent(struct ran_conn *conn);
enum ran_conn_use {
extern const struct value_string ran_conn_use_names[];
static inline const char *ran_conn_use_name(enum ran_conn_use val)
{ return get_value_string(ran_conn_use_names, val); }
#define ran_conn_get(conn, balance_token) \
_ran_conn_get(conn, balance_token, __FILE__, __LINE__)
#define ran_conn_put(conn, balance_token) \
_ran_conn_put(conn, balance_token, __FILE__, __LINE__)
struct ran_conn * _ran_conn_get(struct ran_conn *conn, enum ran_conn_use balance_token,
const char *file, int line);
void _ran_conn_put(struct ran_conn *conn, enum ran_conn_use balance_token,
const char *file, int line);
bool ran_conn_used_by(struct ran_conn *conn, enum ran_conn_use token);