Skip to content

Commit

Permalink
[SMF] Initial implementation of Final-Unit-Indication
Browse files Browse the repository at this point in the history
Only "Terminate" action is implemented so far, and it will be used
regardless of the action provided by the OCS.
  • Loading branch information
pespin committed Apr 4, 2024
1 parent eb2b19b commit 2116621
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 12 deletions.
11 changes: 11 additions & 0 deletions lib/diameter/gy/message.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ extern "C" {
#define OGS_DIAM_GY_AVP_CODE_CHARGING_RULE_BASE_NAME (1004)
#define OGS_DIAM_GY_AVP_CODE_FLOW_INFORMATION (1058)
#define OGS_DIAM_GY_AVP_CODE_QOS_INFORMATION (1016)
#define OGS_DIAM_GY_AVP_CODE_FINAL_UNIT_INDICATION (430)
#define OGS_DIAM_GY_AVP_CODE_FINAL_UNIT_ACTION (449)

extern struct dict_object *ogs_diam_gy_application;

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions src/smf/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
9 changes: 9 additions & 0 deletions src/smf/gsm-sm.c
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,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;
Expand Down Expand Up @@ -829,6 +830,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);
Expand Down
2 changes: 2 additions & 0 deletions src/smf/gy-handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,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);
Expand Down Expand Up @@ -199,6 +200,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);
Expand Down
46 changes: 46 additions & 0 deletions src/smf/gy-path.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
28 changes: 19 additions & 9 deletions src/smf/n4-handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand All @@ -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 {
Expand All @@ -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) {
Expand Down Expand Up @@ -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 */
}
Expand Down Expand Up @@ -1379,4 +1388,5 @@ void smf_n4_handle_session_report_request(
0));
}
}
return cause_value;
}
2 changes: 1 addition & 1 deletion src/smf/n4-handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
10 changes: 8 additions & 2 deletions src/smf/pfcp-sm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down

0 comments on commit 2116621

Please sign in to comment.