Harald Welte | 9ccd662 | 2016-06-17 00:06:42 +0200 | [diff] [blame] | 1 | #pragma once |
| 2 | |
| 3 | #include <stdint.h> |
| 4 | #include <osmocom/core/linuxlist.h> |
| 5 | #include <osmocom/core/fsm.h> |
| 6 | #include <osmocom/core/logging.h> |
| 7 | #include <osmocom/gsm/protocol/gsm_23_003.h> |
| 8 | #include <osmocom/gsm/protocol/gsm_04_08_gprs.h> |
| 9 | #include <osmocom/gsm/gsm23003.h> |
| 10 | #include <openbsc/gsm_data.h> |
| 11 | // for GSM_NAME_LENGTH |
| 12 | #include <openbsc/gsm_subscriber.h> |
| 13 | |
Harald Welte | 9066b74 | 2016-06-19 18:06:02 +0200 | [diff] [blame] | 14 | struct log_target; |
| 15 | |
Harald Welte | 9ccd662 | 2016-06-17 00:06:42 +0200 | [diff] [blame] | 16 | /* from 3s to 10s */ |
| 17 | #define GSM_29002_TIMER_S 10 |
| 18 | /* from 15s to 30s */ |
| 19 | #define GSM_29002_TIMER_M 30 |
| 20 | /* from 1min to 10min */ |
| 21 | #define GSM_29002_TIMER_ML (10*60) |
| 22 | /* from 28h to 38h */ |
| 23 | #define GSM_29002_TIMER_L (32*60*60) |
| 24 | |
Harald Welte | 9ccd662 | 2016-06-17 00:06:42 +0200 | [diff] [blame] | 25 | /* VLR subscriber authentication state */ |
| 26 | enum vlr_subscr_auth_state { |
| 27 | /* subscriber needs to be autenticated */ |
| 28 | VLR_SUB_AS_NEEDS_AUTH, |
| 29 | /* waiting for AuthInfo from HLR/AUC */ |
| 30 | VLR_SUB_AS_NEEDS_AUTH_WAIT_AI, |
| 31 | /* waiting for response from subscriber */ |
| 32 | VLR_SUB_AS_WAIT_RESP, |
| 33 | /* successfully authenticated */ |
| 34 | VLR_SUB_AS_AUTHENTICATED, |
| 35 | /* subscriber needs re-sync */ |
| 36 | VLR_SUB_AS_NEEDS_RESYNC, |
| 37 | /* waiting for AuthInfo with ReSync */ |
| 38 | VLR_SUB_AS_NEEDS_AUTH_WAIT_SAI_RESYNC, |
| 39 | /* waiting for response from subscr, resync case */ |
| 40 | VLR_SUB_AS_WAIT_RESP_RESYNC, |
| 41 | /* waiting for IMSI from subscriber */ |
| 42 | VLR_SUB_AS_WAIT_ID_IMSI, |
| 43 | /* authentication has failed */ |
| 44 | VLR_SUB_AS_AUTH_FAILED, |
| 45 | }; |
| 46 | |
| 47 | enum vlr_lu_event { |
| 48 | VLR_ULA_E_UPDATE_LA, /* Initial trigger (LU from MS) */ |
| 49 | VLR_ULA_E_SEND_ID_ACK, /* Result of Send-ID from PVLR */ |
| 50 | VLR_ULA_E_SEND_ID_NACK, /* Result of Send-ID from PVLR */ |
| 51 | VLR_ULA_E_AUTH_RES, /* Result of auth procedure */ |
| 52 | VLR_ULA_E_CIPH_RES, /* Result of Ciphering Mode Command */ |
| 53 | VLR_ULA_E_ID_IMSI, /* IMSI recieved from MS */ |
| 54 | VLR_ULA_E_ID_IMEI, /* IMEI received from MS */ |
| 55 | VLR_ULA_E_ID_IMEISV, /* IMEISV received from MS */ |
| 56 | VLR_ULA_E_HLR_LU_RES, /* HLR UpdateLocation result */ |
| 57 | VLR_ULA_E_UPD_HLR_COMPL,/* UpdatE_HLR_VLR result */ |
| 58 | VLR_ULA_E_LU_COMPL_SUCCESS,/* Location_Update_Completion_VLR result */ |
| 59 | VLR_ULA_E_LU_COMPL_FAILURE,/* Location_Update_Completion_VLR result */ |
| 60 | VLR_ULA_E_NEW_TMSI_ACK, /* TMSI Reallocation Complete */ |
| 61 | }; |
| 62 | |
| 63 | enum vlr_ciph_result_cause { |
| 64 | VLR_CIPH_REJECT, /* ? */ |
| 65 | VLR_CIPH_COMPL, |
| 66 | }; |
| 67 | |
| 68 | struct vlr_ciph_result { |
| 69 | enum vlr_ciph_result_cause cause; |
| 70 | const char *imeisv; |
| 71 | }; |
| 72 | |
| 73 | enum vlr_subscr_security_context { |
| 74 | VLR_SEC_CTX_NONE, |
| 75 | VLR_SEC_CTX_GSM, |
| 76 | VLR_SEC_CTX_UMTS, |
| 77 | }; |
| 78 | |
| 79 | enum vlr_lu_type { |
| 80 | VLR_LU_TYPE_PERIODIC, |
| 81 | VLR_LU_TYPE_IMSI_ATTACH, |
| 82 | VLR_LU_TYPE_REGULAR, |
| 83 | }; |
| 84 | |
| 85 | #define OSMO_LBUF_DECL(name, xlen) \ |
| 86 | struct { \ |
| 87 | uint8_t buf[xlen]; \ |
| 88 | size_t len; \ |
| 89 | } name |
| 90 | |
| 91 | struct sgsn_mm_ctx; |
| 92 | struct vlr_instance; |
| 93 | |
| 94 | /* The VLR subscriber is the part of the GSM subscriber state in VLR (CS) or |
| 95 | * SGSN (PS), particularly while interacting with the HLR via GSUP */ |
| 96 | struct vlr_subscr { |
| 97 | struct llist_head list; |
| 98 | struct vlr_instance *vlr; |
| 99 | |
| 100 | /* TODO either populate from HLR or drop this completely? */ |
| 101 | long long unsigned int id; |
| 102 | |
| 103 | /* Data from HLR */ /* 3GPP TS 23.008 */ |
| 104 | /* Always use vlr_subscr_set_imsi() to write to imsi[] */ |
| 105 | char imsi[GSM23003_IMSI_MAX_DIGITS+1]; /* 2.1.1.1 */ |
| 106 | char msisdn[GSM_EXTENSION_LENGTH+1]; /* 2.1.2 */ |
| 107 | char name[GSM_NAME_LENGTH+1]; /* proprietary */ |
| 108 | OSMO_LBUF_DECL(hlr, 16); /* 2.4.7 */ |
| 109 | uint32_t periodic_lu_timer; /* 2.4.24 */ |
| 110 | uint32_t age_indicator; /* 2.17.1 */ |
| 111 | |
| 112 | /* Authentication Data */ |
| 113 | struct gsm_auth_tuple auth_tuples[5]; /* 2.3.1-2.3.4 */ |
| 114 | struct gsm_auth_tuple *last_tuple; |
| 115 | enum vlr_subscr_security_context sec_ctx; |
| 116 | |
| 117 | /* Data local to VLR is below */ |
| 118 | uint32_t tmsi; /* 2.1.4 */ |
| 119 | /* Newly allocated TMSI that was not yet acked by MS */ |
| 120 | uint32_t tmsi_new; |
| 121 | |
| 122 | /* some redundancy in information below? */ |
| 123 | struct osmo_cell_global_id cgi; /* 2.4.16 */ |
| 124 | uint16_t lac; /* 2.4.2 */ |
| 125 | |
| 126 | char imeisv[GSM23003_IMEISV_NUM_DIGITS+1]; /* 2.2.3 */ |
| 127 | char imei[GSM23003_IMEISV_NUM_DIGITS+1]; /* 2.1.9 */ |
| 128 | bool imsi_detached_flag; /* 2.7.1 */ |
| 129 | bool conf_by_radio_contact_ind; /* 2.7.4.1 */ |
| 130 | bool sub_dataconf_by_hlr_ind; /* 2.7.4.2 */ |
| 131 | bool loc_conf_in_hlr_ind; /* 2.7.4.3 */ |
| 132 | bool dormant_ind; /* 2.7.8 */ |
| 133 | bool cancel_loc_rx; /* 2.7.8A */ |
| 134 | bool ms_not_reachable_flag; /* 2.10.2 (MNRF) */ |
| 135 | bool la_allowed; |
| 136 | |
| 137 | int use_count; |
| 138 | time_t expire_lu; /* FIXME: overlap with periodic_lu_timer/age_indicator */ |
| 139 | |
| 140 | struct osmo_fsm_inst *lu_fsm; |
| 141 | struct osmo_fsm_inst *auth_fsm; |
| 142 | struct osmo_fsm_inst *proc_arq_fsm; |
| 143 | |
| 144 | bool lu_complete; |
| 145 | |
| 146 | void *msc_conn_ref; |
| 147 | |
| 148 | /* PS (SGSN) specific parts */ |
| 149 | struct { |
| 150 | struct llist_head pdp_list; |
| 151 | uint8_t rac; |
| 152 | uint8_t sac; |
| 153 | struct gprs_mm_ctx *mmctx; |
| 154 | } ps; |
| 155 | /* CS (NITB/CSCN) specific parts */ |
| 156 | struct { |
| 157 | /* pending requests */ |
| 158 | bool is_paging; |
| 159 | struct llist_head requests; |
| 160 | } cs; |
| 161 | }; |
| 162 | |
| 163 | enum vlr_proc_arq_result; |
| 164 | |
| 165 | enum vlr_ciph { |
| 166 | VLR_CIPH_NONE, /*< A5/0, no encryption */ |
| 167 | VLR_CIPH_A5_1, /*< A5/1, encryption */ |
| 168 | VLR_CIPH_A5_2, /*< A5/2, deprecated export-grade encryption */ |
| 169 | VLR_CIPH_A5_3, /*< A5/3, 'new secure' encryption */ |
| 170 | }; |
| 171 | |
| 172 | struct vlr_ops { |
| 173 | /* encode + transmit an AUTH REQ towards the MS. |
| 174 | * \param[in] at auth tuple providing rand, key_seq and autn. |
| 175 | * \param[in] send_autn True to send AUTN, for r99 UMTS auth. |
| 176 | */ |
| 177 | int (*tx_auth_req)(void *msc_conn_ref, struct gsm_auth_tuple *at, |
| 178 | bool send_autn); |
| 179 | /* encode + transmit an AUTH REJECT towards the MS */ |
| 180 | int (*tx_auth_rej)(void *msc_conn_ref); |
| 181 | |
| 182 | /* encode + transmit an IDENTITY REQUEST towards the MS */ |
| 183 | int (*tx_id_req)(void *msc_conn_ref, uint8_t mi_type); |
| 184 | |
| 185 | int (*tx_lu_acc)(void *msc_conn_ref, uint32_t send_tmsi); |
| 186 | int (*tx_lu_rej)(void *msc_conn_ref, uint8_t cause); |
| 187 | int (*tx_cm_serv_acc)(void *msc_conn_ref); |
| 188 | int (*tx_cm_serv_rej)(void *msc_conn_ref, enum vlr_proc_arq_result result); |
| 189 | |
| 190 | int (*set_ciph_mode)(void *msc_conn_ref, enum vlr_ciph ciph_mode, |
| 191 | bool retrieve_imeisv); |
| 192 | |
| 193 | /* notify MSC/SGSN that the subscriber data in VLR has been updated */ |
| 194 | void (*subscr_update)(struct vlr_subscr *vsub); |
| 195 | /* notify MSC/SGSN that the given subscriber has been associated |
| 196 | * with this msc_conn_ref */ |
| 197 | void (*subscr_assoc)(void *msc_conn_ref, struct vlr_subscr *vsub); |
| 198 | }; |
| 199 | |
| 200 | enum vlr_timer { |
| 201 | VLR_T_3250, |
| 202 | VLR_T_3260, |
| 203 | VLR_T_3270, |
| 204 | _NUM_VLR_TIMERS |
| 205 | }; |
| 206 | |
| 207 | /* An instance of the VLR codebase */ |
| 208 | struct vlr_instance { |
| 209 | struct llist_head subscribers; |
| 210 | struct llist_head operations; |
| 211 | struct gsup_client *gsup_client; |
| 212 | struct vlr_ops ops; |
| 213 | struct { |
| 214 | bool retrieve_imeisv; |
| 215 | bool assign_tmsi; |
| 216 | bool check_imei_rqd; |
| 217 | int auth_tuple_max_use_count; |
| 218 | bool auth_reuse_old_sets_on_error; |
| 219 | bool parq_retrieve_imsi; |
| 220 | bool is_ps; |
| 221 | uint32_t timer[_NUM_VLR_TIMERS]; |
| 222 | } cfg; |
| 223 | /* A free-form pointer for use by the caller */ |
| 224 | void *user_ctx; |
| 225 | }; |
| 226 | |
| 227 | extern const struct value_string vlr_ciph_names[]; |
| 228 | static inline const char *vlr_ciph_name(enum vlr_ciph val) |
| 229 | { |
| 230 | return get_value_string(vlr_ciph_names, val); |
| 231 | } |
| 232 | |
| 233 | /* Location Updating request */ |
| 234 | struct osmo_fsm_inst * |
| 235 | vlr_loc_update(struct osmo_fsm_inst *parent, |
| 236 | uint32_t parent_event_success, |
| 237 | uint32_t parent_event_failure, |
| 238 | void *parent_event_data, |
| 239 | struct vlr_instance *vlr, void *msc_conn_ref, |
| 240 | enum vlr_lu_type type, uint32_t tmsi, const char *imsi, |
| 241 | const struct osmo_location_area_id *old_lai, |
| 242 | const struct osmo_location_area_id *new_lai, |
| 243 | bool authentication_required, |
| 244 | enum vlr_ciph ciphering_required, |
| 245 | bool is_r99, bool is_utran, |
| 246 | bool assign_tmsi); |
| 247 | |
| 248 | void vlr_loc_update_conn_timeout(struct osmo_fsm_inst *fi); |
| 249 | |
| 250 | /* tell the VLR that the subscriber connection is gone */ |
| 251 | int vlr_subscr_disconnected(struct vlr_subscr *vsub); |
| 252 | |
| 253 | int vlr_subscr_rx_id_resp(struct vlr_subscr *vsub, const uint8_t *mi, size_t mi_len); |
| 254 | int vlr_subscr_rx_auth_resp(struct vlr_subscr *vsub, bool is_r99, bool is_utran, |
| 255 | const uint8_t *res, uint8_t res_len); |
| 256 | int vlr_subscr_rx_auth_fail(struct vlr_subscr *vsub, const uint8_t *auts); |
| 257 | int vlr_subscr_tx_auth_fail_rep(struct vlr_subscr *vsub); |
| 258 | void vlr_subscr_rx_ciph_res(struct vlr_subscr *vsub, struct vlr_ciph_result *res); |
| 259 | int vlr_subscr_rx_tmsi_reall_compl(struct vlr_subscr *vsub); |
| 260 | int vlr_subscr_rx_imsi_detach(struct vlr_subscr *vsub); |
| 261 | void vlr_subscr_conn_timeout(struct vlr_subscr *vsub); |
| 262 | |
| 263 | struct vlr_instance *vlr_alloc(void *ctx, const struct vlr_ops *ops); |
| 264 | int vlr_start(const char *gsup_unit_name, struct vlr_instance *vlr, |
| 265 | const char *gsup_server_addr_str, uint16_t gsup_server_port); |
| 266 | |
| 267 | /* internal use only */ |
| 268 | |
| 269 | struct osmo_fsm_inst *sub_pres_vlr_fsm_start(struct osmo_fsm_inst *parent, |
| 270 | struct vlr_subscr *vsub, |
| 271 | uint32_t term_event); |
| 272 | struct osmo_fsm_inst * |
| 273 | upd_hlr_vlr_proc_start(struct osmo_fsm_inst *parent, |
| 274 | struct vlr_subscr *vsub, |
| 275 | uint32_t parent_event); |
| 276 | |
| 277 | struct osmo_fsm_inst * |
| 278 | lu_compl_vlr_proc_start(struct osmo_fsm_inst *parent, |
| 279 | struct vlr_subscr *vsub, |
| 280 | void *msc_conn_ref, |
| 281 | uint32_t parent_event_success, |
| 282 | uint32_t parent_event_failure); |
| 283 | |
| 284 | |
| 285 | const char *vlr_subscr_name(struct vlr_subscr *vsub); |
| 286 | const char *vlr_subscr_msisdn_or_name(struct vlr_subscr *vsub); |
| 287 | |
| 288 | #define vlr_subscr_find_by_imsi(vlr, imsi) \ |
| 289 | _vlr_subscr_find_by_imsi(vlr, imsi, __BASE_FILE__, __LINE__) |
| 290 | #define vlr_subscr_find_or_create_by_imsi(vlr, imsi, created) \ |
| 291 | _vlr_subscr_find_or_create_by_imsi(vlr, imsi, created, \ |
| 292 | __BASE_FILE__, __LINE__) |
| 293 | |
| 294 | #define vlr_subscr_find_by_tmsi(vlr, tmsi) \ |
| 295 | _vlr_subscr_find_by_tmsi(vlr, tmsi, __BASE_FILE__, __LINE__) |
| 296 | #define vlr_subscr_find_or_create_by_tmsi(vlr, tmsi, created) \ |
| 297 | _vlr_subscr_find_or_create_by_tmsi(vlr, tmsi, created, \ |
| 298 | __BASE_FILE__, __LINE__) |
| 299 | |
| 300 | #define vlr_subscr_find_by_msisdn(vlr, msisdn) \ |
| 301 | _vlr_subscr_find_by_msisdn(vlr, msisdn, __BASE_FILE__, __LINE__) |
| 302 | |
| 303 | struct vlr_subscr *_vlr_subscr_find_by_imsi(struct vlr_instance *vlr, |
| 304 | const char *imsi, |
| 305 | const char *file, int line); |
| 306 | struct vlr_subscr *_vlr_subscr_find_or_create_by_imsi(struct vlr_instance *vlr, |
| 307 | const char *imsi, |
| 308 | bool *created, |
| 309 | const char *file, |
| 310 | int line); |
| 311 | |
| 312 | struct vlr_subscr *_vlr_subscr_find_by_tmsi(struct vlr_instance *vlr, |
| 313 | uint32_t tmsi, |
| 314 | const char *file, int line); |
| 315 | struct vlr_subscr *_vlr_subscr_find_or_create_by_tmsi(struct vlr_instance *vlr, |
| 316 | uint32_t tmsi, |
| 317 | bool *created, |
| 318 | const char *file, |
| 319 | int line); |
| 320 | |
| 321 | struct vlr_subscr *_vlr_subscr_find_by_msisdn(struct vlr_instance *vlr, |
| 322 | const char *msisdn, |
| 323 | const char *file, int line); |
| 324 | |
| 325 | #define vlr_subscr_get(sub) _vlr_subscr_get(sub, __BASE_FILE__, __LINE__) |
| 326 | #define vlr_subscr_put(sub) _vlr_subscr_put(sub, __BASE_FILE__, __LINE__) |
| 327 | struct vlr_subscr *_vlr_subscr_get(struct vlr_subscr *sub, const char *file, int line); |
| 328 | struct vlr_subscr *_vlr_subscr_put(struct vlr_subscr *sub, const char *file, int line); |
| 329 | |
| 330 | struct vlr_subscr *vlr_subscr_alloc(struct vlr_instance *vlr); |
| 331 | void vlr_subscr_free(struct vlr_subscr *vsub); |
| 332 | int vlr_subscr_alloc_tmsi(struct vlr_subscr *vsub); |
| 333 | |
| 334 | void vlr_subscr_set_imsi(struct vlr_subscr *vsub, const char *imsi); |
| 335 | void vlr_subscr_set_imei(struct vlr_subscr *vsub, const char *imei); |
| 336 | void vlr_subscr_set_imeisv(struct vlr_subscr *vsub, const char *imeisv); |
| 337 | void vlr_subscr_set_msisdn(struct vlr_subscr *vsub, const char *msisdn); |
| 338 | |
| 339 | bool vlr_subscr_matches_imsi(struct vlr_subscr *vsub, const char *imsi); |
| 340 | bool vlr_subscr_matches_tmsi(struct vlr_subscr *vsub, uint32_t tmsi); |
| 341 | bool vlr_subscr_matches_msisdn(struct vlr_subscr *vsub, const char *msisdn); |
| 342 | bool vlr_subscr_matches_imei(struct vlr_subscr *vsub, const char *imei); |
| 343 | |
| 344 | uint32_t vlr_timer(struct vlr_instance *vlr, uint32_t timer); |
| 345 | |
| 346 | int vlr_subscr_changed(struct vlr_subscr *vsub); |
| 347 | int vlr_subscr_purge(struct vlr_subscr *vsub); |
| 348 | void vlr_subscr_cancel(struct vlr_subscr *vsub, enum gsm48_gmm_cause cause); |
| 349 | |
| 350 | |
| 351 | /* Process Acccess Request FSM */ |
| 352 | |
| 353 | enum vlr_proc_arq_result { |
| 354 | VLR_PR_ARQ_RES_NONE, |
| 355 | VLR_PR_ARQ_RES_SYSTEM_FAILURE, |
| 356 | VLR_PR_ARQ_RES_ILLEGAL_SUBSCR, |
| 357 | VLR_PR_ARQ_RES_UNIDENT_SUBSCR, |
| 358 | VLR_PR_ARQ_RES_ROAMING_NOTALLOWED, |
| 359 | VLR_PR_ARQ_RES_ILLEGAL_EQUIP, |
| 360 | VLR_PR_ARQ_RES_UNKNOWN_ERROR, |
| 361 | VLR_PR_ARQ_RES_TIMEOUT, |
| 362 | VLR_PR_ARQ_RES_PASSED, |
| 363 | }; |
| 364 | |
| 365 | extern const struct value_string vlr_proc_arq_result_names[]; |
| 366 | static inline const char *vlr_proc_arq_result_name(enum vlr_proc_arq_result res) |
| 367 | { |
| 368 | return get_value_string(vlr_proc_arq_result_names, res); |
| 369 | } |
| 370 | |
| 371 | enum proc_arq_vlr_event { |
| 372 | PR_ARQ_E_START, |
| 373 | PR_ARQ_E_ID_IMSI, |
| 374 | PR_ARQ_E_AUTH_RES, |
| 375 | PR_ARQ_E_CIPH_RES, |
| 376 | PR_ARQ_E_UPD_LOC_RES, |
| 377 | PR_ARQ_E_TRACE_RES, |
| 378 | PR_ARQ_E_IMEI_RES, |
| 379 | PR_ARQ_E_PRES_RES, |
| 380 | PR_ARQ_E_TMSI_ACK, |
| 381 | }; |
| 382 | |
| 383 | enum vlr_parq_type { |
| 384 | VLR_PR_ARQ_T_INVALID = 0, /* to guard against unset vars */ |
| 385 | VLR_PR_ARQ_T_CM_SERV_REQ, |
| 386 | VLR_PR_ARQ_T_PAGING_RESP, |
| 387 | /* FIXME: differentiate between services of 24.008 10.5.3.3 */ |
| 388 | }; |
| 389 | |
| 390 | /* Process Access Request (CM SERV REQ / PAGING RESP) */ |
| 391 | void |
| 392 | vlr_proc_acc_req(struct osmo_fsm_inst *parent, |
| 393 | uint32_t parent_event_success, |
| 394 | uint32_t parent_event_failure, |
| 395 | void *parent_event_data, |
| 396 | struct vlr_instance *vlr, void *msc_conn_ref, |
| 397 | enum vlr_parq_type type, const uint8_t *mi_lv, |
| 398 | const struct osmo_location_area_id *lai, |
| 399 | bool authentication_required, |
| 400 | enum vlr_ciph ciphering_required, |
| 401 | bool is_r99, bool is_utran); |
| 402 | |
| 403 | void vlr_parq_conn_timeout(struct osmo_fsm_inst *fi); |
| 404 | |
| 405 | void vlr_parq_fsm_init(void); |
| 406 | |
| 407 | int vlr_set_ciph_mode(struct vlr_instance *vlr, |
| 408 | struct osmo_fsm_inst *fi, |
| 409 | void *msc_conn_ref, |
| 410 | enum vlr_ciph ciph_mode, |
| 411 | bool retrieve_imeisv); |
| 412 | |
| 413 | void log_set_filter_vlr_subscr(struct log_target *target, |
| 414 | struct vlr_subscr *vlr_subscr); |