Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 1 | /* 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 Hofmeyr | f839967 | 2019-05-09 12:56:45 +0200 | [diff] [blame^] | 16 | * msc_a_ran_decode_cb(struct ran_dec_msg) msc_a_ran_enc(struct ran_enc_msg) |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 17 | * ^ ^ . | |
| 18 | * | -Decode NAS- | . NAS v |
Neels Hofmeyr | f839967 | 2019-05-09 12:56:45 +0200 | [diff] [blame^] | 19 | * | | . ran_infra[type]->ran_encode(struct ran_enc_msg) |
| 20 | * ran_a_decode_l2() ran_iu_decode_l2() . | | |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 21 | * ^ ^ . v v |
Neels Hofmeyr | f839967 | 2019-05-09 12:56:45 +0200 | [diff] [blame^] | 22 | * | | . ran_a_encode() ran_iu_encode() |
| 23 | * ran_infra[type]->ran_dec_l2() | | |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 24 | * ^ | -Encode BSSAP/RANAP- | |
| 25 | * | v v |
Neels Hofmeyr | f839967 | 2019-05-09 12:56:45 +0200 | [diff] [blame^] | 26 | * msc_a_ran_dec() msub_tx_an_apdu(from MSC_ROLE_A to MSC_ROLE_I) |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 27 | * ^ | |
| 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 Hofmeyr | f839967 | 2019-05-09 12:56:45 +0200 | [diff] [blame^] | 81 | * - 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 Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 83 | * - 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 Hofmeyr | f839967 | 2019-05-09 12:56:45 +0200 | [diff] [blame^] | 86 | * - according to ran_infra[]->ran_encode(), the ran_enc_msg gets encoded as BSSAP or RANAP. |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 87 | * - 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 Hofmeyr | f839967 | 2019-05-09 12:56:45 +0200 | [diff] [blame^] | 150 | * - 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 Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 152 | * - sends DTAP requests back down by calling msc_a_tx_dtap_to_i() (possibly other more specialized tx functions) |
Neels Hofmeyr | f839967 | 2019-05-09 12:56:45 +0200 | [diff] [blame^] | 153 | * - according to ran_infra[]->ran_encode(), the ran_enc_msg gets encoded as BSSAP or RANAP. |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 154 | * - 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 | |
| 186 | struct msgb; |
| 187 | struct ran_infra; |
| 188 | struct 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 | |
| 213 | extern struct osmo_tdef g_sccp_tdefs[]; |
| 214 | |
| 215 | enum reset_msg_type { |
| 216 | SCCP_RAN_MSG_NON_RESET = 0, |
| 217 | SCCP_RAN_MSG_RESET, |
| 218 | SCCP_RAN_MSG_RESET_ACK, |
| 219 | }; |
| 220 | |
| 221 | struct 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 | |
| 253 | struct 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 | |
| 271 | struct 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 | |
| 274 | int 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); |
| 277 | int sccp_ran_down_l2_co(struct sccp_ran_inst *sri, uint32_t conn_id, struct msgb *l2); |
| 278 | int sccp_ran_down_l2_cl(struct sccp_ran_inst *sri, const struct osmo_sccp_addr *called_addr, struct msgb *l2); |
| 279 | |
| 280 | int sccp_ran_disconnect(struct sccp_ran_inst *ran, uint32_t conn_id, uint32_t cause); |