forked from acouzens/open5gs
[SMF] Initial implementation of Final-Unit-Indication
Only "Terminate" action is implemented so far, and it will be used regardless of the action provided by the OCS.
This commit is contained in:
parent
bbdfca29bf
commit
b30604b289
|
@ -40,8 +40,10 @@ extern "C" {
|
|||
#define OGS_DIAM_GY_AVP_CODE_CC_REQUEST_TYPE (416)
|
||||
#define OGS_DIAM_GY_AVP_CODE_CC_TIME (420)
|
||||
#define OGS_DIAM_GY_AVP_CODE_CC_TOTAL_OCTETS (421)
|
||||
#define OGS_DIAM_GY_AVP_CODE_FINAL_UNIT_INDICATION (430)
|
||||
#define OGS_DIAM_GY_AVP_CODE_GRANTED_SERVICE_UNIT (431)
|
||||
#define OGS_DIAM_GY_AVP_CODE_VALIDITY_TIME (448)
|
||||
#define OGS_DIAM_GY_AVP_CODE_FINAL_UNIT_ACTION (449)
|
||||
#define OGS_DIAM_GY_AVP_CODE_MULTIPLE_SERVICES_CREDIT_CONTROL (456)
|
||||
#define OGS_DIAM_GY_AVP_CODE_SUPPORTED_FEATURES (628)
|
||||
#define OGS_DIAM_GY_AVP_CODE_TIME_QUOTA_THRESHOLD (868)
|
||||
|
@ -155,6 +157,14 @@ typedef struct ogs_diam_gy_service_unit_s {
|
|||
uint64_t cc_output_octets;
|
||||
} ogs_diam_gy_service_unit_t;
|
||||
|
||||
typedef struct gs_diam_gy_final_unit_s {
|
||||
bool cc_final_action_present;
|
||||
#define OGS_DIAM_GY_FINAL_UNIT_ACTION_TERMINATE 0
|
||||
#define OGS_DIAM_GY_FINAL_UNIT_ACTION_REDIRECT 1
|
||||
#define OGS_DIAM_GY_FINAL_UNIT_ACTION_REDIRECT_ACCESS 2
|
||||
int32_t cc_final_action;
|
||||
} ogs_diam_gy_final_unit_t;
|
||||
|
||||
typedef struct ogs_diam_gy_message_s {
|
||||
#define OGS_DIAM_GY_CMD_CODE_CREDIT_CONTROL 272
|
||||
#define OGS_DIAM_GY_CMD_RE_AUTH 258
|
||||
|
@ -187,6 +197,7 @@ typedef struct ogs_diam_gy_message_s {
|
|||
uint32_t time_threshold;
|
||||
uint32_t volume_threshold;
|
||||
ogs_diam_gy_service_unit_t granted;
|
||||
ogs_diam_gy_final_unit_t final;
|
||||
uint32_t result_code;
|
||||
uint32_t *err;
|
||||
} cca;
|
||||
|
|
|
@ -357,6 +357,9 @@ typedef struct smf_sess_s {
|
|||
uint64_t dl_octets;
|
||||
ogs_time_t duration;
|
||||
uint32_t reporting_reason; /* OGS_DIAM_GY_REPORTING_REASON_* */
|
||||
/* Whether Gy Final-Unit-Indication was received.
|
||||
* Triggers session release upon Rx of next PFCP Report Req */
|
||||
bool final_unit;
|
||||
/* Snapshot of measurement when last report was sent: */
|
||||
struct {
|
||||
uint64_t ul_octets;
|
||||
|
|
|
@ -727,6 +727,7 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
|
|||
|
||||
ogs_pfcp_xact_t *pfcp_xact = NULL;
|
||||
ogs_pfcp_message_t *pfcp_message = NULL;
|
||||
uint8_t pfcp_cause;
|
||||
|
||||
ogs_diam_gy_message_t *gy_message = NULL;
|
||||
uint32_t diam_err;
|
||||
|
@ -838,6 +839,14 @@ void smf_gsm_state_operational(ogs_fsm_t *s, smf_event_t *e)
|
|||
OGS_FSM_TRAN(s, smf_gsm_state_epc_session_will_release);
|
||||
break;
|
||||
|
||||
case OGS_PFCP_SESSION_REPORT_REQUEST_TYPE:
|
||||
pfcp_cause = smf_n4_handle_session_report_request(sess, pfcp_xact,
|
||||
&pfcp_message->pfcp_session_report_request);
|
||||
if (pfcp_cause != OGS_PFCP_CAUSE_REQUEST_ACCEPTED) {
|
||||
OGS_FSM_TRAN(s, smf_gsm_state_wait_pfcp_deletion);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ogs_error("cannot handle PFCP message type[%d]",
|
||||
pfcp_message->h.type);
|
||||
|
|
|
@ -164,6 +164,7 @@ uint32_t smf_gy_handle_cca_initial_request(
|
|||
/* Configure based on what we received from OCS: */
|
||||
urr_update_time(sess, bearer->urr, gy_message);
|
||||
urr_update_volume(sess, bearer->urr, gy_message);
|
||||
sess->gy.final_unit = gy_message->cca.final.cc_final_action_present;
|
||||
|
||||
/* Associate acconting URR each direction PDR: */
|
||||
ogs_pfcp_pdr_associate_urr(bearer->ul_pdr, bearer->urr);
|
||||
|
@ -221,6 +222,7 @@ uint32_t smf_gy_handle_cca_update_request(
|
|||
|
||||
urr_update_time(sess, urr, gy_message);
|
||||
urr_update_volume(sess, urr, gy_message);
|
||||
sess->gy.final_unit = gy_message->cca.final.cc_final_action_present;
|
||||
/* Associate accounting URR each direction PDR: */
|
||||
ogs_pfcp_pdr_associate_urr(bearer->ul_pdr, urr);
|
||||
ogs_pfcp_pdr_associate_urr(bearer->dl_pdr, urr);
|
||||
|
|
|
@ -48,6 +48,8 @@ static ogs_thread_mutex_t sess_state_mutex;
|
|||
|
||||
static int decode_granted_service_unit(
|
||||
ogs_diam_gy_service_unit_t *su, struct avp *avpch1, int *perror);
|
||||
static int decode_final_unit_indication(
|
||||
ogs_diam_gy_final_unit_t *fu, struct avp *avpch1, int *perror);
|
||||
static void smf_gy_cca_cb(void *data, struct msg **msg);
|
||||
|
||||
static __inline__ struct sess_state *new_state(os0_t sid)
|
||||
|
@ -1149,6 +1151,11 @@ static void smf_gy_cca_cb(void *data, struct msg **msg)
|
|||
case OGS_DIAM_GY_AVP_CODE_VOLUME_QUOTA_THRESHOLD:
|
||||
gy_message->cca.volume_threshold = hdr->avp_value->u32;
|
||||
break;
|
||||
case OGS_DIAM_GY_AVP_CODE_FINAL_UNIT_INDICATION:
|
||||
rv = decode_final_unit_indication(
|
||||
&gy_message->cca.final, avpch1, &error);
|
||||
ogs_assert(rv == OGS_OK);
|
||||
break;
|
||||
default:
|
||||
ogs_warn("Not supported(%d)", hdr->avp_code);
|
||||
break;
|
||||
|
@ -1464,3 +1471,42 @@ static int decode_granted_service_unit(
|
|||
|
||||
return OGS_OK;
|
||||
}
|
||||
|
||||
static int decode_final_unit_indication(
|
||||
ogs_diam_gy_final_unit_t *fu, struct avp *avpch1, int *perror)
|
||||
{
|
||||
int ret = 0, error = 0;
|
||||
struct avp *avpch2;
|
||||
struct avp_hdr *hdr;
|
||||
|
||||
ogs_assert(fu);
|
||||
ogs_assert(avpch1);
|
||||
memset(fu, 0, sizeof(*fu));
|
||||
|
||||
ret = fd_msg_browse(avpch1, MSG_BRW_FIRST_CHILD, &avpch2, NULL);
|
||||
ogs_assert(ret == 0);
|
||||
while (avpch2) {
|
||||
ret = fd_msg_avp_hdr(avpch2, &hdr);
|
||||
ogs_assert(ret == 0);
|
||||
switch (hdr->avp_code) {
|
||||
case OGS_DIAM_GY_AVP_CODE_FINAL_UNIT_ACTION:
|
||||
fu->cc_final_action_present = true;
|
||||
fu->cc_final_action = hdr->avp_value->i32;
|
||||
break;
|
||||
/* TODO:
|
||||
case OGS_DIAM_GY_AVP_CODE_REDIRECT_SERVER:
|
||||
case OGS_DIAM_GY_AVP_CODE_FILTER_ID:
|
||||
case OGS_DIAM_GY_AVP_CODE_RESTRICTION_FILTER_RULE:
|
||||
*/
|
||||
default:
|
||||
ogs_error("Not implemented(%d)", hdr->avp_code);
|
||||
break;
|
||||
}
|
||||
fd_msg_browse(avpch2, MSG_BRW_NEXT, &avpch2, NULL);
|
||||
}
|
||||
|
||||
if (perror)
|
||||
*perror = error;
|
||||
|
||||
return OGS_OK;
|
||||
}
|
||||
|
|
|
@ -1147,7 +1147,9 @@ uint8_t smf_epc_n4_handle_session_deletion_response(
|
|||
return OGS_PFCP_CAUSE_REQUEST_ACCEPTED;
|
||||
}
|
||||
|
||||
void smf_n4_handle_session_report_request(
|
||||
/* Returns OGS_PFCP_CAUSE_REQUEST_ACCEPTED on success,
|
||||
* other cause value on failure */
|
||||
uint8_t smf_n4_handle_session_report_request(
|
||||
smf_sess_t *sess, ogs_pfcp_xact_t *pfcp_xact,
|
||||
ogs_pfcp_session_report_request_t *pfcp_req)
|
||||
{
|
||||
|
@ -1185,7 +1187,7 @@ void smf_n4_handle_session_report_request(
|
|||
ogs_pfcp_send_error_message(pfcp_xact, 0,
|
||||
OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE,
|
||||
cause_value, 0);
|
||||
return;
|
||||
return cause_value;
|
||||
}
|
||||
|
||||
ogs_assert(sess);
|
||||
|
@ -1225,7 +1227,7 @@ void smf_n4_handle_session_report_request(
|
|||
ogs_pfcp_send_error_message(pfcp_xact, 0,
|
||||
OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE,
|
||||
OGS_PFCP_CAUSE_SERVICE_NOT_SUPPORTED, 0);
|
||||
return;
|
||||
return OGS_PFCP_CAUSE_SERVICE_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (qfi) {
|
||||
|
@ -1235,7 +1237,7 @@ void smf_n4_handle_session_report_request(
|
|||
ogs_pfcp_send_error_message(pfcp_xact, 0,
|
||||
OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE,
|
||||
OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND, 0);
|
||||
return;
|
||||
return OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1260,7 +1262,7 @@ void smf_n4_handle_session_report_request(
|
|||
ogs_pfcp_send_error_message(pfcp_xact, 0,
|
||||
OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE,
|
||||
OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND, 0);
|
||||
return;
|
||||
return OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND;
|
||||
}
|
||||
|
||||
switch (sess->up_cnx_state) {
|
||||
|
@ -1332,14 +1334,21 @@ void smf_n4_handle_session_report_request(
|
|||
sess->gy.reporting_reason =
|
||||
smf_pfcp_urr_usage_report_trigger2diam_gy_reporting_reason(&rep_trig);
|
||||
}
|
||||
switch(smf_use_gy_iface()) {
|
||||
switch (smf_use_gy_iface()) {
|
||||
case 1:
|
||||
smf_gy_send_ccr(sess, pfcp_xact,
|
||||
OGS_DIAM_GY_CC_REQUEST_TYPE_UPDATE_REQUEST);
|
||||
if (!sess->gy.final_unit) {
|
||||
smf_gy_send_ccr(sess, pfcp_xact,
|
||||
OGS_DIAM_GY_CC_REQUEST_TYPE_UPDATE_REQUEST);
|
||||
} else {
|
||||
ogs_debug("[%s:%s] Rx PFCP report after Gy Final Unit Indication",
|
||||
smf_ue->imsi_bcd, sess->session.name);
|
||||
/* This effectively triggers session release: */
|
||||
cause_value = OGS_PFCP_CAUSE_NO_RESOURCES_AVAILABLE;
|
||||
}
|
||||
break;
|
||||
case -1:
|
||||
ogs_error("No Gy Diameter Peer");
|
||||
/* TODO: terminate connection */
|
||||
cause_value = OGS_PFCP_CAUSE_NO_RESOURCES_AVAILABLE;
|
||||
break;
|
||||
/* default: continue below */
|
||||
}
|
||||
|
@ -1379,4 +1388,5 @@ void smf_n4_handle_session_report_request(
|
|||
0));
|
||||
}
|
||||
}
|
||||
return cause_value;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ uint8_t smf_epc_n4_handle_session_deletion_response(
|
|||
smf_sess_t *sess, ogs_pfcp_xact_t *xact,
|
||||
ogs_pfcp_session_deletion_response_t *rsp);
|
||||
|
||||
void smf_n4_handle_session_report_request(
|
||||
uint8_t smf_n4_handle_session_report_request(
|
||||
smf_sess_t *sess, ogs_pfcp_xact_t *pfcp_xact,
|
||||
ogs_pfcp_session_report_request_t *pfcp_req);
|
||||
|
||||
|
|
|
@ -370,8 +370,14 @@ void smf_pfcp_state_associated(ogs_fsm_t *s, smf_event_t *e)
|
|||
case OGS_PFCP_SESSION_REPORT_REQUEST_TYPE:
|
||||
if (!message->h.seid_presence) ogs_error("No SEID");
|
||||
|
||||
smf_n4_handle_session_report_request(
|
||||
sess, xact, &message->pfcp_session_report_request);
|
||||
if (!sess) {
|
||||
ogs_error("No Session");
|
||||
ogs_pfcp_send_error_message(xact, 0,
|
||||
OGS_PFCP_SESSION_REPORT_RESPONSE_TYPE,
|
||||
OGS_PFCP_CAUSE_SESSION_CONTEXT_NOT_FOUND, 0);
|
||||
break;
|
||||
}
|
||||
ogs_fsm_dispatch(&sess->sm, e);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
Loading…
Reference in New Issue