diff --git a/modules/ims_charging/Ro_data.c b/modules/ims_charging/Ro_data.c index 63a1f5d02ca..69e0f1408b4 100644 --- a/modules/ims_charging/Ro_data.c +++ b/modules/ims_charging/Ro_data.c @@ -296,10 +296,20 @@ void Ro_free_CCR(Ro_CCR_t *x) { } void Ro_free_CCA(Ro_CCA_t *x) { - if (!x) return; + str *p_str; + if (!x) return; if (x->mscc->final_unit_action) { - mem_free(x->mscc->final_unit_action, pkg); + if (x->mscc->final_unit_action->redirect_server) { + if (x->mscc->final_unit_action->redirect_server->server_address) { + p_str = x->mscc->final_unit_action->redirect_server->server_address; + if (p_str->len > 0 && p_str->s) + mem_free(p_str->s, pkg); + mem_free(p_str, pkg); + } + } + mem_free(x->mscc->final_unit_action, pkg); + } mem_free(x->mscc->granted_service_unit, pkg); mem_free(x->mscc, pkg); diff --git a/modules/ims_charging/Ro_data.h b/modules/ims_charging/Ro_data.h index 26dd0dc327f..5ac3efab057 100644 --- a/modules/ims_charging/Ro_data.h +++ b/modules/ims_charging/Ro_data.h @@ -362,14 +362,21 @@ typedef struct { uint32_t cc_output_octets; } granted_services_unit_t; +typedef struct { + uint32_t address_type; + str* server_address; +} redirect_server_t; + typedef struct { uint32_t action; + redirect_server_t *redirect_server; } final_unit_indication_t; typedef struct { granted_services_unit_t *granted_service_unit; uint32_t validity_time; final_unit_indication_t *final_unit_action; + uint32_t resultcode; } multiple_services_credit_control_t; typedef struct { diff --git a/modules/ims_charging/ccr.c b/modules/ims_charging/ccr.c index 82e5ae80aae..2adb404116d 100644 --- a/modules/ims_charging/ccr.c +++ b/modules/ims_charging/ccr.c @@ -277,6 +277,7 @@ Ro_CCA_t *Ro_parse_CCA_avps(AAAMessage *cca) { mscc->final_unit_action = fui; mscc->final_unit_action->action = -1; + mscc->final_unit_action->redirect_server = 0; AAA_AVP_LIST* avp_list = &cca->avpList; AAA_AVP_LIST mscc_avp_list; @@ -321,6 +322,9 @@ Ro_CCA_t *Ro_parse_CCA_avps(AAAMessage *cca) { case AVP_Validity_Time: mscc->validity_time = get_4bytes(mscc_avp->data.s); break; + case AVP_Result_Code: + mscc->resultcode = get_4bytes(mscc_avp->data.s); + break; case AVP_Final_Unit_Indication: y = cdp_avp->cdp->AAAUngroupAVPS(mscc_avp->data); z = y.head; @@ -329,6 +333,33 @@ Ro_CCA_t *Ro_parse_CCA_avps(AAAMessage *cca) { case AVP_Final_Unit_Action: mscc->final_unit_action->action = get_4bytes(z->data.s); break; + case AVP_Redirect_Server: + LM_DBG("Received redirect server\n"); + redirect_server_t* redirect_server_info = 0; + mem_new(redirect_server_info, sizeof (redirect_server_t), pkg); + mscc->final_unit_action->redirect_server = redirect_server_info; + + AAA_AVP_LIST yy; + AAA_AVP *zz; + yy = cdp_avp->cdp->AAAUngroupAVPS(z->data); + zz = yy.head; + while (zz) { + switch (zz->code) { + case AVP_Redirect_Address_Type: + LM_DBG("Received redirect address type\n"); + mscc->final_unit_action->redirect_server->address_type = get_4bytes(zz->data.s); + break; + case AVP_Redirect_Server_Address: + LM_DBG("Received redirect server address of [%.*s]\n", zz->data.len, zz->data.s); + str_dup_ptr(redirect_server_info->server_address, zz->data, pkg); + break; + default: + LM_ERR("Unsupported Redirect Server AVP with code:[%d]\n", zz->code); + } + zz = zz->next; + cdp_avp->cdp->AAAFreeAVPList(&yy); + } + break; default: LM_ERR("Unsupported Final Unit Indication AVP.\n"); } diff --git a/modules/ims_charging/ims_ro.c b/modules/ims_charging/ims_ro.c index 222aa359586..15172d4e2bb 100644 --- a/modules/ims_charging/ims_ro.c +++ b/modules/ims_charging/ims_ro.c @@ -64,6 +64,7 @@ extern int video_rating_group; static int create_cca_return_code(int result); static int create_cca_result_code(int result); +static int create_cca_fui_avps(int action, str* redirecturi); static void resume_on_initial_ccr(int is_timeout, void *param, AAAMessage *cca, long elapsed_msecs); static void resume_on_interim_ccr(int is_timeout, void *param, AAAMessage *cca, long elapsed_msecs); static void resume_on_termination_ccr(int is_timeout, void *param, AAAMessage *cca, long elapsed_msecs); @@ -1246,6 +1247,8 @@ static void resume_on_initial_ccr(int is_timeout, void *param, AAAMessage *cca, struct cell *t = NULL; struct session_setup_data *ssd = (struct session_setup_data *) param; int error_code = RO_RETURN_ERROR; + str *redirecturi = 0; + int fui_action = 0; if (is_timeout) { counter_inc(ims_charging_cnts_h.ccr_timeouts); @@ -1289,7 +1292,7 @@ static void resume_on_initial_ccr(int is_timeout, void *param, AAAMessage *cca, if (!ro_cca_data) { LM_ERR("Could not parse CCA message response.\n"); error_code = RO_RETURN_ERROR; - create_cca_result_code(0); + create_cca_result_code(0); goto error0; } @@ -1302,6 +1305,40 @@ static void resume_on_initial_ccr(int is_timeout, void *param, AAAMessage *cca, goto error1; } + if (ro_cca_data->mscc->final_unit_action) { + fui_action = ro_cca_data->mscc->final_unit_action->action; + + if (fui_action == AVP_Final_Unit_Action_Redirect) { + if (ro_cca_data->mscc->final_unit_action->redirect_server) { + LM_DBG("FUI with action: [%d]", ro_cca_data->mscc->final_unit_action->action); + + if (ro_cca_data->mscc->final_unit_action->action == AVP_Final_Unit_Action_Redirect) { + LM_DBG("Have REDIRECT action with address type of [%d]\n", ro_cca_data->mscc->final_unit_action->redirect_server->address_type); + if (ro_cca_data->mscc->final_unit_action->redirect_server->address_type == AVP_Redirect_Address_Type_SIP_URI) { + LM_DBG("SIP URI for redirect is [%.*s] with len of %d\n", + ro_cca_data->mscc->final_unit_action->redirect_server->server_address->len, ro_cca_data->mscc->final_unit_action->redirect_server->server_address->s, + ro_cca_data->mscc->final_unit_action->redirect_server->server_address->len); + redirecturi = ro_cca_data->mscc->final_unit_action->redirect_server->server_address; + } else { + LM_DBG("we don't cater for any redirect action which is not a SIP URI... ignoring [%d]\n", ro_cca_data->mscc->final_unit_action->redirect_server->address_type); + } + } else { + LM_DBG("ignoring final unit action which is not REDIRECT - [%d]\n", fui_action); + } + } + } + } + + /* create the AVPs cca_redirect_uri and cca_fui_action for export to cfg file */ + create_cca_fui_avps(fui_action, redirecturi); + + /* check result code at mscc level */ + if (ro_cca_data->mscc->resultcode != 2001) { + LM_DBG("CCA failure at MSCC level with resultcode [%d]\n", ro_cca_data->mscc->resultcode); + error_code = RO_RETURN_FALSE; + goto error1; + } + LM_DBG("Valid CCA response with time chunk of [%i] and validity [%i]\n", ro_cca_data->mscc->granted_service_unit->cc_time, ro_cca_data->mscc->validity_time); @@ -1451,8 +1488,40 @@ static int create_cca_result_code(int result) { return 1; } +static int create_cca_fui_avps(int action, str* redirecturi) { + int_str action_avp_val, action_avp_name, redirecturi_avp_val, redirecturi_avp_name; + action_avp_name.s.s = RO_AVP_CCA_FUI_ACTION; + action_avp_name.s.len = RO_AVP_CCA_FUI_ACTION_LENGTH; + redirecturi_avp_name.s.s = RO_AVP_CCA_FUI_REDIRECT_URI; + redirecturi_avp_name.s.len = RO_AVP_CCA_FUI_REDIRECT_URI_LENGTH; + char buf[10]; + int rc; + + action_avp_val.n = action; + action_avp_val.s.len = snprintf(buf, 10, "%i", action); + action_avp_val.s.s = buf; + rc = add_avp(AVP_NAME_STR|AVP_VAL_STR, action_avp_name, action_avp_val); + if (rc < 0) + LM_ERR("Couldn't create ["RO_AVP_CCA_FUI_ACTION"] AVP\n"); + else + LM_DBG("Created AVP ["RO_AVP_CCA_FUI_ACTION"] successfully: value=[%d]\n", action); + + if (redirecturi && redirecturi->len >0 && redirecturi->s) { + redirecturi_avp_val.s.len = redirecturi->len; + redirecturi_avp_val.s.s = redirecturi->s; + + rc = add_avp(AVP_NAME_STR|AVP_VAL_STR, redirecturi_avp_name, redirecturi_avp_val); + + if (rc < 0) + LM_ERR("Couldn't create ["RO_AVP_CCA_FUI_REDIRECT_URI"] AVP\n"); + else + LM_DBG("Created AVP ["RO_AVP_CCA_FUI_REDIRECT_URI"] successfully: value=[%.*s]\n", redirecturi->len, redirecturi->s); + } + + return 1; +} static int get_mac_avp_value(struct sip_msg *msg, str *value) { str mac_avp_name_str = str_init(RO_MAC_AVP_NAME); diff --git a/modules/ims_charging/mod.h b/modules/ims_charging/mod.h index bb52f5ea232..9f736a121a5 100644 --- a/modules/ims_charging/mod.h +++ b/modules/ims_charging/mod.h @@ -48,6 +48,12 @@ #define RO_AVP_CCA_RESULT_CODE "cca_result_code" #define RO_AVP_CCA_RESULT_CODE_LENGTH 15 +#define RO_AVP_CCA_FUI_ACTION "cca_fui_action" +#define RO_AVP_CCA_FUI_ACTION_LENGTH 14 + +#define RO_AVP_CCA_FUI_REDIRECT_URI "cca_redirect_uri" +#define RO_AVP_CCA_FUI_REDIRECT_URI_LENGTH 16 + #define RO_MAC_AVP_NAME "$avp(ro_mac_value)" #define DB_DEFAULT_UPDATE_PERIOD 60