int get_imsi(struct msg * msg, struct avp ** avp) { struct avp * nextavp = NULL, * a = NULL; struct avp_hdr * a_hdr = NULL; struct dict_avp_data dictdata; struct avp_hdr *avp_dst; *avp = NULL; CHECK_FCT( fd_dict_getval(dcca_dict.Subscription_Id, &dictdata) ); CHECK_FCT( fd_msg_browse(msg, MSG_BRW_FIRST_CHILD, (void *)&nextavp, NULL) ); while (nextavp) { CHECK_FCT( fd_msg_avp_hdr( nextavp, &avp_dst ) ); if ( (avp_dst->avp_code == dictdata.avp_code) && (avp_dst->avp_vendor == dictdata.avp_vendor) ) { CHECK_FCT( avp_search_child ( nextavp, dcca_dict.Subscription_Id_Type, &a) ); if(a) { CHECK_FCT( fd_msg_avp_hdr( a, &a_hdr ) ); if(a_hdr->avp_value->i32 == 1) { CHECK_FCT( avp_search_child ( nextavp, dcca_dict.Subscription_Id_Data, avp) ); break; } } } /* Otherwise move to next AVP in the message */ CHECK_FCT( fd_msg_browse(nextavp, MSG_BRW_NEXT, (void *)&nextavp, NULL) ); } return 0; }
/* The callback called on new messages */ static int rtereg_out(void * cbdata, struct msg ** pmsg, struct fd_list * candidates) { struct msg * msg = *pmsg; struct avp * avp = NULL; TRACE_ENTRY("%p %p %p", cbdata, msg, candidates); CHECK_PARAMS(msg && candidates); /* Check if it is worth processing the message */ if (FD_IS_LIST_EMPTY(candidates)) { return 0; } /* Now search the AVP in the message */ CHECK_FCT( fd_msg_search_avp ( msg, rtereg_conf.avp, &avp ) ); if (avp != NULL) { struct avp_hdr * ahdr = NULL; CHECK_FCT( fd_msg_avp_hdr ( avp, &ahdr ) ); if (ahdr->avp_value != NULL) { #ifndef HAVE_REG_STARTEND int ret; /* Lock the buffer */ CHECK_POSIX( pthread_mutex_lock(&mtx) ); /* Augment the buffer if needed */ if (ahdr->avp_value->os.len >= bufsz) { CHECK_MALLOC_DO( buf = realloc(buf, ahdr->avp_value->os.len + 1), { pthread_mutex_unlock(&mtx); return ENOMEM; } );
static inline int s6a_parse_ambr(struct avp *avp_ambr, ambr_t *ambr) { struct avp *avp = NULL; struct avp_hdr *hdr; CHECK_FCT(fd_msg_browse(avp_ambr, MSG_BRW_FIRST_CHILD, &avp, NULL)); if (!avp) { /* Child avps for ambr are mandatory */ return -1; } while(avp) { CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); switch(hdr->avp_code) { case AVP_CODE_BANDWIDTH_UL: CHECK_FCT(s6a_parse_bitrate(hdr, &ambr->br_ul)); break; case AVP_CODE_BANDWIDTH_DL: CHECK_FCT(s6a_parse_bitrate(hdr, &ambr->br_dl)); break; default: return -1; } /* Go to next AVP in the grouped AVP */ CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL)); } return 0; }
static inline int s6a_parse_apn_configuration_profile(struct avp *avp_apn_conf_prof, apn_config_profile_t *apn_config_profile) { struct avp *avp = NULL; struct avp_hdr *hdr; CHECK_FCT(fd_msg_browse(avp_apn_conf_prof, MSG_BRW_FIRST_CHILD, &avp, NULL)); while(avp) { CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); switch(hdr->avp_code) { case AVP_CODE_CONTEXT_IDENTIFIER: apn_config_profile->context_identifier = hdr->avp_value->u32; break; case AVP_CODE_ALL_APN_CONFIG_INC_IND: CHECK_FCT(s6a_parse_all_apn_conf_inc_ind(hdr, &apn_config_profile->all_apn_conf_ind)); break; case AVP_CODE_APN_CONFIGURATION: { DevCheck(apn_config_profile->nb_apns < MAX_APN_PER_UE, apn_config_profile->nb_apns, MAX_APN_PER_UE, 0); CHECK_FCT(s6a_parse_apn_configuration( avp, &apn_config_profile->apn_configuration[apn_config_profile->nb_apns])); apn_config_profile->nb_apns++; } break; } /* Go to next AVP in the grouped AVP */ CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL)); } return 0; }
static inline int s6a_parse_eps_subscribed_qos_profile(struct avp *avp_qos, eps_subscribed_qos_profile_t *ptr) { struct avp *avp = NULL; struct avp_hdr *hdr; CHECK_FCT(fd_msg_browse(avp_qos, MSG_BRW_FIRST_CHILD, &avp, NULL)); while(avp) { CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); switch(hdr->avp_code) { case AVP_CODE_QCI: CHECK_FCT(s6a_parse_qci(hdr, &ptr->qci)); break; case AVP_CODE_ALLOCATION_RETENTION_PRIORITY: CHECK_FCT(s6a_parse_allocation_retention_priority(avp, &ptr->allocation_retention_priority)); break; default: return -1; } /* Go to next AVP in the grouped AVP */ CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL)); } return 0; }
int dcca_cb_read( struct msg ** msg, struct dict_object * avp, struct avp_hdr ** avp_dst ) { struct avp * a = NULL; CHECK_FCT( fd_msg_search_avp ( *msg, avp, &a) ); if (a) { CHECK_FCT( fd_msg_avp_hdr( a, avp_dst ) ); } return 0; }
int s6a_parse_experimental_result(struct avp *avp, s6a_experimental_result_t *ptr) { struct avp_hdr *hdr; struct avp *child_avp = NULL; if (!avp) { return EINVAL; } CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); DevAssert(hdr->avp_code == AVP_CODE_EXPERIMENTAL_RESULT); CHECK_FCT(fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &child_avp, NULL)); while(child_avp) { CHECK_FCT(fd_msg_avp_hdr(child_avp, &hdr)); switch(hdr->avp_code) { case AVP_CODE_EXPERIMENTAL_RESULT_CODE: S6A_ERROR("Got experimental error %u:%s\n", hdr->avp_value->u32, experimental_retcode_2_string(hdr->avp_value->u32)); if (ptr) { *ptr = (s6a_experimental_result_t)hdr->avp_value->u32; } break; case AVP_CODE_VENDOR_ID: DevCheck(hdr->avp_value->u32 == 10415, hdr->avp_value->u32, AVP_CODE_VENDOR_ID, 10415); break; default: return -1; } /* Go to next AVP in the grouped AVP */ CHECK_FCT(fd_msg_browse(child_avp, MSG_BRW_NEXT, &child_avp, NULL)); } return 0; }
int s6a_parse_subscription_data(struct avp *avp_subscription_data, subscription_data_t *subscription_data) { struct avp *avp = NULL; struct avp_hdr *hdr; CHECK_FCT(fd_msg_browse(avp_subscription_data, MSG_BRW_FIRST_CHILD, &avp, NULL)); while(avp) { CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); switch(hdr->avp_code) { case AVP_CODE_SUBSCRIBER_STATUS: CHECK_FCT(s6a_parse_subscriber_status(hdr, &subscription_data->subscriber_status)); break; case AVP_CODE_MSISDN: CHECK_FCT(s6a_parse_msisdn(hdr, subscription_data->msisdn, &subscription_data->msisdn_length)); break; case AVP_CODE_NETWORK_ACCESS_MODE: CHECK_FCT(s6a_parse_network_access_mode(hdr, &subscription_data->access_mode)); break; case AVP_CODE_ACCESS_RESTRICTION_DATA: CHECK_FCT(s6a_parse_access_restriction_data(hdr, &subscription_data->access_restriction)); break; case AVP_CODE_AMBR: CHECK_FCT(s6a_parse_ambr(avp, &subscription_data->subscribed_ambr)); break; case AVP_CODE_APN_CONFIGURATION_PROFILE: CHECK_FCT(s6a_parse_apn_configuration_profile(avp, &subscription_data->apn_config_profile)); break; case AVP_CODE_SUBSCRIBED_PERIODIC_RAU_TAU_TIMER: subscription_data->rau_tau_timer = hdr->avp_value->u32; break; default: return -1; } /* Go to next AVP in the grouped AVP */ CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL)); } return 0; }
static inline int s6a_parse_allocation_retention_priority(struct avp *avp_arp, allocation_retention_priority_t *ptr) { struct avp *avp = NULL; struct avp_hdr *hdr; /* If the Pre-emption-Capability AVP is not present in the * Allocation-Retention-Priority AVP, the default value shall be * PRE-EMPTION_CAPABILITY_DISABLED (1). */ ptr->pre_emp_capability = PRE_EMPTION_CAPABILITY_DISABLED; /* If the Pre-emption-Vulnerability AVP is not present in the * Allocation-Retention-Priority AVP, the default value shall be * PRE-EMPTION_VULNERABILITY_ENABLED (0). */ ptr->pre_emp_vulnerability = PRE_EMPTION_VULNERABILITY_ENABLED; CHECK_FCT(fd_msg_browse(avp_arp, MSG_BRW_FIRST_CHILD, &avp, NULL)); while(avp) { CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); switch(hdr->avp_code) { case AVP_CODE_PRIORITY_LEVEL: CHECK_FCT(s6a_parse_priority_level(hdr, &ptr->priority_level)); break; case AVP_CODE_PRE_EMPTION_CAPABILITY: CHECK_FCT(s6a_parse_pre_emp_capability(hdr, &ptr->pre_emp_capability)); break; case AVP_CODE_PRE_EMPTION_VULNERABILITY: CHECK_FCT(s6a_parse_pre_emp_vulnerability(hdr, &ptr->pre_emp_vulnerability)); break; default: return -1; } /* Go to next AVP in the grouped AVP */ CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL)); } return 0; }
int avp_search_child ( struct avp * msg, struct dict_object * what, struct avp ** avp ) { struct avp * nextavp; struct dict_avp_data dictdata; struct avp_hdr *avp_dst; TRACE_ENTRY("%p %p %p", msg, what, avp); *avp = NULL; CHECK_FCT( fd_dict_getval(what, &dictdata) ); /* Loop on all top AVPs */ CHECK_FCT( fd_msg_browse(msg, MSG_BRW_FIRST_CHILD, (void *)&nextavp, NULL) ); while (nextavp) { CHECK_FCT( fd_msg_avp_hdr( nextavp, &avp_dst ) ); if ( (avp_dst->avp_code == dictdata.avp_code) && (avp_dst->avp_vendor == dictdata.avp_vendor) ) { break; } /* Otherwise move to next AVP in the message */ CHECK_FCT( fd_msg_browse(nextavp, MSG_BRW_NEXT, (void *)&nextavp, NULL) ); } if (avp) *avp = nextavp; if (avp && nextavp) { struct dictionary * dict; CHECK_FCT( fd_dict_getdict( what, &dict) ); CHECK_FCT_DO( fd_msg_parse_dict( nextavp, dict, NULL ), /* nothing */ ); } if (avp || nextavp) return 0; else return ENOENT; }
static inline int s6a_parse_apn_configuration(struct avp *avp_apn_conf_prof, apn_configuration_t *apn_config) { struct avp *avp = NULL; struct avp_hdr *hdr; CHECK_FCT(fd_msg_browse(avp_apn_conf_prof, MSG_BRW_FIRST_CHILD, &avp, NULL)); while(avp) { CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); switch(hdr->avp_code) { case AVP_CODE_CONTEXT_IDENTIFIER: apn_config->context_identifier = hdr->avp_value->u32; break; case AVP_CODE_SERVED_PARTY_IP_ADDRESS: if (apn_config->nb_ip_address == 2) { DevMessage("Only two IP addresses can be provided"); } CHECK_FCT(s6a_parse_ip_address(hdr, &apn_config->ip_address[apn_config->nb_ip_address])); apn_config->nb_ip_address++; break; case AVP_CODE_PDN_TYPE: CHECK_FCT(s6a_parse_pdn_type(hdr, &apn_config->pdn_type)); break; case AVP_CODE_SERVICE_SELECTION: CHECK_FCT(s6a_parse_service_selection(hdr, apn_config->service_selection, &apn_config->service_selection_length)); break; case AVP_CODE_EPS_SUBSCRIBED_QOS_PROFILE: CHECK_FCT(s6a_parse_eps_subscribed_qos_profile(avp, &apn_config->subscribed_qos)); break; case AVP_CODE_AMBR: CHECK_FCT(s6a_parse_ambr(avp, &apn_config->ambr)); break; } /* Go to next AVP in the grouped AVP */ CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL)); } return 0; }
/* Callback for incoming Test-Request messages */ static int ta_tr_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act) { struct msg *ans, *req; struct avp * src = NULL; struct avp_hdr * hdr = NULL; UsageServerSession* mi; TRACE_ENTRY("%p %p %p %p", msg, avp, sess, act); if (msg == NULL) return EINVAL; /* Value of Origin-Host */ fprintf(stderr, "Request received from "); CHECK_FCT( fd_msg_search_avp ( *msg, ta_origin_host, &src) ); if (src) { CHECK_FCT( fd_msg_avp_hdr( src, &hdr ) ); fprintf(stderr, "'%.*s'", (int)hdr->avp_value->os.len, hdr->avp_value->os.data); } else { fprintf(stderr, "no_Origin-Host"); } fprintf(stderr, ", replying...\n"); //get or create the session/session state req = *msg; /* Create answer header */ CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, msg, 0 ) ); ans = *msg; d_req_type reqType; //get the op type CHECK_FCT( fd_msg_search_avp ( req, ta_avp_optype, &src) ); CHECK_FCT( fd_msg_avp_hdr( src, &hdr ) ); reqType = hdr->avp_value->i32; if (reqType==d_start){ //create the session state mi= usageserver_session_alloc(); mi->leftQuota = DUMMY_INIT_QUOTA; }else{ //get the session state fd_sess_state_retrieve(ta_cli_reg, sess, &mi); } if (reqType!=d_start){//for update, stop, need to update the leftQuota //update the left quota in session state, according to the used quota avp in req CHECK_FCT( fd_msg_search_avp ( req, ta_avp_usedQuota, &src) ); CHECK_FCT( fd_msg_avp_hdr( src, &hdr ) ); uint64_t usedQuota = hdr->avp_value->u64; if (mi->leftQuota>=usedQuota){ mi->leftQuota-=usedQuota; }else{ fprintf(stderr, "fatal, the used should not be larger then the granted last time."); mi->leftQuota=0; } } if (reqType!=d_stop){//for start, update, need to reply with grantedQuota //set the granted quota AVP according to requested quota and left quota in session state CHECK_FCT( fd_msg_search_avp ( req, ta_avp_requestQuota, &src) ); CHECK_FCT( fd_msg_avp_hdr( src, &hdr ) ); uint64_t reqAmt = hdr->avp_value->u64; uint64_t grantAmt=0; if (mi->leftQuota>=reqAmt){ grantAmt = reqAmt; }else{ grantAmt = mi->leftQuota; } hdr->avp_value->u64 = grantAmt; CHECK_FCT( fd_msg_avp_new ( ta_avp_grantedQuota, 0, &avp ) ); CHECK_FCT( fd_msg_avp_setvalue( avp, hdr->avp_value ) ); CHECK_FCT( fd_msg_avp_add( ans, MSG_BRW_LAST_CHILD, avp ) ); fprintf(stderr, "add granted quota avp, %llu.\n", grantAmt); } fprintf(stderr, "session:leftQuota:%llu\n", mi->leftQuota); /* Set the Origin-Host, Origin-Realm, Result-Code AVPs */ CHECK_FCT( fd_msg_rescode_set( ans, "DIAMETER_SUCCESS", NULL, NULL, 1 ) ); //save the session state fd_sess_state_store(ta_cli_reg, sess, &mi); /* Send the answer */ CHECK_FCT( fd_msg_send( msg, NULL, NULL ) ); return 0; }
static int dcca_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act) { struct msg * m; struct avp_hdr * val_app_id = NULL, * val_rt = NULL, * val_rn = NULL, * val_io = NULL, * val_oo = NULL, *val_imsi = NULL; struct avp *groupedavp = NULL, *groupedavp2 = NULL; union avp_value validity_time, total_octets, result_code, rating_group; struct avp * a = NULL, * aa = NULL; int input_octets = 0, output_octets = 0; char* imsi = NULL; LOG_N("CCR processor"); TRACE_ENTRY("%p %p %p %p", msg, avp, sess, act); if (msg == NULL) return EINVAL; // // Read AVPs from request // // CHECK_FCT( dcca_read_avps_from_message(*msg) ); // Read AVPs CHECK_FCT( dcca_cb_read(msg, dcca_dict.Auth_Application_Id, &val_app_id) ); CHECK_FCT( dcca_cb_read(msg, dcca_dict.CC_Request_Type, &val_rt) ); CHECK_FCT( dcca_cb_read(msg, dcca_dict.CC_Request_Number, &val_rn) ); // Read IMSI CHECK_FCT( get_imsi(*msg, &a) ); if (a) { CHECK_FCT( fd_msg_avp_hdr( a, &val_imsi ) ); int len = val_imsi->avp_value->os.len; imsi = malloc(len * sizeof(char)); int i; for (i = 0; i < len; i++) { imsi[i] = val_imsi->avp_value->os.data[i]; } imsi[len] = 0; } // Read Input / Output Octets CHECK_FCT( fd_msg_search_avp ( *msg, dcca_dict.Multiple_Services_Credit_Control, &a) ); if (a) { CHECK_FCT( avp_search_child ( a, dcca_dict.Used_Service_Unit, &a) ); if (a) { CHECK_FCT( avp_search_child ( a, dcca_dict.CC_Input_Octets, &aa) ); if (aa) { CHECK_FCT( fd_msg_avp_hdr( aa, &val_io ) ); input_octets = val_io->avp_value->i32; } CHECK_FCT( avp_search_child ( a, dcca_dict.CC_Output_Octets, &aa) ); if (aa) { CHECK_FCT( fd_msg_avp_hdr( aa, &val_oo ) ); output_octets = val_oo->avp_value->i32; } } } LOG_N("IMSI: %s", imsi); LOG_N("IN: %i", input_octets); LOG_N("OUT: %i", output_octets); // Create response message CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, msg, 0 ) ); m = *msg; CHECK_FCT( fd_msg_rescode_set( m, "DIAMETER_SUCCESS", NULL, NULL, 1 ) ); // Put params to response CHECK_FCT( dcca_cb_put(m, dcca_dict.Auth_Application_Id, val_app_id) ); CHECK_FCT( dcca_cb_put(m, dcca_dict.CC_Request_Type, val_rt) ); CHECK_FCT( dcca_cb_put(m, dcca_dict.CC_Request_Number, val_rn) ); // Multiple Services CC Group total_octets.i64 = rest_api_vsca(imsi, input_octets, output_octets); CHECK_FCT( fd_msg_avp_new ( dcca_dict.Multiple_Services_Credit_Control, 0, &groupedavp ) ); // Granted Service Unit CHECK_FCT( fd_msg_avp_new ( dcca_dict.Granted_Service_Unit, 0, &groupedavp2 ) ); CHECK_FCT( dcca_cb_put_value_to_avp(groupedavp2, dcca_dict.CC_Total_Octets, &total_octets) ); CHECK_FCT( fd_msg_avp_add( groupedavp, MSG_BRW_LAST_CHILD, groupedavp2 ) ); // Result code result_code.i32 = 2001; CHECK_FCT( dcca_cb_put_value_to_avp(groupedavp, dcca_dict.Result_Code, &result_code) ); // Rating group rating_group.i32 = 1001; CHECK_FCT( dcca_cb_put_value_to_avp(groupedavp, dcca_dict.Rating_Group, &rating_group) ); // Validity Time validity_time.i32 = 60; CHECK_FCT( dcca_cb_put_value_to_avp(groupedavp, dcca_dict.Validity_Time, &validity_time) ); CHECK_FCT( fd_msg_avp_add( m, MSG_BRW_LAST_CHILD, groupedavp ) ); // Send the answer *act = DISP_ACT_SEND; return 0; }
/* Callback for incoming Base Accounting Accounting-Request messages */ static int acct_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act) { struct msg * m; struct avp * a = NULL; struct avp_hdr * art=NULL, *arn=NULL; /* We keep a pointer on the Accounting-Record-{Type, Number} AVPs from the query */ struct acct_record_list rl; TRACE_ENTRY("%p %p %p %p", msg, avp, sess, act); if (msg == NULL) return EINVAL; m = *msg; /* Prepare a new record list */ CHECK_FCT( acct_rec_prepare( &rl ) ); /* Maps the AVPs from the query with this record list */ CHECK_FCT( acct_rec_map( &rl, m ) ); /* Check that at least one AVP was mapped */ CHECK_FCT( acct_rec_validate( &rl ) ); /* Now, save these mapped AVPs in the database */ CHECK_FCT( acct_db_insert( &rl ) ); acct_rec_empty( &rl ); /* OK, we can send a positive reply now */ /* Get Accounting-Record-{Number,Type} values */ CHECK_FCT( fd_msg_search_avp ( m, acct_dict.Accounting_Record_Type, &a) ); if (a) { CHECK_FCT( fd_msg_avp_hdr( a, &art ) ); } CHECK_FCT( fd_msg_search_avp ( m, acct_dict.Accounting_Record_Number, &a) ); if (a) { CHECK_FCT( fd_msg_avp_hdr( a, &arn ) ); } /* Create the answer message */ CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, msg, 0 ) ); m = *msg; /* Set the Origin-Host, Origin-Realm, Result-Code AVPs */ CHECK_FCT( fd_msg_rescode_set( m, "DIAMETER_SUCCESS", NULL, NULL, 1 ) ); /* Add the mandatory AVPs in the ACA */ if (art) { CHECK_FCT( fd_msg_avp_new ( acct_dict.Accounting_Record_Type, 0, &a ) ); CHECK_FCT( fd_msg_avp_setvalue( a, art->avp_value ) ); CHECK_FCT( fd_msg_avp_add( m, MSG_BRW_LAST_CHILD, a ) ); } if (arn) { CHECK_FCT( fd_msg_avp_new ( acct_dict.Accounting_Record_Number, 0, &a ) ); CHECK_FCT( fd_msg_avp_setvalue( a, arn->avp_value ) ); CHECK_FCT( fd_msg_avp_add( m, MSG_BRW_LAST_CHILD, a ) ); } /* Send the answer */ *act = DISP_ACT_SEND; return 0; }