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; }
/* entry point */ static int acct_entry(char * conffile) { struct disp_when data; TRACE_ENTRY("%p", conffile); #ifndef TEST_DEBUG /* We do this differently in the test scenario */ /* Initialize the configuration and parse the file */ CHECK_FCT( acct_conf_init() ); CHECK_FCT( acct_conf_parse(conffile) ); CHECK_FCT( acct_conf_check(conffile) ); #endif /* TEST_DEBUG */ /* Now initialize the database module */ CHECK_FCT( acct_db_init() ); /* Search the AVPs we will need in this file */ CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Accounting-Record-Number", &acct_dict.Accounting_Record_Number, ENOENT) ); CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Accounting-Record-Type", &acct_dict.Accounting_Record_Type, ENOENT) ); /* Register the dispatch callbacks */ memset(&data, 0, sizeof(data)); CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Diameter Base Accounting", &data.app, ENOENT) ); CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &data.command, ENOENT) ); CHECK_FCT( fd_disp_register( acct_cb, DISP_HOW_CC, &data, NULL, NULL ) ); /* Advertise the support for the Diameter Base Accounting application in the peer */ CHECK_FCT( fd_disp_app_support ( data.app, NULL, 0, 1 ) ); return 0; }
/* The callback for load balancing the requests across the peers */ static int rt_load_balancing(void * cbdata, struct msg ** pmsg, struct fd_list * candidates) { struct fd_list *lic; struct msg * msg = *pmsg; 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; /* load balancing */ for (lic = candidates->next; lic != candidates; lic = lic->next) { struct rtd_candidate * cand = (struct rtd_candidate *) lic; struct peer_hdr *peer; long to_receive, to_send, load; int score; CHECK_FCT(fd_peer_getbyid(cand->diamid, cand->diamidlen, 0, &peer)); CHECK_FCT(fd_peer_get_load_pending(peer, &to_receive, &to_send)); load = to_receive + to_send; score = cand->score; if ((cand->score > 0) && (load >= cand->score)) cand->score = 1; else cand->score -= load; TRACE_DEBUG(INFO, "evaluated peer `%.*s', score was %d, now %d", (int)cand->diamidlen, cand->diamid, score, cand->score); } 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; }
/* 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; } );
int ui_gtk_initialize(int argc, char *argv[]) { GtkWidget *vbox; /* Create the main window */ ui_main_data.window = gtk_window_new (GTK_WINDOW_TOPLEVEL); ui_init_filters (TRUE, FALSE); // gtk_window_set_default_icon_from_file ("../analyzer.png", NULL); gtk_window_set_default_icon_name (GTK_STOCK_FIND); gtk_window_set_position (GTK_WINDOW(ui_main_data.window), GTK_WIN_POS_CENTER); gtk_window_set_default_size (GTK_WINDOW(ui_main_data.window), 1024, 800); ui_set_title(""); gtk_window_set_resizable (GTK_WINDOW(ui_main_data.window), TRUE); vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); CHECK_FCT(ui_menu_bar_create(vbox)); CHECK_FCT(ui_toolbar_create(vbox)); CHECK_FCT(ui_notebook_create(vbox)); gtk_container_add (GTK_CONTAINER(ui_main_data.window), vbox); /* Assign the destroy event */ g_signal_connect(ui_main_data.window, "destroy", ui_main_window_destroy, NULL); /* Show the application window */ gtk_widget_show_all (ui_main_data.window); g_idle_add (ui_idle_callback, NULL); return RC_OK; }
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 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; }
/* freeDiameter starting point */ int main(int argc, char * argv[]) { int ret; sigset_t sig_all; /* Block all signals from the current thread and all its future children -- we will catch everything in catch_signals */ sigfillset(&sig_all); ret = pthread_sigmask(SIG_BLOCK, &sig_all, NULL); ASSERT(ret == 0); /* Parse the command-line */ ret = main_cmdline(argc, argv); if (ret != 0) { return ret; } /* Initialize the core library */ ret = fd_core_initialize(); if (ret != 0) { fprintf(stderr, "An error occurred during freeDiameter core library initialization.\n"); return ret; } /* Set gnutls debug level ? */ if (gnutls_debug) { gnutls_global_set_log_function((gnutls_log_func)fd_gnutls_debug); gnutls_global_set_log_level (gnutls_debug); TRACE_DEBUG(INFO, "Enabled GNUTLS debug at level %d", gnutls_debug); } /* Parse the configuration file */ CHECK_FCT_DO( fd_core_parseconf(conffile), goto error ); /* Start the servers */ CHECK_FCT_DO( fd_core_start(), goto error ); /* Allow SIGINT and SIGTERM from this point to terminate the application */ CHECK_POSIX_DO( pthread_create(&signals_thr, NULL, catch_signals, NULL), goto error ); TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon initialized."); /* Now, just wait for termination */ CHECK_FCT( fd_core_wait_shutdown_complete() ); /* Just in case it was not the result of a signal, we cancel signals_thr */ fd_thr_term(&signals_thr); return 0; error: CHECK_FCT_DO( fd_core_shutdown(), ); CHECK_FCT( fd_core_wait_shutdown_complete() ); fd_thr_term(&signals_thr); return -1; }
/* The extension-specific initialization code */ static int sample_main(char * conffile) { /* The debug macro from main tree can be used the same way */ TRACE_ENTRY("%p", conffile); /* This is how we access daemon's global vars */ fprintf(stdout, "I am extension " __FILE__ " running on host %s.", fd_g_config->cnf_diamid); /* The configuration file name is received in the conffile var. It's up to extension to parse it */ if (conffile) { fprintf(stdout, "I should parse my configuration file there: %s\n", conffile); } else { fprintf(stdout, "I received no configuration file to parse\n"); } /* Functions from the libfreediameter can also be used as demonstrated here: */ TRACE_DEBUG(INFO, "Let's create that 'Example-AVP'..."); { struct dict_object * origin_host_avp = NULL; struct dict_object * session_id_avp = NULL; struct dict_object * example_avp_avp = NULL; struct dict_rule_data rule_data = { NULL, RULE_REQUIRED, 0, -1, 1 }; struct dict_avp_data example_avp_data = { 999999, 0, "Example-AVP", AVP_FLAG_VENDOR , 0, AVP_TYPE_GROUPED }; CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &origin_host_avp, ENOENT)); CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &session_id_avp, ENOENT)); CHECK_FCT( fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &example_avp_data , NULL, &example_avp_avp )); rule_data.rule_avp = origin_host_avp; rule_data.rule_min = 1; rule_data.rule_max = 1; CHECK_FCT( fd_dict_new ( fd_g_config->cnf_dict, DICT_RULE, &rule_data, example_avp_avp, NULL )); rule_data.rule_avp = session_id_avp; rule_data.rule_min = 1; rule_data.rule_max = -1; CHECK_FCT( fd_dict_new ( fd_g_config->cnf_dict, DICT_RULE, &rule_data, example_avp_avp, NULL )); } TRACE_DEBUG(INFO, "'Example-AVP' created without error"); /* Call the c++ function */ mycppfunc(); /* The initialization function returns an error code with the standard POSIX meaning (ENOMEM, and so on) */ return 0; }
/* entry point */ static int rt_load_balance_entry(char * conffile) { /* Register the callback */ CHECK_FCT(fd_rt_out_register(rt_load_balancing, NULL, 10, &rt_load_balancing_hdl)); TRACE_DEBUG(INFO, "Extension 'Load Balancing' initialized"); return 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; }
/* 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; }
/* The entry point */ static int diameap_main(char * conffile) { TRACE_ENTRY("%p", conffile); memset(diameap_config, 0, sizeof(struct diameap_conf)); /* Initialize configuration */ CHECK_FCT(diameap_init(conffile)); /* Start Diameter EAP Application (Back-end Authenticator ) */ CHECK_FCT(diameap_start_server()); /* Announce the support of Diameter EAP Application to other peers */ CHECK_FCT(fd_disp_app_support(dataobj_diameap_app, dataobj_diameap_ven, 1, 0)); LOG_D("%sDiameter EAP Application Extension started successfully.",DIAMEAP_EXTENSION); 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 ta_serv_init(void) { CHECK_FCT( fd_sess_handler_create(&ta_cli_reg, (void *)free, NULL, NULL) ); struct disp_when data; TRACE_DEBUG(FULL, "Initializing dispatch callbacks for test"); memset(&data, 0, sizeof(data)); data.app = ta_appli; data.command = ta_cmd_r; /* fallback CB if command != Test-Request received */ CHECK_FCT( fd_disp_register( ta_fb_cb, DISP_HOW_APPID, &data, NULL, &ta_hdl_fb ) ); /* Now specific handler for Test-Request */ CHECK_FCT( fd_disp_register( ta_tr_cb, DISP_HOW_CC, &data, NULL, &ta_hdl_tr ) ); return 0; }
static int diameap_ba_policygetnextmethod(struct eap_state_machine * eap_sm, eap_type * eaptype, u32 * vendor) { TRACE_ENTRY("%p %p %p",eap_sm,eaptype,vendor); *vendor = 0; *eaptype = TYPE_NONE; if (eap_sm == NULL) { return EINVAL; } eap_sm->selectedMethod = NULL; if (eap_sm->user.userid == NULL) { if ((eap_sm->currentMethod == TYPE_NONE)) { *vendor = VENDOR_IETF; *eaptype = TYPE_IDENTITY; if (eap_sm->selectedMethod != NULL) { (*eap_sm->selectedMethod->eap_method_free)(eap_sm->methodData); eap_sm->methodData = NULL; } CHECK_FCT(diameap_plugin_get(VENDOR_IETF,TYPE_IDENTITY,&eap_sm->selectedMethod)); return 0; } eap_sm->selectedMethod = NULL; *vendor = 0; *eaptype = TYPE_NONE; return 0; } if (eap_sm->user.methodId == -1) { if (eap_sm->user.proposed_eap_method >= TYPE_EAP_MD5) { *vendor = eap_sm->user.proposed_eap_method_vendor; if (*vendor == VENDOR_IETF) { *eaptype = eap_sm->user.proposed_eap_method; } else { *eaptype = TYPE_EXPANDED_TYPES; } if (eap_sm->selectedMethod != NULL) { (*eap_sm->selectedMethod->eap_method_free)(eap_sm->methodData); eap_sm->methodData = NULL; } CHECK_FCT_DO(diameap_plugin_get(*vendor,*eaptype,&eap_sm->selectedMethod), { TRACE_DEBUG(INFO,"%s [EAP Protocol] Invalid EAP-TYPE %d (vendor %d)",DIAMEAP_EXTENSION,*eaptype,*vendor);return 1;});
/* entry point */ static int rtd_entry(char * conffile) { TRACE_ENTRY("%p", conffile); /* Initialize the repo */ CHECK_FCT( rtd_init() ); /* Parse the configuration file */ CHECK_FCT( rtd_conf_handle(conffile) ); #if 0 /* Dump the rules */ rtd_dump(); #endif /* 0 */ /* Register the callback */ CHECK_FCT( fd_rt_out_register( rtd_out, NULL, 5, &rtd_hdl ) ); /* We're done */ return 0; }
/* Alloc / reinit a peer structure. if *ptr is not NULL, it must already point to a valid struct fd_peer. */ int fd_peer_alloc(struct fd_peer ** ptr) { struct fd_peer *p; TRACE_ENTRY("%p", ptr); CHECK_PARAMS(ptr); if (*ptr) { p = *ptr; } else { CHECK_MALLOC( p = malloc(sizeof(struct fd_peer)) ); *ptr = p; } /* Now initialize the content */ memset(p, 0, sizeof(struct fd_peer)); fd_list_init(&p->p_hdr.chain, p); fd_list_init(&p->p_hdr.info.pi_endpoints, p); fd_list_init(&p->p_hdr.info.runtime.pir_apps, p); p->p_eyec = EYEC_PEER; CHECK_POSIX( pthread_mutex_init(&p->p_state_mtx, NULL) ); fd_list_init(&p->p_actives, p); fd_list_init(&p->p_expiry, p); CHECK_FCT( fd_fifo_new(&p->p_tosend, 5) ); CHECK_FCT( fd_fifo_new(&p->p_tofailover, 0) ); p->p_hbh = lrand48(); fd_list_init(&p->p_sr.srs, p); fd_list_init(&p->p_sr.exp, p); CHECK_POSIX( pthread_mutex_init(&p->p_sr.mtx, NULL) ); CHECK_POSIX( pthread_cond_init(&p->p_sr.cnd, NULL) ); fd_list_init(&p->p_connparams, p); 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; }
/* 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 main(int argc, char *argv[]) { int ret = 0; GLogLevelFlags log_flags; log_flags = (GLogLevelFlags) (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG); /* This initialize the library and check potential ABI mismatches * between the version it was compiled for and the actual shared * library used. */ LIBXML_TEST_VERSION; xmlInitParser(); /* Initialize the widget set */ gtk_init(&argc, &argv); /* Parse command line options */ ui_gtk_parse_arg (argc, argv); /* Set log handlers: * Domain, Levels, Handler, Domain enabled levels */ g_log_set_handler( NULL, log_flags, console_log_handler, (gpointer) (G_LOG_LEVELS)); g_log_set_handler("BUFFERS", log_flags, console_log_handler, (gpointer) (G_LOG_LEVELS & (~(G_LOG_LEVEL_DEBUG)))); g_log_set_handler("PARSER", log_flags, console_log_handler, (gpointer) (G_LOG_LEVELS & (~(G_LOG_LEVEL_DEBUG)))); g_log_set_handler("RESOLVER", log_flags, console_log_handler, (gpointer) (G_LOG_LEVELS & (~(G_LOG_LEVEL_DEBUG)))); g_log_set_handler("UI", log_flags, console_log_handler, (gpointer) (G_LOG_LEVELS & (~(G_LOG_LEVEL_DEBUG)))); g_log_set_handler("UI_CB", log_flags, console_log_handler, (gpointer) (G_LOG_LEVELS)); g_log_set_handler("UI_FILTER", log_flags, console_log_handler, (gpointer) (G_LOG_LEVELS & (~(G_LOG_LEVEL_DEBUG)))); g_log_set_handler("UI_INTER", log_flags, console_log_handler, (gpointer) (G_LOG_LEVELS)); g_log_set_handler("UI_TREE", log_flags, console_log_handler, (gpointer) (G_LOG_LEVELS & (~(G_LOG_LEVEL_DEBUG)))); CHECK_FCT(ui_gtk_initialize(argc, argv)); /* Enter the main event loop, and wait for user interaction */ gtk_main (); /* Free the global variables that may * have been allocated by the parser. */ xmlCleanupParser (); return ret; }
int file_read_dump(buffer_t **buffer, const char *filename) { int fd = -1; buffer_t *new_buf = NULL; uint8_t data[READ_BUFFER_SIZE]; ssize_t current_read; if (!filename) return RC_BAD_PARAM; if ((fd = open(filename, O_RDONLY)) == -1) { g_warning("Cannot open %s for reading, returned %d:%s\n", filename, errno, strerror(errno)); return RC_FAIL; } CHECK_FCT(buffer_new_from_data(&new_buf, NULL, 0, 0)); do { current_read = read(fd, data, READ_BUFFER_SIZE); if (current_read == -1) { g_warning("Failed to read data from file, returned %d:%s\n", errno, strerror(errno)); return RC_FAIL; } CHECK_FCT(buffer_append_data(new_buf, data, current_read)); } while(current_read == READ_BUFFER_SIZE); *buffer = new_buf; buffer_dump(new_buf, stdout); close(fd); return RC_OK; }
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_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; }
// Remove a peer entry. int fd_peer_remove ( DiamId_t diamid, size_t diamidlen ) { struct fd_list * li; // Find the peer in the peer list from its pi_diamid. CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_peers_rw) ); for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) { struct fd_peer * peer = (struct fd_peer *)li; int cmp = fd_os_cmp( diamid, diamidlen, peer->p_hdr.info.pi_diamid, peer->p_hdr.info.pi_diamidlen ); if (cmp == 0) { /* update the peer lifetime, set the expiry flag and call fd_p_expi_update so that the * p_exp_timer value is updated and the peer expires immediately. */ peer->p_hdr.info.config.pic_flags.exp = PI_EXP_INACTIVE; peer->p_hdr.info.config.pic_lft = 0; CHECK_FCT( fd_p_expi_update(peer) ); break; } } CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) ); 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; }
/* Add a new peer entry */ int fd_peer_add ( struct peer_info * info, const char * orig_dbg, void (*cb)(struct peer_info *, void *), void * cb_data ) { struct fd_peer *p = NULL; struct fd_list * li, *li_inf; int ret = 0; TRACE_ENTRY("%p %p %p %p", info, orig_dbg, cb, cb_data); CHECK_PARAMS(info && info->pi_diamid); if (info->config.pic_realm) { if (!fd_os_is_valid_DiameterIdentity((os0_t)info->config.pic_realm, strlen(info->config.pic_realm))) { TRACE_DEBUG(INFO, "'%s' is not a valid DiameterIdentity.", info->config.pic_realm); return EINVAL; } } /* Create a structure to contain the new peer information */ CHECK_FCT( fd_peer_alloc(&p) ); /* Copy the informations from the parameters received */ p->p_hdr.info.pi_diamid = info->pi_diamid; CHECK_FCT( fd_os_validate_DiameterIdentity(&p->p_hdr.info.pi_diamid, &p->p_hdr.info.pi_diamidlen, 1) ); memcpy( &p->p_hdr.info.config, &info->config, sizeof(p->p_hdr.info.config) ); /* Duplicate the strings if provided */ if (info->config.pic_realm) { CHECK_MALLOC( p->p_hdr.info.config.pic_realm = strdup(info->config.pic_realm) ); } if (info->config.pic_priority) { CHECK_MALLOC( p->p_hdr.info.config.pic_priority = strdup(info->config.pic_priority) ); } /* Move the list of endpoints into the peer */ if (info->pi_endpoints.next) while (!FD_IS_LIST_EMPTY( &info->pi_endpoints ) ) { li = info->pi_endpoints.next; fd_list_unlink(li); fd_list_insert_before(&p->p_hdr.info.pi_endpoints, li); } /* The internal data */ if (orig_dbg) { CHECK_MALLOC( p->p_dbgorig = strdup(orig_dbg) ); } else { CHECK_MALLOC( p->p_dbgorig = strdup("unspecified") ); } p->p_cb = cb; p->p_cb_data = cb_data; /* Ok, now check if we don't already have an entry with the same Diameter Id, and insert this one */ CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_peers_rw) ); li_inf = &fd_g_peers; for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) { struct fd_peer * next = (struct fd_peer *)li; int cont; int cmp = fd_os_almostcasesrch( p->p_hdr.info.pi_diamid, p->p_hdr.info.pi_diamidlen, next->p_hdr.info.pi_diamid, next->p_hdr.info.pi_diamidlen, &cont ); if (cmp > 0) li_inf = li; /* it will come after this element, for sure */ if (cmp == 0) { ret = EEXIST; /* we have a duplicate */ break; } if (!cont) break; } /* We can insert the new peer object */ if (! ret) do { /* Update expiry list */ CHECK_FCT_DO( ret = fd_p_expi_update( p ), break ); /* Insert the new element in the list */ fd_list_insert_after( li_inf, &p->p_hdr.chain ); } while (0); CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) ); if (ret) { CHECK_FCT( fd_peer_free(&p) ); } else { CHECK_FCT( fd_psm_begin(p) ); } return ret; }
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; }