int dcca_cb_put_value_to_avp(struct avp * msg, struct dict_object * avp, union avp_value * value) { struct avp * a = NULL; CHECK_FCT( fd_msg_avp_new ( avp, 0, &a ) ); CHECK_FCT( fd_msg_avp_setvalue( a, value ) ); CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, a ) ); return 0; }
/* Perform a conversion between ipv6 in BCD to AVP served-party-ip-address */ int s6a_add_ipv6_address ( struct avp *avp, const char *ipv6_addr) { struct avp *child_avp; union avp_value value; uint8_t ipv6[18]; struct in6_addr sin6; if (ipv6_addr == NULL) { return -1; } memset (&sin6, 0, sizeof (struct in6_addr)); /* * This is an IPv6 family -> ipv6 buffer should start with 0x0002 */ ipv6[0] = 0x00; ipv6[1] = 0x02; if (inet_pton (AF_INET6, ipv6_addr, &sin6) == -1) { fprintf (stderr, "INET6 address conversion has failed\n"); return -1; } /* * If the IPV6 address is 0:0:0:0:0:0:0:0 then we don't add it to the * * * * served-party ip address and consider the ip address can be dynamically * * * * allocated. */ if (!IN6_IS_ADDR_UNSPECIFIED (sin6.s6_addr32)) { memcpy (&ipv6[2], &sin6.s6_addr, 16); CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_served_party_ip_addr, 0, &child_avp)); value.os.data = ipv6; value.os.len = 18; CHECK_FCT (fd_msg_avp_setvalue (child_avp, &value)); CHECK_FCT (fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, child_avp)); return 0; } return -1; }
/* Perform a conversion between ipv4 in BCD to AVP served-party-ip-address */ int s6a_add_ipv4_address ( struct avp *avp, const char *ipv4_addr) { struct avp *child_avp; union avp_value value; uint8_t ipv4[6]; /* Converted IPv4 address with family */ in_addr_t sin; if (ipv4_addr == NULL) { return -1; } /* * This is an IPv4 family -> ipv4 buffer should start with 0x0001 */ ipv4[0] = 0x00; ipv4[1] = 0x01; sin = inet_addr (ipv4_addr); /* * No need to add the address if it is an any address */ if (sin != INADDR_ANY) { memcpy (&ipv4[2], &sin, 4); CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_served_party_ip_addr, 0, &child_avp)); value.os.data = ipv4; value.os.len = 6; CHECK_FCT (fd_msg_avp_setvalue (child_avp, &value)); CHECK_FCT (fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, child_avp)); return 0; } /* * No IP address added to AVP */ return -1; }
int s6a_add_subscription_data_avp ( struct msg *message, mysql_ul_ans_t * mysql_ans) { int ret = -1, i = 0; mysql_pdn_t *pdns = NULL; uint8_t nb_pdns = 0; struct avp *avp = NULL, *child_avp = NULL; union avp_value value; if (mysql_ans == NULL) { return -1; } ret = hss_mysql_query_pdns (mysql_ans->imsi, &pdns, &nb_pdns); if (ret != 0) { /* * mysql query failed: * * * * - maybe no more memory * * * * - maybe user is not known (should have failed before) * * * * - maybe imsi has no EPS subscribed */ goto out; } if (nb_pdns == 0) { /* * No PDN for this user -> DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION */ return -1; } /* * Create the Subscription-Data AVP */ CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_subscription_data, 0, &avp)); { uint8_t msisdn_len = strlen (mysql_ans->msisdn); /* * The MSISDN is known in the HSS, add it to the subscription data */ if (msisdn_len > 0) { CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_msisdn, 0, &child_avp)); value.os.data = (uint8_t *) mysql_ans->msisdn; value.os.len = msisdn_len; CHECK_FCT (fd_msg_avp_setvalue (child_avp, &value)); CHECK_FCT (fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, child_avp)); } } /* * We have to include the acess-restriction-data if the value stored in DB * * * * indicates that at least one restriction is applied to the USER. */ if (mysql_ans->access_restriction != 0) { CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_access_restriction_data, 0, &child_avp)); value.u32 = (uint32_t) mysql_ans->access_restriction; CHECK_FCT (fd_msg_avp_setvalue (child_avp, &value)); CHECK_FCT (fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, child_avp)); } /* * Add the Subscriber-Status to the list of AVP. * * * * It shall indicate if the service is barred or granted. * * * * TODO: normally this parameter comes from DB... */ CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_subscriber_status, 0, &child_avp)); /* * SERVICE_GRANTED */ value.u32 = 0; CHECK_FCT (fd_msg_avp_setvalue (child_avp, &value)); CHECK_FCT (fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, child_avp)); /* * Add the Network-Access-Mode to the list of AVP. * * * * LTE Standalone HSS/MME: ONLY_PACKET. */ CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_network_access_mode, 0, &child_avp)); /* * SERVICE_GRANTED */ value.u32 = 2; CHECK_FCT (fd_msg_avp_setvalue (child_avp, &value)); CHECK_FCT (fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, child_avp)); /* * Add the AMBR to list of AVPs */ { struct avp *bandwidth; CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_ambr, 0, &child_avp)); /* * Uplink bandwidth */ CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_max_bandwidth_ul, 0, &bandwidth)); value.u32 = mysql_ans->aggr_ul; CHECK_FCT (fd_msg_avp_setvalue (bandwidth, &value)); CHECK_FCT (fd_msg_avp_add (child_avp, MSG_BRW_LAST_CHILD, bandwidth)); /* * Downlink bandwidth */ CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_max_bandwidth_dl, 0, &bandwidth)); value.u32 = mysql_ans->aggr_dl; CHECK_FCT (fd_msg_avp_setvalue (bandwidth, &value)); CHECK_FCT (fd_msg_avp_add (child_avp, MSG_BRW_LAST_CHILD, bandwidth)); CHECK_FCT (fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, child_avp)); } /* * Add the APN-Configuration-Profile only if at least one APN is subscribed */ if (nb_pdns > 0) { struct avp *apn_profile; CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_apn_configuration_profile, 0, &apn_profile)); /* * Context-Identifier */ CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_context_identifier, 0, &child_avp)); value.u32 = 0; /* * TODO: this is the reference to the default APN... */ CHECK_FCT (fd_msg_avp_setvalue (child_avp, &value)); CHECK_FCT (fd_msg_avp_add (apn_profile, MSG_BRW_LAST_CHILD, child_avp)); /* * All-APN-Configurations-Included-Indicator */ CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_all_apn_conf_inc_ind, 0, &child_avp)); value.u32 = 0; CHECK_FCT (fd_msg_avp_setvalue (child_avp, &value)); CHECK_FCT (fd_msg_avp_add (apn_profile, MSG_BRW_LAST_CHILD, child_avp)); for (i = 0; i < nb_pdns; i++) { struct avp *apn_configuration; mysql_pdn_t *pdn_elm; pdn_elm = &pdns[i]; /* * APN-Configuration */ CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_apn_configuration, 0, &apn_configuration)); /* * Context-Identifier */ CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_context_identifier, 0, &child_avp)); value.u32 = i; CHECK_FCT (fd_msg_avp_setvalue (child_avp, &value)); CHECK_FCT (fd_msg_avp_add (apn_configuration, MSG_BRW_LAST_CHILD, child_avp)); /* * PDN-Type */ CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_pdn_type, 0, &child_avp)); value.u32 = pdn_elm->pdn_type; CHECK_FCT (fd_msg_avp_setvalue (child_avp, &value)); CHECK_FCT (fd_msg_avp_add (apn_configuration, MSG_BRW_LAST_CHILD, child_avp)); if ((pdn_elm->pdn_type == IPV4) || (pdn_elm->pdn_type == IPV4_OR_IPV6) || (pdn_elm->pdn_type == IPV4V6)) { s6a_add_ipv4_address (apn_configuration, pdn_elm->pdn_address.ipv4_address); } if ((pdn_elm->pdn_type == IPV6) || (pdn_elm->pdn_type == IPV4_OR_IPV6) || (pdn_elm->pdn_type == IPV4V6)) { s6a_add_ipv6_address (apn_configuration, pdn_elm->pdn_address.ipv6_address); } /* * Service-Selection */ CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_service_selection, 0, &child_avp)); value.os.data = (uint8_t *) pdn_elm->apn; value.os.len = strlen (pdn_elm->apn); CHECK_FCT (fd_msg_avp_setvalue (child_avp, &value)); CHECK_FCT (fd_msg_avp_add (apn_configuration, MSG_BRW_LAST_CHILD, child_avp)); /* * Add the eps subscribed qos profile */ { struct avp *qos_profile, *allocation_priority; CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_eps_subscribed_qos_profile, 0, &qos_profile)); CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_qos_class_identifier, 0, &child_avp)); /* * For a QCI_1 */ value.u32 = (uint32_t) pdn_elm->qci; CHECK_FCT (fd_msg_avp_setvalue (child_avp, &value)); CHECK_FCT (fd_msg_avp_add (qos_profile, MSG_BRW_LAST_CHILD, child_avp)); /* * Allocation retention priority */ { CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_allocation_retention_priority, 0, &allocation_priority)); /* * Priority level */ CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_priority_level, 0, &child_avp)); value.u32 = (uint32_t) pdn_elm->priority_level; CHECK_FCT (fd_msg_avp_setvalue (child_avp, &value)); CHECK_FCT (fd_msg_avp_add (allocation_priority, MSG_BRW_LAST_CHILD, child_avp)); /* * Pre-emption-capability */ CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_pre_emption_capability, 0, &child_avp)); value.u32 = (uint32_t) pdn_elm->pre_emp_cap; CHECK_FCT (fd_msg_avp_setvalue (child_avp, &value)); CHECK_FCT (fd_msg_avp_add (allocation_priority, MSG_BRW_LAST_CHILD, child_avp)); /* * Pre-emption-vulnerability */ CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_pre_emption_vulnerability, 0, &child_avp)); value.u32 = (uint32_t) pdn_elm->pre_emp_vul; CHECK_FCT (fd_msg_avp_setvalue (child_avp, &value)); CHECK_FCT (fd_msg_avp_add (allocation_priority, MSG_BRW_LAST_CHILD, child_avp)); CHECK_FCT (fd_msg_avp_add (qos_profile, MSG_BRW_LAST_CHILD, allocation_priority)); } CHECK_FCT (fd_msg_avp_add (apn_configuration, MSG_BRW_LAST_CHILD, qos_profile)); } /* * Add the AMBR to list of AVPs */ { struct avp *bandwidth; CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_ambr, 0, &bandwidth)); /* * Uplink bandwidth */ CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_max_bandwidth_ul, 0, &child_avp)); value.u32 = (uint32_t) pdn_elm->aggr_ul; CHECK_FCT (fd_msg_avp_setvalue (child_avp, &value)); CHECK_FCT (fd_msg_avp_add (bandwidth, MSG_BRW_LAST_CHILD, child_avp)); /* * Downlink bandwidth */ CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_max_bandwidth_dl, 0, &child_avp)); value.u32 = (uint32_t) pdn_elm->aggr_dl; CHECK_FCT (fd_msg_avp_setvalue (child_avp, &value)); CHECK_FCT (fd_msg_avp_add (bandwidth, MSG_BRW_LAST_CHILD, child_avp)); CHECK_FCT (fd_msg_avp_add (apn_configuration, MSG_BRW_LAST_CHILD, bandwidth)); } CHECK_FCT (fd_msg_avp_add (apn_profile, MSG_BRW_LAST_CHILD, apn_configuration)); } CHECK_FCT (fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, apn_profile)); } /* * Subscribed-Periodic-RAU-TAU-Timer */ CHECK_FCT (fd_msg_avp_new (s6a_cnf.dataobj_s6a_subscribed_rau_tau_timer, 0, &child_avp)); /* * Request an RAU/TAU update every x seconds */ value.u32 = (uint32_t) mysql_ans->rau_tau; CHECK_FCT (fd_msg_avp_setvalue (child_avp, &value)); CHECK_FCT (fd_msg_avp_add (avp, MSG_BRW_LAST_CHILD, child_avp)); /* * Add the AVP to the message */ CHECK_FCT (fd_msg_avp_add (message, MSG_BRW_LAST_CHILD, avp)); out: if (pdns) { free (pdns); } return ret; }
/* 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; }
//Called to send a UAR int test_sip_SAR_cb() { struct dict_object * sar_model=NULL; struct msg * message=NULL; struct avp *avp=NULL; union avp_value value; //Fake values START char *sip_aor="sip:[email protected]"; size_t aor_len=strlen(sip_aor); char *destination_realm="tera.ics.keio.ac.jp"; size_t destination_realmlen=strlen(destination_realm); char *destination_host="suika.tera.ics.keio.ac.jp"; size_t destination_hostlen=strlen(destination_host); char *username="******"; size_t usernamelen=strlen(username); char *sipserveruri="sip:[email protected]"; size_t sipserverurilen=strlen(sipserveruri); // char *visitednetwork="Pink"; //size_t visitednetworklen=strlen(visitednetwork); //int registrationtype = 2; int data_already_available=0; int assignment_type=0; //Fake values STOP //Create the base message for an RTR CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Server-Assignment-Request", &sar_model, ENOENT) ); CHECK_FCT( fd_msg_new (sar_model, 0, &message)); // Create a new session { CHECK_FCT( fd_msg_new_session( message, (os0_t)"appsip", CONSTSTRLEN("appsip") ) ); } //Add the Auth-Application-Id { CHECK_FCT( fd_msg_avp_new ( sip_dict.Auth_Application_Id, 0, &avp ) ); value.i32 = 6; CHECK_FCT( fd_msg_avp_setvalue ( avp, &value ) ); CHECK_FCT( fd_msg_avp_add ( message, MSG_BRW_LAST_CHILD, avp) ); } //Auth_Session_State { CHECK_FCT( fd_msg_avp_new ( sip_dict.Auth_Session_State, 0, &avp ) ); value.i32=1; CHECK_FCT( fd_msg_avp_setvalue( avp, &value ) ); CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_LAST_CHILD, avp ) ); } //Origin_Host & Origin_Realm CHECK_FCT( fd_msg_add_origin ( message, 0 )); //Destination_Host { CHECK_FCT( fd_msg_avp_new ( sip_dict.Destination_Host, 0, &avp ) ); value.os.data=(unsigned char *)destination_host; value.os.len=destination_hostlen; CHECK_FCT( fd_msg_avp_setvalue( avp, &value ) ); CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_LAST_CHILD, avp ) ); } //Destination_Realm { CHECK_FCT( fd_msg_avp_new ( sip_dict.Destination_Realm, 0, &avp ) ); value.os.data=(unsigned char *)destination_realm; value.os.len=destination_realmlen; CHECK_FCT( fd_msg_avp_setvalue( avp, &value ) ); CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_LAST_CHILD, avp ) ); } //SIP_AOR { CHECK_FCT( fd_msg_avp_new ( sip_dict.SIP_AOR, 0, &avp ) ); value.os.data=(unsigned char *)sip_aor; value.os.len=aor_len; CHECK_FCT( fd_msg_avp_setvalue( avp, &value ) ); CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_LAST_CHILD, avp ) ); } //Username { CHECK_FCT( fd_msg_avp_new ( sip_dict.User_Name, 0, &avp ) ); value.os.data=(unsigned char *)username; value.os.len=usernamelen; CHECK_FCT( fd_msg_avp_setvalue( avp, &value ) ); CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_LAST_CHILD, avp ) ); } //SIP_User_Data_Already_Available { CHECK_FCT( fd_msg_avp_new ( sip_dict.SIP_User_Data_Already_Available, 0, &avp ) ); value.i32=data_already_available; CHECK_FCT( fd_msg_avp_setvalue( avp, &value ) ); CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_LAST_CHILD, avp ) ); } //SIP_Server_Assignment_Type; { CHECK_FCT( fd_msg_avp_new ( sip_dict.SIP_Server_Assignment_Type, 0, &avp ) ); value.i32=assignment_type; CHECK_FCT( fd_msg_avp_setvalue( avp, &value ) ); CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_LAST_CHILD, avp ) ); } //SIP_server_uri { CHECK_FCT( fd_msg_avp_new ( sip_dict.SIP_Server_URI, 0, &avp ) ); value.os.data=(unsigned char *)sipserveruri; value.os.len=sipserverurilen; CHECK_FCT( fd_msg_avp_setvalue( avp, &value ) ); CHECK_FCT( fd_msg_avp_add( message, MSG_BRW_LAST_CHILD, avp ) ); } CHECK_FCT( fd_msg_send( &message, NULL, NULL )); 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; }