diff --git a/src/mme/sgsap-build.c b/src/mme/sgsap-build.c index 18317f582..d27b4a44d 100644 --- a/src/mme/sgsap-build.c +++ b/src/mme/sgsap-build.c @@ -91,6 +91,7 @@ ogs_pkbuf_t *sgsap_build_location_update_request(mme_ue_t *mme_ue) return pkbuf; } + ogs_pkbuf_t *sgsap_build_tmsi_reallocation_complete(mme_ue_t *mme_ue) { mme_csmap_t *csmap = NULL; @@ -124,6 +125,96 @@ ogs_pkbuf_t *sgsap_build_tmsi_reallocation_complete(mme_ue_t *mme_ue) return pkbuf; } +ogs_pkbuf_t *sgsap_build_ue_activity_indication(mme_ue_t *mme_ue) +{ + ogs_tlv_t *root = NULL; + ogs_pkbuf_t *pkbuf = NULL; + + ogs_assert(mme_ue); + + root = ogs_tlv_add(NULL, OGS_TLV_MODE_T1_L1, SGSAP_IE_IMSI_TYPE, + SGSAP_IE_IMSI_LEN, 0, &mme_ue->nas_mobile_identity_imsi); + + /* TODO: Maximum UE Availability Time */ + + pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN); + if (!pkbuf) { + ogs_error("ogs_pkbuf_alloc() failed"); + ogs_tlv_free_all(root); + return NULL; + } + ogs_pkbuf_put_u8(pkbuf, SGSAP_UE_ACTIVITY_INDICATION); + ogs_pkbuf_put(pkbuf, OGS_MAX_SDU_LEN-1); + + ogs_pkbuf_trim(pkbuf, 1+ogs_tlv_render(root, + pkbuf->data+1, OGS_MAX_SDU_LEN-1)); + + ogs_tlv_free_all(root); + + return pkbuf; +} + +ogs_pkbuf_t *sgsap_build_alert_ack(mme_ue_t *mme_ue) +{ + ogs_tlv_t *root = NULL; + ogs_pkbuf_t *pkbuf = NULL; + + ogs_assert(mme_ue); + + root = ogs_tlv_add(NULL, OGS_TLV_MODE_T1_L1, SGSAP_IE_IMSI_TYPE, + SGSAP_IE_IMSI_LEN, 0, &mme_ue->nas_mobile_identity_imsi); + + pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN); + if (!pkbuf) { + ogs_error("ogs_pkbuf_alloc() failed"); + ogs_tlv_free_all(root); + return NULL; + } + ogs_pkbuf_put_u8(pkbuf, SGSAP_ALERT_ACK); + ogs_pkbuf_put(pkbuf, OGS_MAX_SDU_LEN-1); + + ogs_pkbuf_trim(pkbuf, 1+ogs_tlv_render(root, + pkbuf->data+1, OGS_MAX_SDU_LEN-1)); + + ogs_tlv_free_all(root); + + return pkbuf; +} + +ogs_pkbuf_t *sgsap_build_alert_reject( + ogs_nas_mobile_identity_imsi_t *nas_mobile_identity_imsi, + int nas_mobile_identity_imsi_len, uint8_t sgs_cause) +{ + ogs_tlv_t *root = NULL; + ogs_pkbuf_t *pkbuf = NULL; + + ogs_assert(nas_mobile_identity_imsi); + ogs_assert(nas_mobile_identity_imsi_len == SGSAP_IE_IMSI_LEN); + + root = ogs_tlv_add(NULL, OGS_TLV_MODE_T1_L1, + SGSAP_IE_IMSI_TYPE, SGSAP_IE_IMSI_LEN, 0, nas_mobile_identity_imsi); + ogs_tlv_add(root, OGS_TLV_MODE_T1_L1, + SGSAP_IE_SGS_CAUSE_TYPE, SGSAP_IE_SGS_CAUSE_LEN, 0, &sgs_cause); + + ogs_debug(" CAUSE[%d]", sgs_cause); + + pkbuf = ogs_pkbuf_alloc(NULL, OGS_MAX_SDU_LEN); + if (!pkbuf) { + ogs_error("ogs_pkbuf_alloc() failed"); + ogs_tlv_free_all(root); + return NULL; + } + ogs_pkbuf_put_u8(pkbuf, SGSAP_ALERT_REJECT); + ogs_pkbuf_put(pkbuf, OGS_MAX_SDU_LEN-1); + + ogs_pkbuf_trim(pkbuf, 1+ogs_tlv_render(root, + pkbuf->data+1, OGS_MAX_SDU_LEN-1)); + + ogs_tlv_free_all(root); + + return pkbuf; +} + ogs_pkbuf_t *sgsap_build_detach_indication(mme_ue_t *mme_ue) { mme_csmap_t *csmap = NULL; diff --git a/src/mme/sgsap-build.h b/src/mme/sgsap-build.h index 12810e9c8..2364d10c8 100644 --- a/src/mme/sgsap-build.h +++ b/src/mme/sgsap-build.h @@ -30,6 +30,11 @@ extern "C" { ogs_pkbuf_t *sgsap_build_location_update_request(mme_ue_t *mme_ue); ogs_pkbuf_t *sgsap_build_tmsi_reallocation_complete(mme_ue_t *mme_ue); +ogs_pkbuf_t *sgsap_build_ue_activity_indication(mme_ue_t *mme_ue); +ogs_pkbuf_t *sgsap_build_alert_ack(mme_ue_t *mme_ue); +ogs_pkbuf_t *sgsap_build_alert_reject( + ogs_nas_mobile_identity_imsi_t *nas_mobile_identity_imsi, + int nas_mobile_identity_imsi_len, uint8_t sgs_cause); ogs_pkbuf_t *sgsap_build_detach_indication(mme_ue_t *mme_ue); ogs_pkbuf_t *sgsap_build_mo_csfb_indication(mme_ue_t *mme_ue); ogs_pkbuf_t *sgsap_build_paging_reject( diff --git a/src/mme/sgsap-handler.c b/src/mme/sgsap-handler.c index 62c82f4c2..a30e681a7 100644 --- a/src/mme/sgsap-handler.c +++ b/src/mme/sgsap-handler.c @@ -405,6 +405,98 @@ error: return; } +void sgsap_handle_alert_request(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf) +{ + ogs_tlv_t *root = NULL, *iter = NULL; + mme_ue_t *mme_ue = NULL; + uint8_t sgs_cause = SGSAP_SGS_CAUSE_IMSI_UNKNOWN; + + char imsi_bcd[OGS_MAX_IMSI_BCD_LEN+1] = {0, }; + + ogs_nas_mobile_identity_imsi_t *nas_mobile_identity_imsi = NULL; + int nas_mobile_identity_imsi_len = 0; + + ogs_assert(vlr); + ogs_assert(pkbuf); + + ogs_warn("[SGSAP] Rx ALERT-REQUEST"); + + ogs_pkbuf_pull(pkbuf, 1); + + root = ogs_tlv_parse_block(pkbuf->len, pkbuf->data, OGS_TLV_MODE_T1_L1); + if (!root) { + ogs_error("ogs_tlv_parse_block() failed"); + sgs_cause = SGSAP_SGS_CAUSE_SEMANTICALLY_INCORRECT_MESSAGE; + goto alert_reject; + } + + iter = root; + while (iter) { + switch (iter->type) { + case SGSAP_IE_IMSI_TYPE: + nas_mobile_identity_imsi = iter->value; + nas_mobile_identity_imsi_len = iter->length; + break; + default: + ogs_warn("Invalid Type [%d]", iter->type); + break; + } + iter = iter->next; + } + + ogs_tlv_free_all(root); + + if (!nas_mobile_identity_imsi) { + ogs_error("No IMSI"); + sgs_cause = SGSAP_SGS_CAUSE_MISSING_MANDATORY_IE; + goto alert_reject; + } + if (nas_mobile_identity_imsi_len != SGSAP_IE_IMSI_LEN) { + ogs_error("Invalid IMSI len [%d]", nas_mobile_identity_imsi_len); + sgs_cause = SGSAP_SGS_CAUSE_INVALID_MANDATORY_IE; + goto alert_reject; + } + + if (nas_mobile_identity_imsi->type != OGS_NAS_MOBILE_IDENTITY_IMSI) { + ogs_error("nas_mobile_identity_imsi->type == " + "OGS_NAS_MOBILE_IDENTITY_IMSI"); + sgs_cause = SGSAP_SGS_CAUSE_INVALID_MANDATORY_IE; + goto alert_reject; + } + + ogs_nas_eps_imsi_to_bcd(nas_mobile_identity_imsi, + nas_mobile_identity_imsi_len, imsi_bcd); + mme_ue = mme_ue_find_by_imsi_bcd(imsi_bcd); + + if (!mme_ue) { + ogs_error("No UE(mme-ue) context"); + sgs_cause = SGSAP_SGS_CAUSE_IMSI_UNKNOWN; + goto alert_reject; + } + + /* TODO: Set NEAF flag in UE */ + + ogs_warn("[SGSAP] Tx ALERT-ACK"); + + sgsap_send_to_vlr_with_sid( + vlr, + sgsap_build_alert_ack(mme_ue), + 0); + return; + +alert_reject: + ogs_debug("[SGSAP] Tx ALERT-REJECT"); + ogs_debug(" IMSI[%s]", imsi_bcd); + + sgsap_send_to_vlr_with_sid( + vlr, + sgsap_build_alert_reject( + nas_mobile_identity_imsi, nas_mobile_identity_imsi_len, + sgs_cause), + 0); + return; +} + void sgsap_handle_detach_ack(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf) { ogs_tlv_t *root = NULL, *iter = NULL; diff --git a/src/mme/sgsap-handler.h b/src/mme/sgsap-handler.h index 8d38de64b..16bcc1fb7 100644 --- a/src/mme/sgsap-handler.h +++ b/src/mme/sgsap-handler.h @@ -28,6 +28,7 @@ extern "C" { void sgsap_handle_location_update_accept(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf); void sgsap_handle_location_update_reject(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf); +void sgsap_handle_alert_request(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf); void sgsap_handle_detach_ack(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf); void sgsap_handle_paging_request(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf); void sgsap_handle_downlink_unitdata(mme_vlr_t *vlr, ogs_pkbuf_t *pkbuf); diff --git a/src/mme/sgsap-path.c b/src/mme/sgsap-path.c index 2fbdfb2b1..f648c4a3a 100644 --- a/src/mme/sgsap-path.c +++ b/src/mme/sgsap-path.c @@ -150,6 +150,26 @@ int sgsap_send_tmsi_reallocation_complete(mme_ue_t *mme_ue) return rv; } +int sgsap_send_ue_activity_indication(mme_ue_t *mme_ue) +{ + int rv; + ogs_pkbuf_t *pkbuf = NULL; + ogs_assert(mme_ue); + + ogs_debug("[SGSAP] Tx UE-ACTIVITY-IND"); + ogs_debug(" IMSI[%s]", mme_ue->imsi_bcd); + + pkbuf = sgsap_build_ue_activity_indication(mme_ue); + if (!pkbuf) { + ogs_error("sgsap_build_tmsi_reallocation_complete() failed"); + return OGS_ERROR; + } + rv = sgsap_send_to_vlr(mme_ue, pkbuf); + ogs_expect(rv == OGS_OK); + + return rv; +} + int sgsap_send_detach_indication(mme_ue_t *mme_ue) { int rv; diff --git a/src/mme/sgsap-path.h b/src/mme/sgsap-path.h index 897019c9b..65e8fc69e 100644 --- a/src/mme/sgsap-path.h +++ b/src/mme/sgsap-path.h @@ -44,6 +44,7 @@ int sgsap_send_to_vlr(mme_ue_t *mme_ue, ogs_pkbuf_t *pkbuf); int sgsap_send_location_update_request(mme_ue_t *mme_ue); int sgsap_send_tmsi_reallocation_complete(mme_ue_t *mme_ue); +int sgsap_send_ue_activity_indication(mme_ue_t *mme_ue); int sgsap_send_detach_indication(mme_ue_t *mme_ue); int sgsap_send_mo_csfb_indication(mme_ue_t *mme_ue); int sgsap_send_paging_reject(mme_ue_t *mme_ue, uint8_t sgs_cause); diff --git a/src/mme/sgsap-sm.c b/src/mme/sgsap-sm.c index ea8db719d..3d390bc46 100644 --- a/src/mme/sgsap-sm.c +++ b/src/mme/sgsap-sm.c @@ -153,6 +153,9 @@ void sgsap_state_connected(ogs_fsm_t *s, mme_event_t *e) case SGSAP_LOCATION_UPDATE_REJECT: sgsap_handle_location_update_reject(vlr, pkbuf); break; + case SGSAP_ALERT_REQUEST: + sgsap_handle_alert_request(vlr, pkbuf); + break; case SGSAP_EPS_DETACH_ACK: case SGSAP_IMSI_DETACH_ACK: sgsap_handle_detach_ack(vlr, pkbuf); diff --git a/src/mme/sgsap-types.h b/src/mme/sgsap-types.h index fe0ab775d..88e229309 100644 --- a/src/mme/sgsap-types.h +++ b/src/mme/sgsap-types.h @@ -33,6 +33,10 @@ extern "C" { #define SGSAP_LOCATION_UPDATE_ACCEPT 10 #define SGSAP_LOCATION_UPDATE_REJECT 11 #define SGSAP_TMSI_REALLOCATION_COMPLETE 12 +#define SGSAP_ALERT_REQUEST 13 +#define SGSAP_ALERT_ACK 14 +#define SGSAP_ALERT_REJECT 15 +#define SGSAP_UE_ACTIVITY_INDICATION 16 #define SGSAP_EPS_DETACH_INDICATION 17 #define SGSAP_EPS_DETACH_ACK 18 #define SGSAP_IMSI_DETACH_INDICATION 19