From 849033d695188add825c40c605c1bde768c59481 Mon Sep 17 00:00:00 2001 From: Luis Azedo Date: Wed, 25 Feb 2015 10:06:35 +0000 Subject: [PATCH] registrar - add registered extra parameter adds 3rd parameter to registered to optionally restrict the contacts adds module parameter to optionally add contact xavp on successful match when calling registered add contact xavp to the $ulc structure --- modules/registrar/api.c | 2 +- modules/registrar/lookup.c | 66 ++++++-- modules/registrar/lookup.h | 2 +- modules/registrar/reg_mod.c | 88 +++++----- modules/registrar/reg_mod.h | 8 +- modules/registrar/regpv.c | 313 +++++++++++++++++++++++++++++++++++- 6 files changed, 421 insertions(+), 58 deletions(-) diff --git a/modules/registrar/api.c b/modules/registrar/api.c index cf8f37adfbe..0314a342a5a 100644 --- a/modules/registrar/api.c +++ b/modules/registrar/api.c @@ -103,7 +103,7 @@ int regapi_registered(struct sip_msg *msg, char *table) LM_ERR("usrloc domain [%s] not found\n", table); return -1; } - return registered(msg, d, NULL); + return registered(msg, d, NULL, 0); } /** diff --git a/modules/registrar/lookup.c b/modules/registrar/lookup.c index 6468e54047a..8e4f6141dd1 100644 --- a/modules/registrar/lookup.c +++ b/modules/registrar/lookup.c @@ -619,13 +619,16 @@ int lookup_branches(sip_msg_t *msg, udomain_t *d) * it is similar to lookup but registered neither rewrites * the Request-URI nor appends branches */ -int registered(struct sip_msg* _m, udomain_t* _d, str* _uri) +int registered(struct sip_msg* _m, udomain_t* _d, str* _uri, int match_flag) { str uri, aor; urecord_t* r; ucontact_t* ptr; int res; - int_str match_callid=(int_str)0; + str match_callid = {0,0}; + str match_received = {0,0}; + str match_contact = {0,0}; + sr_xavp_t *vavp = NULL; if(_uri!=NULL) { @@ -650,26 +653,61 @@ int registered(struct sip_msg* _m, udomain_t* _d, str* _uri) } if (res == 0) { - - if (reg_callid_avp_name.n) { - struct usr_avp *avp = - search_first_avp( reg_callid_avp_type, reg_callid_avp_name, &match_callid, 0); - if (!(avp && is_avp_str_val(avp))) - match_callid.n = 0; - match_callid.s.s = NULL; - } else { - match_callid.n = 0; - match_callid.s.s = NULL; + LM_DBG("searching with match flags (%d,%d)\n", match_flag, reg_match_flag_param); + if(reg_xavp_cfg.s!=NULL) { + + if((match_flag & 1) + && (vavp = xavp_get_child_with_sval(®_xavp_cfg, &match_callid_name)) != NULL + && vavp->val.v.s.len > 0) { + match_callid = vavp->val.v.s; + LM_DBG("matching with callid %.*s\n", match_callid.len, match_callid.s); + } + + if((match_flag & 2) + && (vavp = xavp_get_child_with_sval(®_xavp_cfg, &match_received_name)) != NULL + && vavp->val.v.s.len > 0) { + match_received = vavp->val.v.s; + LM_DBG("matching with received %.*s\n", match_received.len, match_received.s); + } + + if((match_flag & 4) + && (vavp = xavp_get_child_with_sval(®_xavp_cfg, &match_contact_name)) != NULL + && vavp->val.v.s.len > 0) { + match_contact = vavp->val.v.s; + LM_DBG("matching with contact %.*s\n", match_contact.len, match_contact.s); + } } for (ptr = r->contacts; ptr; ptr = ptr->next) { if(!VALID_CONTACT(ptr, act_time)) continue; - if (match_callid.s.s && /* optionally enforce tighter matching w/ Call-ID */ - memcmp(match_callid.s.s,ptr->callid.s,match_callid.s.len)) + if (match_callid.s && /* optionally enforce tighter matching w/ Call-ID */ + match_callid.len > 0 && + (match_callid.len != ptr->callid.len || + memcmp(match_callid.s, ptr->callid.s, match_callid.len))) continue; + if (match_received.s && /* optionally enforce tighter matching w/ ip:port */ + match_received.len > 0 && + (match_received.len != ptr->received.len || + memcmp(match_received.s, ptr->received.s, match_received.len))) + continue; + if (match_contact.s && /* optionally enforce tighter matching w/ Contact */ + match_contact.len > 0 && + (match_contact.len != ptr->c.len || + memcmp(match_contact.s, ptr->c.s, match_contact.len))) + continue; + + if(ptr->xavp!=NULL && reg_match_flag_param == 1) { + sr_xavp_t *xavp = xavp_clone_level_nodata(ptr->xavp); + if(xavp_add(xavp, NULL)<0) { + LM_ERR("error adding xavp for %.*s after successful match\n", aor.len, ZSW(aor.s)); + xavp_destroy_list(&xavp); + } + } + ul.release_urecord(r); ul.unlock_udomain(_d, &aor); LM_DBG("'%.*s' found in usrloc\n", aor.len, ZSW(aor.s)); + return 1; } } diff --git a/modules/registrar/lookup.h b/modules/registrar/lookup.h index 1e77bfeb7b1..9d06aa7126e 100644 --- a/modules/registrar/lookup.h +++ b/modules/registrar/lookup.h @@ -66,7 +66,7 @@ int lookup_branches(sip_msg_t *msg, udomain_t *d); * it is similar to lookup but registered neither rewrites * the Request-URI nor appends branches */ -int registered(struct sip_msg* _m, udomain_t* _d, str* _uri); +int registered(struct sip_msg* _m, udomain_t* _d, str* _uri, int match_flag); #endif /* LOOKUP_H */ diff --git a/modules/registrar/reg_mod.c b/modules/registrar/reg_mod.c index 437883cc6c9..3eba126e78a 100644 --- a/modules/registrar/reg_mod.c +++ b/modules/registrar/reg_mod.c @@ -69,6 +69,7 @@ static int w_lookup(struct sip_msg* _m, char* _d, char* _p2); static int w_lookup_to_dset(struct sip_msg* _m, char* _d, char* _p2); static int w_lookup_branches(struct sip_msg* _m, char* _d, char* _p2); static int w_registered(struct sip_msg* _m, char* _d, char* _uri); +static int w_registered2(struct sip_msg* _m, char* _d, char* _uri, char* _flags); static int w_unregister(struct sip_msg* _m, char* _d, char* _uri); static int w_unregister2(struct sip_msg* _m, char* _d, char* _uri, char *_ruid); @@ -78,6 +79,7 @@ static int domain_uri_fixup(void** param, int param_no); static int save_fixup(void** param, int param_no); static int unreg_fixup(void** param, int param_no); static int fetchc_fixup(void** param, int param_no); +static int registered_fixup(void** param, int param_no); /*! \brief Functions */ static int add_sock_hdr(struct sip_msg* msg, char *str, char *foo); @@ -101,10 +103,10 @@ int reg_outbound_mode = 0; int reg_regid_mode = 0; int reg_flow_timer = 0; -/* Populate this AVP if testing for specific registration instance. */ -char *reg_callid_avp_param = 0; -unsigned short reg_callid_avp_type = 0; -int_str reg_callid_avp_name; +int reg_match_flag_param = 0; +str match_callid_name = str_init("match_callid"); +str match_received_name = str_init("match_received"); +str match_contact_name = str_init("match_contact"); char* rcv_avp_param = 0; unsigned short rcv_avp_type = 0; @@ -164,6 +166,8 @@ static cmd_export_t cmds[] = { REQUEST_ROUTE | FAILURE_ROUTE }, {"registered", (cmd_function)w_registered, 2, domain_uri_fixup, 0, REQUEST_ROUTE | FAILURE_ROUTE }, + {"registered", (cmd_function)w_registered2, 3, registered_fixup, 0, + REQUEST_ROUTE | FAILURE_ROUTE }, {"add_sock_hdr", (cmd_function)add_sock_hdr, 1, fixup_str_null, 0, REQUEST_ROUTE }, {"unregister", (cmd_function)w_unregister, 2, unreg_fixup, 0, @@ -200,22 +204,22 @@ static param_export_t params[] = { {"max_expires", INT_PARAM, &default_registrar_cfg.max_expires }, {"received_param", PARAM_STR, &rcv_param }, {"received_avp", PARAM_STRING, &rcv_avp_param }, - {"reg_callid_avp", PARAM_STRING, ®_callid_avp_param }, {"max_contacts", INT_PARAM, &default_registrar_cfg.max_contacts }, {"retry_after", INT_PARAM, &default_registrar_cfg.retry_after }, - {"sock_flag", INT_PARAM, &sock_flag }, - {"sock_hdr_name", PARAM_STR, &sock_hdr_name }, - {"method_filtering", INT_PARAM, &method_filtering }, - {"use_path", INT_PARAM, &path_enabled }, - {"path_mode", INT_PARAM, &path_mode }, - {"path_use_received", INT_PARAM, &path_use_params }, - {"path_check_local", INT_PARAM, &path_check_local }, - {"xavp_cfg", PARAM_STR, ®_xavp_cfg }, - {"xavp_rcd", PARAM_STR, ®_xavp_rcd }, - {"gruu_enabled", INT_PARAM, ®_gruu_enabled }, - {"outbound_mode", INT_PARAM, ®_outbound_mode }, + {"sock_flag", INT_PARAM, &sock_flag }, + {"sock_hdr_name", PARAM_STR, &sock_hdr_name }, + {"method_filtering", INT_PARAM, &method_filtering }, + {"use_path", INT_PARAM, &path_enabled }, + {"path_mode", INT_PARAM, &path_mode }, + {"path_use_received", INT_PARAM, &path_use_params }, + {"path_check_local", INT_PARAM, &path_check_local }, + {"xavp_cfg", PARAM_STR, ®_xavp_cfg }, + {"xavp_rcd", PARAM_STR, ®_xavp_rcd }, + {"gruu_enabled", INT_PARAM, ®_gruu_enabled }, + {"outbound_mode", INT_PARAM, ®_outbound_mode }, {"regid_mode", INT_PARAM, ®_regid_mode }, {"flow_timer", INT_PARAM, ®_flow_timer }, + {"reg_on_match_flag", INT_PARAM, ®_match_flag_param }, {0, 0, 0} }; @@ -285,8 +289,6 @@ static int mod_init(void) LM_ERR("Fail to declare the configuration\n"); return -1; } - - if (rcv_avp_param && *rcv_avp_param) { s.s = rcv_avp_param; s.len = strlen(s.s); @@ -306,24 +308,6 @@ static int mod_init(void) rcv_avp_type = 0; } - if (reg_callid_avp_param && *reg_callid_avp_param) { - s.s = reg_callid_avp_param; s.len = strlen(s.s); - if (pv_parse_spec(&s, &avp_spec)==0 - || avp_spec.type!=PVT_AVP) { - LM_ERR("malformed or non AVP %s AVP definition\n", reg_callid_avp_param); - return -1; - } - - if(pv_get_avp_name(0, &avp_spec.pvp, ®_callid_avp_name, ®_callid_avp_type)!=0) - { - LM_ERR("[%s]- invalid AVP definition\n", reg_callid_avp_param); - return -1; - } - } else { - reg_callid_avp_name.n = 0; - reg_callid_avp_type = 0; - } - bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0); if (!bind_usrloc) { LM_ERR("can't bind usrloc\n"); @@ -485,7 +469,24 @@ static int w_registered(struct sip_msg* _m, char* _d, char* _uri) LM_ERR("invalid uri parameter\n"); return -1; } - return registered(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL); + return registered(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL, 0); +} + +static int w_registered2(struct sip_msg* _m, char* _d, char* _uri, char* _flags) +{ + str uri = {0}; + int flags = 0; + if(_uri!=NULL && (fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0 || uri.len<=0)) + { + LM_ERR("invalid uri parameter\n"); + return -1; + } + if(_flags!=NULL && (fixup_get_ivalue(_m, (fparam_t*)_flags, &flags)) < 0) + { + LM_ERR("invalid flags parameter\n"); + return -1; + } + return registered(_m, (udomain_t*)_d, (uri.len>0)?&uri:NULL, flags); } static int w_unregister(struct sip_msg* _m, char* _d, char* _uri) @@ -550,6 +551,18 @@ static int domain_uri_fixup(void** param, int param_no) return 0; } +static int registered_fixup(void** param, int param_no) +{ + if (param_no == 1) { + return domain_fixup(param, 1); + } else if (param_no == 2) { + return fixup_spve_null(param, 1); + } else if (param_no == 3) { + return fixup_igp_null(param, 1); + } + return 0; +} + /*! \brief * Convert char* parameter to udomain_t* pointer @@ -616,7 +629,6 @@ static int fetchc_fixup(void** param, int param_no) return 0; } - static void mod_destroy(void) { free_contact_buf(); diff --git a/modules/registrar/reg_mod.h b/modules/registrar/reg_mod.h index 892a60668d5..84eb27ef296 100644 --- a/modules/registrar/reg_mod.h +++ b/modules/registrar/reg_mod.h @@ -74,8 +74,12 @@ extern float def_q; extern unsigned short rcv_avp_type; extern int_str rcv_avp_name; -extern unsigned short reg_callid_avp_type; -extern int_str reg_callid_avp_name; + +extern int reg_match_flag_param; +extern str match_callid_name; +extern str match_received_name; +extern str match_contact_name; + extern str rcv_param; extern int method_filtering; diff --git a/modules/registrar/regpv.c b/modules/registrar/regpv.c index 719bec3ff0c..38d874d7bd3 100644 --- a/modules/registrar/regpv.c +++ b/modules/registrar/regpv.c @@ -35,10 +35,15 @@ #include "../../action.h" #include "../../lib/kcore/faked_msg.h" #include "../usrloc/usrloc.h" +#include "../../pvapi.h" +#include "../../xavp.h" #include "reg_mod.h" #include "common.h" #include "regpv.h" +#define REGPV_FIELD_DELIM ", " +#define REGPV_FIELD_DELIM_LEN (sizeof(REGPV_FIELD_DELIM) - 1) + typedef struct _regpv_profile { str pname; str domain; @@ -53,6 +58,7 @@ typedef struct _regpv_profile { typedef struct _regpv_name { regpv_profile_t *rp; int attr; + pv_xavp_name_t* xname; } regpv_name_t; static regpv_profile_t *_regpv_profile_list = NULL; @@ -110,6 +116,9 @@ static void regpv_free_profile(regpv_profile_t *rpp) ptr = rpp->contacts; while(ptr) { + if(ptr->xavp) { + xavp_destroy_list(&ptr->xavp); + } ptr0 = ptr; ptr = ptr->next; pkg_free(ptr0); @@ -151,6 +160,285 @@ void regpv_free_profiles(void) _regpv_profile_list = 0; } +char* regpv_xavp_fill_ni(str *in, pv_xavp_name_t *xname) +{ + char *p; + str idx; + int n; + + if(in->s==NULL || in->len<=0 || xname==NULL) + return NULL; + p = in->s; + + /* eat ws */ + while(ps+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r')) + p++; + if(p>in->s+in->len || *p=='\0') + goto error; + xname->name.s = p; + while(p < in->s + in->len) + { + if(*p=='=' || *p==' ' || *p=='\t' || *p=='\n' || *p=='\r' || *p=='[') + break; + p++; + } + xname->name.len = p - xname->name.s; + if(p>in->s+in->len || *p=='\0') + return p; + /* eat ws */ + while(ps+in->len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r')) + p++; + if(p>in->s+in->len || *p=='\0') + return p; + + if(*p!='[') + return p; + /* there is index */ + p++; + idx.s = p; + n = 0; + while(ps+in->len && *p!='\0') + { + if(*p==']') + { + if(n==0) + break; + n--; + } + if(*p == '[') + n++; + p++; + } + if(p>in->s+in->len || *p=='\0') + goto error; + + if(p==idx.s) + { + LM_ERR("xavp [\"%.*s\"] does not get empty index param\n", + in->len, in->s); + goto error; + } + idx.len = p - idx.s; + if(pv_parse_index(&xname->index, &idx)!=0) + { + LM_ERR("idx \"%.*s\" has an invalid index param [%.*s]\n", + in->len, in->s, idx.len, idx.s); + goto error; + } + xname->index.type = PVT_EXTRA; + p++; + return p; +error: + return NULL; +} + +int regpv_parse_xavp_name(pv_spec_p sp, str *in) +{ + pv_xavp_name_t *xname=NULL; + char *p; + str s; + + if(in->s==NULL || in->len<=0) + return -1; + + xname = (pv_xavp_name_t*)shm_malloc(sizeof(pv_xavp_name_t)); + if(xname==NULL) + return -1; + + memset(xname, 0, sizeof(pv_xavp_name_t)); + + s = *in; + + p = regpv_xavp_fill_ni(&s, xname); + if(p==NULL) { + goto error; + } + + if(*p!='=') { + goto done; + } + p++; + if(*p!='>') { + goto error; + } + p++; + + s.len = in->len - (int)(p - in->s); + s.s = p; + LM_INFO("xavp sublist [%.*s] - key [%.*s]\n", xname->name.len, + xname->name.s, s.len, s.s); + + xname->next = (pv_xavp_name_t*)pkg_malloc(sizeof(pv_xavp_name_t)); + if(xname->next==NULL) { + goto error; + } + + memset(xname->next, 0, sizeof(pv_xavp_name_t)); + + p = regpv_xavp_fill_ni(&s, xname->next); + if(p==NULL) { + goto error; + } + +done: + sp->pvp.pvn.u.dname = (void*)xname; + sp->pvp.pvn.type = PV_NAME_PVAR; + return 0; + +error: + if(xname!=NULL) { + pkg_free(xname); + } + return -1; +} + +int regpv_xavp_get_value(struct sip_msg *msg, pv_param_t *param, + pv_value_t *res, sr_xavp_t *avp) +{ + static char _pv_xavp_buf[128]; + str s; + + switch(avp->val.type) { + case SR_XTYPE_NULL: + return pv_get_null(msg, param, res); + break; + case SR_XTYPE_INT: + return pv_get_sintval(msg, param, res, avp->val.v.i); + break; + case SR_XTYPE_STR: + return pv_get_strval(msg, param, res, &avp->val.v.s); + break; + case SR_XTYPE_TIME: + if(snprintf(_pv_xavp_buf, 128, "%lu", (long unsigned)avp->val.v.t)<0) + return pv_get_null(msg, param, res); + break; + case SR_XTYPE_LONG: + if(snprintf(_pv_xavp_buf, 128, "%ld", (long unsigned)avp->val.v.l)<0) + return pv_get_null(msg, param, res); + break; + case SR_XTYPE_LLONG: + if(snprintf(_pv_xavp_buf, 128, "%lld", avp->val.v.ll)<0) + return pv_get_null(msg, param, res); + break; + case SR_XTYPE_XAVP: + if(snprintf(_pv_xavp_buf, 128, "<>", avp->val.v.xavp)<0) + return pv_get_null(msg, param, res); + break; + case SR_XTYPE_DATA: + if(snprintf(_pv_xavp_buf, 128, "<>", avp->val.v.data)<0) + return pv_get_null(msg, param, res); + break; + default: + return pv_get_null(msg, param, res); + } + s.s = _pv_xavp_buf; + s.len = strlen(_pv_xavp_buf); + return pv_get_strval(msg, param, res, &s); +} + +int regpv_get_xavp_from_start(struct sip_msg *msg, pv_param_t *param, + pv_value_t *res, sr_xavp_t **start) +{ + pv_xavp_name_t *xname=NULL; + sr_xavp_t *avp=NULL; + int idxf = 0; + int idx = 0; + int count; + char *p, *p_ini; + int p_size; + + if(param==NULL) + { + LM_ERR("bad parameters\n"); + return -1; + } + xname = ((regpv_name_t*)param->pvn.u.dname)->xname; + + if(xname->index.type==PVT_EXTRA) + { + /* get the index */ + if(pv_get_spec_index(msg, &xname->index.pvp, &idx, &idxf)!=0) + { + LM_ERR("invalid index\n"); + return -1; + } + } + /* fix the index */ + if(idx<0) + { + count = xavp_count(&xname->name, start); + idx = count + idx; + } + avp = xavp_get_by_index(&xname->name, idx, start); + if(avp==NULL) { + LM_DBG("GET XAVP AVP = NULL\n"); + return pv_get_null(msg, param, res); + } + if(xname->next==NULL) { + LM_DBG("GET XAVP XNAME NEXT = NULL\n"); + return regpv_xavp_get_value(msg, param, res, avp); + } + + idx = 0; + idxf = 0; + if(xname->next->index.type==PVT_EXTRA) + { + /* get the index */ + if(pv_get_spec_index(msg, &xname->next->index.pvp, &idx, &idxf)!=0) + { + LM_ERR("invalid index\n"); + return -1; + } + } + /* fix the index */ + if(idx<0) + { + count = xavp_count(&xname->next->name, &avp->val.v.xavp); + idx = count + idx; + } + avp = xavp_get_by_index(&xname->next->name, idx, &avp->val.v.xavp); + if(avp==NULL) { + LM_DBG("GET XAVP AVP BY INDEX = NULL\n"); + return pv_get_null(msg, param, res); + } + /* get all values of second key */ + if(idxf==PV_IDX_ALL) + { + p_ini = pv_get_buffer(); + p = p_ini; + p_size = pv_get_buffer_size(); + do { + if(p!=p_ini) + { + if(p-p_ini+REGPV_FIELD_DELIM_LEN+1>p_size) + { + LM_ERR("local buffer length exceeded\n"); + return pv_get_null(msg, param, res); + } + memcpy(p, REGPV_FIELD_DELIM, REGPV_FIELD_DELIM_LEN); + p += REGPV_FIELD_DELIM_LEN; + } + if(regpv_xavp_get_value(msg, param, res, avp)<0) + { + LM_ERR("can get value\n"); + return pv_get_null(msg, param, res); + } + if(p-p_ini+res->rs.len+1>p_size) + { + LM_ERR("local buffer length exceeded!\n"); + return pv_get_null(msg, param, res); + } + memcpy(p, res->rs.s, res->rs.len); + p += res->rs.len; + } while ((avp=xavp_get_next(avp))!=0); + res->rs.s = p_ini; + res->rs.len = p - p_ini; + return 0; + } + return regpv_xavp_get_value(msg, param, res, avp); +} + + int pv_get_ulc(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { @@ -192,7 +480,7 @@ int pv_get_ulc(struct sip_msg *msg, pv_param_t *param, /* get contact */ i = 0; c = rpp->contacts; - while(rpp) + while(c) { if(i == idx) break; @@ -269,6 +557,10 @@ int pv_get_ulc(struct sip_msg *msg, pv_param_t *param, if(c->instance.len>0) return pv_get_strval(msg, param, res, &c->instance); break; + case 21: /* xavp */ + if(c->xavp) + return regpv_get_xavp_from_start(msg, param, res, &c->xavp); + break; } return pv_get_null(msg, param, res); @@ -333,6 +625,15 @@ int pv_parse_ulc_name(pv_spec_p sp, str *in) memset(rp, 0, sizeof(regpv_name_t)); rp->rp = rpp; + if(strstr(pa.s, "=>")) { + regpv_parse_xavp_name(sp, &pa); + pv_xavp_name_t* xname = (pv_xavp_name_t*)sp->pvp.pvn.u.dname; + LM_DBG("ulc parse xavp name [%.*s] \n", xname->name.len, xname->name.s); + rp->xname = xname; + rp->attr = 21; + goto done; + } + switch(pa.len) { case 1: @@ -402,6 +703,7 @@ int pv_parse_ulc_name(pv_spec_p sp, str *in) default: goto error; } +done: sp->pvp.pvn.u.dname = (void*)rp; sp->pvp.pvn.type = PV_NAME_PVAR; @@ -538,7 +840,10 @@ int pv_fetch_contacts(struct sip_msg* msg, char* table, char* uri, c0->instance.len = ptr->instance.len; p += c0->instance.len; } - + if(ptr->xavp != NULL && reg_match_flag_param == 1) + { + c0->xavp = xavp_clone_level_nodata(ptr->xavp); + } if(ptr0==NULL) { rpp->contacts = c0; @@ -679,6 +984,10 @@ void reg_ul_expired_contact(ucontact_t* ptr, int type, void* param) c0->instance.len = ptr->instance.len; p += c0->instance.len; } + if(ptr->xavp != NULL && reg_match_flag_param == 1) + { + c0->xavp = xavp_clone_level_nodata(ptr->xavp); + } rpp->contacts = c0; rpp->nrc = 1;