Пример #1
0
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;

}
Пример #2
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;
}
Пример #6
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;
}
Пример #10
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;
}
Пример #12
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;
}
Пример #13
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;
}
Пример #14
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;
}