Преглед изворни кода

modules/icscf: added I-CSCF module.

Jason Penton пре 12 година
родитељ
комит
29e841d41f

+ 27 - 0
modules/icscf/Makefile

@@ -0,0 +1,27 @@
+# $Id$
+#
+# ICSCF make file
+#
+# 
+
+
+include ../../Makefile.defs
+auto_gen=
+NAME=icscf.so
+LIBS=
+
+DEFS += -DOPENSER_MOD_INTERFACE
+
+DEFS += -I/usr/include/libxml2
+LIBS += -L$(LOCALBASE)/lib -lxml2 -lrt
+
+
+SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/srdb1/srdb1 $(SERLIBPATH)/kcore/kcore
+SER_LIBS+=$(SERLIBPATH)/ims/kamailio_ims
+
+
+
+
+
+include ../../Makefile.modules

+ 44 - 0
modules/icscf/blurb

@@ -0,0 +1,44 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */

+ 1028 - 0
modules/icscf/cxdx_avp.c

@@ -0,0 +1,1028 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#include "../cdp/cdp_load.h"
+#include "../../modules/tm/tm_load.h"
+#include "cxdx_avp.h"
+
+
+
+static str s_empty = {0, 0};
+
+/**
+ * Create and add an AVP to a Diameter message.
+ * @param m - Diameter message to add to
+ * @param d - the payload data
+ * @param len - length of the payload data
+ * @param avp_code - the code of the AVP
+ * @param flags - flags for the AVP
+ * @param vendorid - the value of the vendor id or 0 if none
+ * @param data_do - what to do with the data when done
+ * @param func - the name of the calling function, for debugging purposes
+ * @returns 1 on success or 0 on failure
+ */
+static inline int cxdx_add_avp(AAAMessage *m,char *d,int len,int avp_code,
+	int flags,int vendorid,int data_do,const char *func)
+{
+	AAA_AVP *avp;
+	if (vendorid!=0) flags |= AAA_AVP_FLAG_VENDOR_SPECIFIC;
+	avp = cdpb.AAACreateAVP(avp_code,flags,vendorid,d,len,data_do);
+	if (!avp) {
+		LM_ERR("%s: Failed creating avp\n",func);
+		return 0;
+	}
+	if (cdpb.AAAAddAVPToMessage(m,avp,m->avpList.tail)!=AAA_ERR_SUCCESS) {
+		LM_ERR("%s: Failed adding avp to message\n",func);
+		cdpb.AAAFreeAVP(&avp);
+		return 0;
+	}
+	return 1;
+}
+
+/**
+ * Create and add an AVP to a list of AVPs.
+ * @param list - the AVP list to add to
+ * @param d - the payload data
+ * @param len - length of the payload data
+ * @param avp_code - the code of the AVP
+ * @param flags - flags for the AVP
+ * @param vendorid - the value of the vendor id or 0 if none
+ * @param data_do - what to do with the data when done
+ * @param func - the name of the calling function, for debugging purposes
+ * @returns 1 on success or 0 on failure
+ */
+static inline int cxdx_add_avp_list(AAA_AVP_LIST *list,char *d,int len,int avp_code,
+	int flags,int vendorid,int data_do,const char *func)
+{
+	AAA_AVP *avp;
+	if (vendorid!=0) flags |= AAA_AVP_FLAG_VENDOR_SPECIFIC;
+	avp = cdpb.AAACreateAVP(avp_code,flags,vendorid,d,len,data_do);
+	if (!avp) {
+		LM_ERR("%s: Failed creating avp\n",func);
+		return 0;
+	}
+	if (list->tail) {
+		avp->prev=list->tail;
+		avp->next=0;
+		list->tail->next = avp;
+		list->tail=avp;
+	} else {
+		list->head = avp;
+		list->tail = avp;
+		avp->next=0;
+		avp->prev=0;
+	}
+
+	return 1;
+}
+
+/**
+ * Returns the value of a certain AVP from a Diameter message.
+ * @param m - Diameter message to look into
+ * @param avp_code - the code to search for
+ * @param vendorid - the value of the vendor id to look for or 0 if none
+ * @param func - the name of the calling function, for debugging purposes
+ * @returns the str with the payload on success or an empty string on failure
+ */
+static inline str cxdx_get_avp(AAAMessage *msg,int avp_code,int vendor_id,
+							const char *func)
+{
+	AAA_AVP *avp;
+	str r={0,0};
+
+	avp = cdpb.AAAFindMatchingAVP(msg,0,avp_code,vendor_id,0);
+	if (avp==0){
+		LM_INFO("%s: Failed finding avp\n",func);
+		return r;
+	}
+	else
+		return avp->data;
+}
+
+/**
+ * Creates and adds a Destination-Realm AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_destination_realm(AAAMessage *msg,str data)
+{
+	return
+	cxdx_add_avp(msg,data.s,data.len,
+		AVP_Destination_Realm,
+		AAA_AVP_FLAG_MANDATORY,
+		0,
+		AVP_DUPLICATE_DATA,
+		__FUNCTION__);
+}
+
+
+/**
+ * Creates and adds a Vendor-Specifig-Application-ID AVP.
+ * @param msg - the Diameter message to add to.
+ * @param vendor_id - the value of the vendor_id,
+ * @param auth_id - the authorization application id
+ * @param acct_id - the accounting application id
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_vendor_specific_appid(AAAMessage *msg,unsigned int vendor_id,
+	unsigned int auth_id,unsigned int acct_id)
+{
+	AAA_AVP_LIST list;
+	str group;
+	char x[4];
+
+	list.head=0;list.tail=0;
+
+	set_4bytes(x,vendor_id);
+	cxdx_add_avp_list(&list,
+		x,4,
+		AVP_Vendor_Id,
+		AAA_AVP_FLAG_MANDATORY,
+		0,
+		AVP_DUPLICATE_DATA,
+		__FUNCTION__);
+
+	if (auth_id) {
+		set_4bytes(x,auth_id);
+		cxdx_add_avp_list(&list,
+			x,4,
+			AVP_Auth_Application_Id,
+			AAA_AVP_FLAG_MANDATORY,
+			0,
+			AVP_DUPLICATE_DATA,
+			__FUNCTION__);
+	}
+	if (acct_id) {
+		set_4bytes(x,acct_id);
+		cxdx_add_avp_list(&list,
+			x,4,
+			AVP_Acct_Application_Id,
+			AAA_AVP_FLAG_MANDATORY,
+			0,
+			AVP_DUPLICATE_DATA,
+			__FUNCTION__);
+	}
+
+	group = cdpb.AAAGroupAVPS(list);
+
+	cdpb.AAAFreeAVPList(&list);
+
+	return
+	cxdx_add_avp(msg,group.s,group.len,
+		AVP_Vendor_Specific_Application_Id,
+		AAA_AVP_FLAG_MANDATORY,
+		0,
+		AVP_FREE_DATA,
+		__FUNCTION__);
+}
+
+/**
+ * Creates and adds a Auth-Session-State AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_auth_session_state(AAAMessage *msg,unsigned int data)
+{
+	char x[4];
+	set_4bytes(x,data);
+	return
+	cxdx_add_avp(msg,x,4,
+		AVP_Auth_Session_State,
+		AAA_AVP_FLAG_MANDATORY,
+		0,
+		AVP_DUPLICATE_DATA,
+		__FUNCTION__);
+}
+
+/**
+ * Creates and adds a User-Name AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_user_name(AAAMessage *msg,str data)
+{
+	return
+	cxdx_add_avp(msg,data.s,data.len,
+		AVP_User_Name,
+		AAA_AVP_FLAG_MANDATORY,
+		0,
+		AVP_DUPLICATE_DATA,
+		__FUNCTION__);
+}
+
+/**
+ * Creates and adds a Public Identity AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_public_identity(AAAMessage *msg,str data)
+{
+	return
+	cxdx_add_avp(msg,data.s,data.len,
+		AVP_IMS_Public_Identity,
+		AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+		IMS_vendor_id_3GPP,
+		AVP_DUPLICATE_DATA,
+		__FUNCTION__);
+}
+
+/**
+ * Creates and adds a Visited-Network-ID AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_visited_network_id(AAAMessage *msg,str data)
+{
+	return
+	cxdx_add_avp(msg,data.s,data.len,
+		AVP_IMS_Visited_Network_Identifier,
+		AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+		IMS_vendor_id_3GPP,
+		AVP_DUPLICATE_DATA,
+		__FUNCTION__);
+}
+
+/**
+ * Creates and adds a UAR-Flags AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_UAR_flags(AAAMessage *msg, unsigned int sos_reg)
+{
+
+	char x[4];
+	/* optional AVP*/
+	if(!sos_reg)
+		return 1;
+
+	set_4bytes(x, AVP_IMS_UAR_Flags_Emergency_Registration);
+	return
+	cxdx_add_avp(msg,x,4,
+		AVP_IMS_UAR_Flags,
+		AAA_AVP_FLAG_VENDOR_SPECIFIC,
+		IMS_vendor_id_3GPP,
+		AVP_DUPLICATE_DATA,
+		__FUNCTION__);
+
+}
+/**
+ * Creates and adds a Authorization-Type AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_authorization_type(AAAMessage *msg,unsigned int data)
+{
+	char x[4];
+	set_4bytes(x,data);
+	return
+	cxdx_add_avp(msg,x,4,
+		AVP_IMS_User_Authorization_Type,
+		AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+		IMS_vendor_id_3GPP,
+		AVP_DUPLICATE_DATA,
+		__FUNCTION__);
+}
+
+/**
+ * Returns the Result-Code AVP from a Diameter message.
+ * @param msg - the Diameter message
+ * @returns the AVP payload on success or an empty string on error
+ */
+inline int cxdx_get_result_code(AAAMessage *msg, int *data)
+{
+	str s;
+	s = cxdx_get_avp(msg,
+		AVP_Result_Code,
+		0,
+		__FUNCTION__);
+	if (!s.s) return 0;
+	*data = get_4bytes(s.s);
+	return 1;
+}
+
+/**
+ * Returns the Experimental-Result-Code AVP from a Diameter message.
+ * @param msg - the Diameter message
+ * @returns the AVP payload on success or an empty string on error
+ */
+inline int cxdx_get_experimental_result_code(AAAMessage *msg, int *data)
+{
+	AAA_AVP_LIST list;
+	AAA_AVP *avp;
+	str grp;
+	grp = cxdx_get_avp(msg,
+		AVP_IMS_Experimental_Result,
+		0,
+		__FUNCTION__);
+	if (!grp.s) return 0;
+
+	list = cdpb.AAAUngroupAVPS(grp);
+
+	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_Experimental_Result_Code,0,0);
+	if (!avp||!avp->data.s) {
+		cdpb.AAAFreeAVPList(&list);
+		return 0;
+	}
+
+	*data = get_4bytes(avp->data.s);
+	cdpb.AAAFreeAVPList(&list);
+
+	return 1;
+}
+
+/**
+ * Returns the Server-Name AVP from a Diameter message.
+ * @param msg - the Diameter message
+ * @returns the AVP payload on success or an empty string on error
+ */
+inline str cxdx_get_server_name(AAAMessage *msg)
+{
+	return cxdx_get_avp(msg,
+		AVP_IMS_Server_Name,
+		IMS_vendor_id_3GPP,
+		__FUNCTION__);
+}
+
+/**
+ * Returns the Capabilities from the grouped AVP from a Diameter message.
+ * @param msg - the Diameter message
+ * @param m - array to be filled with the retrieved mandatory capabilities
+ * @param m_cnt - size of the array above to be filled
+ * @param o - array to be filled with the retrieved optional capabilities
+ * @param o_cnt - size of the array above to be filled
+ * @returns 1 on success 0 on fail
+ */
+inline int cxdx_get_capabilities(AAAMessage *msg,int **m,int *m_cnt,int **o,int *o_cnt,
+	str **p,int *p_cnt)
+{
+	AAA_AVP_LIST list;
+	AAA_AVP *avp;
+	str grp;
+	grp = cxdx_get_avp(msg,
+		AVP_IMS_Server_Capabilities,
+		IMS_vendor_id_3GPP,
+		__FUNCTION__);
+	if (!grp.s) return 0;
+
+	list = cdpb.AAAUngroupAVPS(grp);
+
+	avp = list.head;
+	*m_cnt=0;
+	*o_cnt=0;
+	*p_cnt=0;
+	while(avp){
+		if (avp->code == AVP_IMS_Mandatory_Capability) (*m_cnt)++;
+		if (avp->code == AVP_IMS_Optional_Capability) (*o_cnt)++;
+		if (avp->code == AVP_IMS_Server_Name) (*p_cnt)++;
+		avp = avp->next;
+	}
+	avp = list.head;
+	*m=shm_malloc(sizeof(int)*(*m_cnt));
+	if (!*m){
+		LM_ERR("cannot allocated %lx bytes of shm.\n",
+			sizeof(int)*(*m_cnt));
+		goto error;
+	}
+	*o=shm_malloc(sizeof(int)*(*o_cnt));
+	if (!*o){
+		LM_ERR("cannot allocated %lx bytes of shm.\n",
+			sizeof(int)*(*o_cnt));
+		goto error;
+	}
+	*p=shm_malloc(sizeof(str)*(*p_cnt));
+	if (!*p){
+		LM_ERR("cannot allocated %lx bytes of shm.\n",
+			sizeof(str)*(*p_cnt));
+		goto error;
+	}
+
+	*m_cnt=0;
+	*o_cnt=0;
+	*p_cnt=0;
+	while(avp){
+		if (avp->code == AVP_IMS_Mandatory_Capability)
+			(*m)[(*m_cnt)++]=get_4bytes(avp->data.s);
+		if (avp->code == AVP_IMS_Optional_Capability)
+			(*o)[(*o_cnt)++]=get_4bytes(avp->data.s);
+		if (avp->code == AVP_IMS_Server_Name)
+			(*p)[(*p_cnt)++]=avp->data;
+		avp = avp->next;
+	}
+	cdpb.AAAFreeAVPList(&list);
+	return 1;
+
+error:
+	cdpb.AAAFreeAVPList(&list);
+	if (*m) shm_free(*m);
+	if (*o) shm_free(*o);
+	if (*p) shm_free(*p);
+	*m_cnt=0;
+	*o_cnt=0;
+	*p_cnt=0;
+	return 0;
+}
+
+/**
+ * Creates and adds a SIP-Number-Auth-Items AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_sip_number_auth_items(AAAMessage *msg,unsigned int data)
+{
+	char x[4];
+	set_4bytes(x,data);
+	return
+	cxdx_add_avp(msg,x,4,
+		AVP_IMS_SIP_Number_Auth_Items,
+		AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+		IMS_vendor_id_3GPP,
+		AVP_DUPLICATE_DATA,
+		__FUNCTION__);
+}
+
+/**
+ * Creates and adds a SIP-Auth-Data-Item AVP.
+ * @param msg - the Diameter message to add to.
+ * @param auth_scheme - the value for the authorization scheme AVP
+ * @param auth - the value for the authorization AVP
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_sip_auth_data_item_request(AAAMessage *msg, str auth_scheme, str auth, str username, str realm,str method, str server_name)
+{
+	AAA_AVP_LIST list;
+	str group;
+	str etsi_authorization = {0, 0};
+	list.head=0;list.tail=0;
+
+	if (auth_scheme.len){
+		cxdx_add_avp_list(&list,
+			auth_scheme.s,auth_scheme.len,
+			AVP_IMS_SIP_Authentication_Scheme,
+			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+			IMS_vendor_id_3GPP,
+			AVP_DONT_FREE_DATA,
+			__FUNCTION__);
+	}
+	if (auth.len){
+		cxdx_add_avp_list(&list,
+			auth.s,auth.len,
+			AVP_IMS_SIP_Authorization,
+			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+			IMS_vendor_id_3GPP,
+			AVP_DONT_FREE_DATA,
+			__FUNCTION__);
+	}
+
+	if (server_name.len)
+	{
+		etsi_authorization = cxdx_ETSI_sip_authorization(username, realm, s_empty, server_name, s_empty, s_empty, method, s_empty);
+
+		if (etsi_authorization.len){
+			cxdx_add_avp_list(&list,
+				etsi_authorization.s,etsi_authorization.len,
+				AVP_ETSI_SIP_Authorization,
+				AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+				IMS_vendor_id_ETSI,
+				AVP_FREE_DATA,
+				__FUNCTION__);
+		}
+	}
+
+	if (!list.head) return 1;
+	group = cdpb.AAAGroupAVPS(list);
+
+	cdpb.AAAFreeAVPList(&list);
+
+	return
+	cxdx_add_avp(msg,group.s,group.len,
+		AVP_IMS_SIP_Auth_Data_Item,
+		AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+		IMS_vendor_id_3GPP,
+		AVP_FREE_DATA,
+		__FUNCTION__);
+}
+
+/**
+ * Creates and adds a Server-Name AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_server_name(AAAMessage *msg,str data)
+{
+	return
+	cxdx_add_avp(msg,data.s,data.len,
+		AVP_IMS_Server_Name,
+		AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+		IMS_vendor_id_3GPP,
+		AVP_DUPLICATE_DATA,
+		__FUNCTION__);
+}
+
+/**
+ * Returns the SIP-Number-Auth-Items AVP from a Diameter message.
+ * @param msg - the Diameter message
+ * @returns the number or 0 on error
+ */
+inline int cxdx_get_sip_number_auth_items(AAAMessage *msg, int *data)
+{
+	str s;
+	s = cxdx_get_avp(msg,
+		AVP_IMS_SIP_Number_Auth_Items,
+		IMS_vendor_id_3GPP,
+		__FUNCTION__);
+	if (!s.s) return 0;
+	*data = get_4bytes(s.s);
+	return 1;
+}
+
+/**
+ * Returns the Auth-Data-Item from a Diameter answer message.
+ * @param msg - the Diameter message
+ * @param auth_date - the string to fill with the authorization data
+ * @param item_number - the int to fill with the item number
+ * @param auth_scheme - the string to fill with the authentication scheme data
+ * @param authenticate - the string to fill with the authenticate data
+ * @param authorization - the string to fill with the authorization data
+ * @param ck - the string to fill with the cipher key
+ * @param ik - the string to fill with the integrity key
+ * @returns the AVP payload on success or an empty string on error
+ */
+int cxdx_get_auth_data_item_answer(AAAMessage *msg, AAA_AVP **auth_data,
+	int *item_number,str *auth_scheme,str *authenticate,str *authorization,
+	str *ck,str *ik,
+	str *ip,
+	str *ha1, str *response_auth, str *digest_realm,
+	str *line_identifier)
+{
+	AAA_AVP_LIST list;
+	AAA_AVP_LIST list2;
+	AAA_AVP *avp;
+	AAA_AVP *avp2;
+	str grp;
+	ha1->s = 0; ha1->len = 0;
+	*auth_data = cdpb.AAAFindMatchingAVP(msg,*auth_data,AVP_IMS_SIP_Auth_Data_Item,
+		IMS_vendor_id_3GPP,0);
+	if (!*auth_data) return 0;
+
+	grp = (*auth_data)->data;
+	if (!grp.len) return 0;
+
+	list = cdpb.AAAUngroupAVPS(grp);
+
+	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_SIP_Item_Number,
+		IMS_vendor_id_3GPP,0);
+	if (!avp||!avp->data.len==4) *item_number=0;
+	else *item_number = get_4bytes(avp->data.s);
+
+	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_SIP_Authentication_Scheme,
+		IMS_vendor_id_3GPP,0);
+	if (!avp||!avp->data.s) {auth_scheme->s=0;auth_scheme->len=0;}
+	else *auth_scheme = avp->data;
+
+	/* Early-IMS */
+	ip->s=0;ip->len=0;
+	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_Framed_IP_Address,0,0);
+	if (avp && avp->data.s){
+		if (avp->data.len!=4){
+			LM_ERR("Invalid length of AVP Framed IP Address (should be 4 for AVP_Framed_IP_Address) >%d.\n",
+				avp->data.len);
+		}
+		ip->len = 4;
+		ip->s = avp->data.s;
+	} else {
+		avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_Framed_IPv6_Prefix,0,0);
+		if (avp && avp->data.s){
+			if (avp->data.len==0){
+				LM_ERR("Invalid length of AVP Framed IPv6 Prefix (should be >0 for AVP_Framed_IPv6_Prefix) >%d.\n",
+					avp->data.len);
+			}
+			ip->len = avp->data.len;
+			ip->s = avp->data.s;
+		}
+	}
+
+	/* Digest */
+
+	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_CableLabs_SIP_Digest_Authenticate,IMS_vendor_id_CableLabs,0);
+	if (avp  && avp->data.s)
+	{
+		list2 = cdpb.AAAUngroupAVPS(avp->data);
+
+		avp2 = cdpb.AAAFindMatchingAVPList(list2,0,AVP_CableLabs_Digest_HA1,IMS_vendor_id_CableLabs,0);
+		if (!avp2||!avp2->data.s) {
+			ha1->s = 0; ha1->len = 0;
+			cdpb.AAAFreeAVPList(&list2);
+			return 0;
+		}
+		*ha1 = avp2->data;
+		cdpb.AAAFreeAVPList(&list2);
+	}
+
+
+	/* SIP Digest */
+
+	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_SIP_Digest_Authenticate,IMS_vendor_id_3GPP,0);
+	if (avp  && avp->data.s)
+	{
+		list2 = cdpb.AAAUngroupAVPS(avp->data);
+
+		avp2 = cdpb.AAAFindMatchingAVPList(list2,0,AVP_IMS_Digest_HA1,0,0);
+		if (!avp2||!avp2->data.s) {
+			ha1->s = 0; ha1->len = 0;
+			cdpb.AAAFreeAVPList(&list2);
+			return 0;
+		}
+		*ha1 = avp2->data;
+		cdpb.AAAFreeAVPList(&list2);
+	}
+
+
+	/* AKA, MD5 */
+	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_SIP_Authenticate,
+		IMS_vendor_id_3GPP,0);
+	if (!avp||!avp->data.s) {authenticate->s=0;authenticate->len=0;}
+	else *authenticate = avp->data;
+
+	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_SIP_Authorization,
+		IMS_vendor_id_3GPP,0);
+	if (!avp||!avp->data.s) {authorization->s=0;authorization->len=0;}
+	else *authorization = avp->data;
+
+	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_Confidentiality_Key,
+		IMS_vendor_id_3GPP,0);
+	if (!avp||!avp->data.s) {ck->s=0;ck->len=0;}
+	else *ck = avp->data;
+
+	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_Integrity_Key,
+		IMS_vendor_id_3GPP,0);
+	if (!avp||!avp->data.s) {ik->s=0;ik->len=0;}
+	else *ik = avp->data;
+
+	/* ETSI HTTP Digest */
+
+	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_ETSI_SIP_Authenticate,IMS_vendor_id_ETSI,0);
+	if (avp  && avp->data.s)
+	{
+		list2 = cdpb.AAAUngroupAVPS(avp->data);
+
+		avp2 = cdpb.AAAFindMatchingAVPList(list2,0,AVP_ETSI_Digest_Realm, IMS_vendor_id_ETSI,0);
+		if (!avp2||!avp2->data.s) {
+			digest_realm->s=0;digest_realm->len=0;
+			cdpb.AAAFreeAVPList(&list2);
+			return 0;
+		}
+		*digest_realm = avp2->data;
+
+		avp2 = cdpb.AAAFindMatchingAVPList(list2,0,AVP_ETSI_Digest_Nonce, IMS_vendor_id_ETSI,0);
+		if (!avp2||!avp2->data.s) {
+			authenticate->s=0;authenticate->len=0;
+			cdpb.AAAFreeAVPList(&list2);
+			return 0;
+		}
+		*authenticate = avp2->data;
+
+		avp2 = cdpb.AAAFindMatchingAVPList(list2,0,AVP_ETSI_Digest_HA1, IMS_vendor_id_ETSI,0);
+		if (!avp2||!avp2->data.s) {
+			ha1->s = 0; ha1->len = 0;
+			cdpb.AAAFreeAVPList(&list2);
+			return 0;
+		}
+		*ha1 = avp2->data;
+
+		cdpb.AAAFreeAVPList(&list2);
+	}
+
+	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_ETSI_SIP_Authentication_Info,IMS_vendor_id_ETSI,0);
+	if (avp  && avp->data.s)
+	{
+		list2 = cdpb.AAAUngroupAVPS(avp->data);
+
+		avp2 = cdpb.AAAFindMatchingAVPList(list2,0,AVP_ETSI_Digest_Response_Auth, IMS_vendor_id_ETSI,0);
+		if (!avp2||!avp2->data.s) {
+			response_auth->s=0;response_auth->len=0;
+			cdpb.AAAFreeAVPList(&list2);
+			return 0;
+		}
+		*response_auth = avp2->data;
+		cdpb.AAAFreeAVPList(&list2);
+	}
+	else
+	{
+		response_auth->s=0;response_auth->len=0;
+	}
+
+	/* NASS Bundled */
+	avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_ETSI_Line_Identifier, IMS_vendor_id_ETSI,0);
+	if (!avp||!avp->data.s) {line_identifier->s=0;line_identifier->len=0;}
+	else *line_identifier = avp->data;
+
+	cdpb.AAAFreeAVPList(&list);
+	return 1;
+}
+
+/**
+ * Creates and adds a ETSI_sip_authorization AVP.
+ * @param username - UserName
+ * @param realm - Realm
+ * @param nonce - Nonce
+ * @param URI - URI
+ * @param response - Response
+ * @param algoritm - Algorithm
+ * @param method - Method
+ * @param hash - Enitity-Body-Hash
+ * @returns grouped str on success
+ */
+str cxdx_ETSI_sip_authorization(str username, str realm, str nonce, str URI, str response, str algorithm, str method, str hash)
+{
+	AAA_AVP_LIST list;
+	str group = {0, 0};
+	list.head=0;list.tail=0;
+
+	if (username.len){
+		cxdx_add_avp_list(&list,
+			username.s,username.len,
+			AVP_ETSI_Digest_Username,
+			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+			IMS_vendor_id_ETSI,
+			AVP_DONT_FREE_DATA,
+			__FUNCTION__);
+	}
+
+	if (realm.len){
+		cxdx_add_avp_list(&list,
+			realm.s,realm.len,
+			AVP_ETSI_Digest_Realm,
+			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+			IMS_vendor_id_ETSI,
+			AVP_DONT_FREE_DATA,
+			__FUNCTION__);
+	}
+
+	if (nonce.len){
+		cxdx_add_avp_list(&list,
+			nonce.s,nonce.len,
+			AVP_ETSI_Digest_Nonce,
+			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+			IMS_vendor_id_ETSI,
+			AVP_DONT_FREE_DATA,
+			__FUNCTION__);
+	}
+
+	if (URI.len){
+		cxdx_add_avp_list(&list,
+			URI.s,URI.len,
+			AVP_ETSI_Digest_URI,
+			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+			IMS_vendor_id_ETSI,
+			AVP_DONT_FREE_DATA,
+			__FUNCTION__);
+	}
+
+	if (response.len){
+		cxdx_add_avp_list(&list,
+			response.s,response.len,
+			AVP_ETSI_Digest_Response,
+			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+			IMS_vendor_id_ETSI,
+			AVP_DONT_FREE_DATA,
+			__FUNCTION__);
+	}
+
+	if (algorithm.len){
+		cxdx_add_avp_list(&list,
+			algorithm.s,algorithm.len,
+			AVP_ETSI_Digest_Algorithm,
+			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+			IMS_vendor_id_ETSI,
+			AVP_DONT_FREE_DATA,
+			__FUNCTION__);
+	}
+
+	if (method.len){
+		cxdx_add_avp_list(&list,
+			method.s,method.len,
+			AVP_ETSI_Digest_Method,
+			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+			IMS_vendor_id_ETSI,
+			AVP_DONT_FREE_DATA,
+			__FUNCTION__);
+	}
+
+	if (hash.len){
+		cxdx_add_avp_list(&list,
+			hash.s,hash.len,
+			AVP_ETSI_Digest_Entity_Body_Hash,
+			AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+			IMS_vendor_id_ETSI,
+			AVP_DONT_FREE_DATA,
+			__FUNCTION__);
+	}
+
+	if (!list.head) return group;
+	group = cdpb.AAAGroupAVPS(list);
+
+	cdpb.AAAFreeAVPList(&list);
+
+	return group;
+}
+
+/**
+ * Returns the User-Data from a Diameter message.
+ * @param msg - the Diameter message
+ * @returns the AVP payload on success or an empty string on error
+ */
+
+inline str cxdx_get_user_data(AAAMessage *msg)
+{
+	return cxdx_get_avp(msg,
+		AVP_IMS_User_Data_Cx,
+		IMS_vendor_id_3GPP,
+		__FUNCTION__);
+}
+
+/**
+ * Returns the Charging-Information from a Diameter message.
+ * @param msg - the Diameter message
+ * @returns the AVP payload on success or an empty string on error
+ */
+inline int cxdx_get_charging_info(AAAMessage *msg,str *ccf1,str *ccf2,str *ecf1,str *ecf2)
+{
+	AAA_AVP_LIST list;
+	AAA_AVP *avp;
+	str grp;
+	grp = cxdx_get_avp(msg,
+		AVP_IMS_Charging_Information,
+		IMS_vendor_id_3GPP,
+		__FUNCTION__);
+	if (!grp.s) return 0;
+
+	list = cdpb.AAAUngroupAVPS(grp);
+
+	if (ccf1){
+		avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_Primary_Charging_Collection_Function_Name,
+			IMS_vendor_id_3GPP,0);
+		if (avp) *ccf1 = avp->data;
+	}
+	if (ccf2){
+		avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_Secondary_Charging_Collection_Function_Name,
+			IMS_vendor_id_3GPP,0);
+		if (avp) *ccf2 = avp->data;
+	}
+	if (ecf1){
+		avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_Primary_Event_Charging_Function_Name,
+			IMS_vendor_id_3GPP,0);
+		if (avp) *ecf1 = avp->data;
+	}
+	if (ecf2){
+		avp = cdpb.AAAFindMatchingAVPList(list,0,AVP_IMS_Secondary_Event_Charging_Function_Name,
+			IMS_vendor_id_3GPP,0);
+		if (avp) *ecf2 = avp->data;
+	}
+
+	cdpb.AAAFreeAVPList(&list);
+	return 1;
+
+}
+
+/**
+ * Creates and adds a Server-Assignment-Type AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_server_assignment_type(AAAMessage *msg,unsigned int data)
+{
+	char x[4];
+	set_4bytes(x,data);
+	return
+	cxdx_add_avp(msg,x,4,
+		AVP_IMS_Server_Assignment_Type,
+		AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+		IMS_vendor_id_3GPP,
+		AVP_DUPLICATE_DATA,
+		__FUNCTION__);
+}
+
+/**
+ * Creates and adds Userdata-Available AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_userdata_available(AAAMessage *msg,unsigned int data)
+{
+	char x[4];
+	set_4bytes(x,data);
+	return
+	cxdx_add_avp(msg,x,4,
+		AVP_IMS_User_Data_Already_Available,
+		AAA_AVP_FLAG_MANDATORY|AAA_AVP_FLAG_VENDOR_SPECIFIC,
+		IMS_vendor_id_3GPP,
+		AVP_DUPLICATE_DATA,
+		__FUNCTION__);
+}
+
+/**
+ * Finds out the next Public-Identity AVP from a Diameter message.
+ * @param msg - the Diameter message
+ * @param pos - position to resume search or NULL if to start from the first AVP
+ * @param avp_code - the code of the AVP to look for
+ * @param vendor_id - the vendor id of the AVP to look for
+ * @param func - the name of the calling function for debugging purposes
+ * @returns the AVP payload on success or an empty string on error
+ */
+inline AAA_AVP* cxdx_get_next_public_identity(AAAMessage *msg,AAA_AVP* pos,int avp_code,int vendor_id,const char *func)
+{
+	AAA_AVP *avp;
+
+	avp = cdpb.AAAFindMatchingAVP(msg,pos,avp_code,vendor_id,0);
+	if (avp==0){
+		LM_DBG("INFO:%s: Failed finding avp\n",func);
+		return avp;
+	}
+	else
+		return avp;
+}
+
+/**
+ * Returns the User-Name AVP from a Diameter message.
+ * @param msg - the Diameter message
+ * @returns the AVP payload on success or an empty string on error
+ */
+inline str cxdx_get_user_name(AAAMessage *msg)
+{
+	return cxdx_get_avp(msg,
+		AVP_User_Name,
+		0,
+		__FUNCTION__);
+}
+
+/**
+ * Creates and adds a Result-Code AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_result_code(AAAMessage *msg,unsigned int data)
+{
+	char x[4];
+	set_4bytes(x,data);
+	return
+	cxdx_add_avp(msg,x,4,
+		AVP_Result_Code,
+		AAA_AVP_FLAG_MANDATORY,
+		0,
+		AVP_DUPLICATE_DATA,
+		__FUNCTION__);
+}

+ 276 - 0
modules/icscf/cxdx_avp.h

@@ -0,0 +1,276 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#ifndef IS_CSCF_CXDX_AVP_H
+#define IS_CSCF_CXDX_AVP_H
+
+extern struct cdp_binds cdpb;            /**< Structure with pointers to cdp funcs 		*/
+extern struct tm_binds tmb;
+
+struct AAAMessage;
+struct AAA_AVP;
+struct sip_msg;
+
+/**
+ * Creates and adds a Destination-Realm AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_destination_realm(AAAMessage *msg, str data);
+
+/**
+ * Creates and adds a Vendor-Specifig-Application-ID AVP.
+ * @param msg - the Diameter message to add to.
+ * @param vendor_id - the value of the vendor_id,
+ * @param auth_id - the authorization application id
+ * @param acct_id - the accounting application id
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_vendor_specific_appid(AAAMessage *msg,unsigned int vendor_id,unsigned int auth_id,unsigned int acct_id);
+
+/**
+ * Creates and adds a Auth-Session-State AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_auth_session_state(AAAMessage *msg,unsigned int data);
+
+/**
+ * Creates and adds a User-Name AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_user_name(AAAMessage *msg,str data);
+
+/**
+ * Creates and adds a Public Identity AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_public_identity(AAAMessage *msg,str data);
+
+/**
+ * Creates and adds a Visited-Network-ID AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_visited_network_id(AAAMessage *msg,str data);
+
+/**
+ * Creates and adds a UAR-Flags AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_UAR_flags(AAAMessage *msg, unsigned int sos_reg);
+
+/**
+ * Creates and adds a Authorization-Type AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_authorization_type(AAAMessage *msg,unsigned int data);
+
+/**
+ * Returns the Result-Code AVP from a Diameter message.
+ * @param msg - the Diameter message
+ * @returns the AVP payload on success or an empty string on error
+ */
+inline int cxdx_get_result_code(AAAMessage *msg, int *data);
+
+/**
+ * Returns the Experimental-Result-Code AVP from a Diameter message.
+ * @param msg - the Diameter message
+ * @returns the AVP payload on success or an empty string on error
+ */
+inline int cxdx_get_experimental_result_code(AAAMessage *msg, int *data);
+
+/**
+ * Returns the Server-Name AVP from a Diameter message.
+ * @param msg - the Diameter message
+ * @returns the AVP payload on success or an empty string on error
+ */
+inline str cxdx_get_server_name(AAAMessage *msg);
+
+/**
+ * Returns the Capabilities from the grouped AVP from a Diameter message.
+ * @param msg - the Diameter message
+ * @param m - array to be filled with the retrieved mandatory capabilities
+ * @param m_cnt - size of the array above to be filled
+ * @param o - array to be filled with the retrieved optional capabilities
+ * @param o_cnt - size of the array above to be filled
+ * @returns 1 on success 0 on fail
+ */
+inline int cxdx_get_capabilities(AAAMessage *msg,int **m,int *m_cnt,int **o,int *o_cnt,	str **p,int *p_cnt);
+
+/**
+ * Creates and adds a SIP-Number-Auth-Items AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_sip_number_auth_items(AAAMessage *msg,unsigned int data);
+
+/**
+ * Creates and adds a SIP-Auth-Data-Item AVP.
+ * @param msg - the Diameter message to add to.
+ * @param auth_scheme - the value for the authorization scheme AVP
+ * @param auth - the value for the authorization AVP
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_sip_auth_data_item_request(AAAMessage *msg, str auth_scheme, str auth, str username, str realm,str method, str server_name);
+
+/**
+ * Creates and adds a Server-Name AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_server_name(AAAMessage *msg,str data);
+
+/**
+ * Returns the SIP-Number-Auth-Items AVP from a Diameter message.
+ * @param msg - the Diameter message
+ * @returns the number or 0 on error
+ */
+inline int cxdx_get_sip_number_auth_items(AAAMessage *msg, int *data);
+
+/**
+ * Returns the Auth-Data-Item from a Diameter answer message.
+ * @param msg - the Diameter message
+ * @param auth_date - the string to fill with the authorization data
+ * @param item_number - the int to fill with the item number
+ * @param auth_scheme - the string to fill with the authentication scheme data
+ * @param authenticate - the string to fill with the authenticate data
+ * @param authorization - the string to fill with the authorization data
+ * @param ck - the string to fill with the cipher key
+ * @param ik - the string to fill with the integrity key
+ * @returns the AVP payload on success or an empty string on error
+ */
+int cxdx_get_auth_data_item_answer(AAAMessage *msg, AAA_AVP **auth_data,
+	int *item_number,str *auth_scheme,str *authenticate,str *authorization,
+	str *ck,str *ik,
+	str *ip,
+	str *ha1, str *response_auth, str *digest_realm,
+	str *line_identifier);
+
+/**
+ * Creates and adds a ETSI_sip_authorization AVP.
+ * @param username - UserName
+ * @param realm - Realm
+ * @param nonce - Nonce
+ * @param URI - URI
+ * @param response - Response
+ * @param algoritm - Algorithm
+ * @param method - Method
+ * @param hash - Enitity-Body-Hash
+ * @returns grouped str on success
+ */
+str cxdx_ETSI_sip_authorization(str username, str realm, str nonce, str URI, str response, str algorithm, str method, str hash);
+
+/**
+ * Returns the User-Data from a Diameter message.
+ * @param msg - the Diameter message
+ * @returns the AVP payload on success or an empty string on error
+ */
+
+inline str cxdx_get_user_data(AAAMessage *msg);
+
+/**
+ * Returns the Charging-Information from a Diameter message.
+ * @param msg - the Diameter message
+ * @returns the AVP payload on success or an empty string on error
+ */
+inline int cxdx_get_charging_info(AAAMessage *msg,str *ccf1,str *ccf2,str *ecf1,str *ecf2);
+
+/**
+ * Creates and adds a Server-Assignment-Type AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_server_assignment_type(AAAMessage *msg,unsigned int data);
+
+/**
+ * Creates and adds Userdata-Available AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_userdata_available(AAAMessage *msg,unsigned int data);
+
+/**
+ * Finds out the next Public-Identity AVP from a Diameter message.
+ * @param msg - the Diameter message
+ * @param pos - position to resume search or NULL if to start from the first AVP
+ * @param avp_code - the code of the AVP to look for
+ * @param vendor_id - the vendor id of the AVP to look for
+ * @param func - the name of the calling function for debugging purposes
+ * @returns the AVP payload on success or an empty string on error
+ */
+inline AAA_AVP* cxdx_get_next_public_identity(AAAMessage *msg,AAA_AVP* pos,int avp_code,int vendor_id,const char *func);
+
+/**
+ * Returns the User-Name AVP from a Diameter message.
+ * @param msg - the Diameter message
+ * @returns the AVP payload on success or an empty string on error
+ */
+inline str cxdx_get_user_name(AAAMessage *msg);
+
+/**
+ * Creates and adds a Result-Code AVP.
+ * @param msg - the Diameter message to add to.
+ * @param data - the value for the AVP payload
+ * @returns 1 on success or 0 on error
+ */
+inline int cxdx_add_result_code(AAAMessage *msg,unsigned int data);
+
+#endif /* IS_CSCF_CXDX_AVP_H */

+ 278 - 0
modules/icscf/cxdx_lir.c

@@ -0,0 +1,278 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#include "stats.h"
+#include "../cdp/cdp_load.h"
+#include "../../modules/dialog2/dlg_load.h"
+#include "cxdx_avp.h"
+#include "cxdx_lir.h"
+#include "mod.h"
+#include "location.h"
+
+//we use pseudo variables to communicate back to config file this takes the result and converys to a return code, publishes it a pseudo variable
+int create_lia_return_code(int result) {
+    int rc;
+    int_str avp_val, avp_name;
+    avp_name.s.s = "lia_return_code";
+    avp_name.s.len = 15;
+
+    //build avp spec for uaa_return_code
+    avp_val.n = result;
+
+    rc = add_avp(AVP_NAME_STR, avp_name, avp_val);
+
+    if (rc < 0)
+        LM_ERR("couldnt create AVP\n");
+    else
+        LM_INFO("created AVP successfully : [%.*s]\n", avp_name.s.len, avp_name.s.s);
+
+    return 1;
+}
+
+
+void free_saved_lir_transaction_data(saved_lir_transaction_t* data) {
+    if (!data)
+        return;
+    shm_free(data);
+}
+
+void async_cdp_lir_callback(int is_timeout, void *param, AAAMessage *lia, long elapsed_msecs) {
+    struct run_act_ctx ra_ctx;
+    str server_name;
+    int *m_capab = 0, m_capab_cnt = 0;
+    int *o_capab = 0, o_capab_cnt = 0;
+    str *p_server_names = 0;
+    int p_server_names_cnt = 0;
+    int rc = -1, experimental_rc = -1;
+    saved_lir_transaction_t* data = (saved_lir_transaction_t*) param;
+    struct cell *t = 0;
+    int result = CSCF_RETURN_TRUE;
+    scscf_entry *list = 0;
+    str call_id;
+
+    if (tmb.t_lookup_ident(&t, data->tindex, data->tlabel) < 0) {
+        LM_ERR("ERROR: t_continue: transaction not found\n");
+        //result = CSCF_RETURN_ERROR;//not needed we set by default to error!
+        goto error;
+    }
+
+    if (is_timeout != 0) {
+        LM_ERR("Error timeout when  sending message via CDP\n");
+        update_stat(stat_lir_timeouts, 1);
+        goto error;
+    }
+
+    //update stats on response time
+    update_stat(lir_replies_received, 1);
+    update_stat(lir_replies_response_time, elapsed_msecs);
+
+    if (!lia) {
+        LM_ERR("Error sending message via CDP\n");
+        //result = CSCF_RETURN_ERROR;//not needed we set by default to error!
+        goto error;
+    }
+
+    server_name = cxdx_get_server_name(lia);
+    if (!server_name.len) {
+        cxdx_get_capabilities(lia, &m_capab, &m_capab_cnt, &o_capab,
+                &o_capab_cnt, &p_server_names, &p_server_names_cnt);
+    }
+
+    cxdx_get_result_code(lia, &rc);
+    cxdx_get_experimental_result_code(lia, &experimental_rc);
+
+    if (rc && !experimental_rc) {
+        LM_ERR("No result code or experimental result code - responding 480\n");
+        cscf_reply_transactional_async(t, t->uas.request, 480, MSG_480_DIAMETER_MISSING_AVP);
+        result = CSCF_RETURN_FALSE;
+        goto done;
+    }
+
+    switch (rc) {
+        case -1:
+            switch (experimental_rc) {
+
+                case RC_IMS_DIAMETER_ERROR_USER_UNKNOWN:
+                    /* Check, if route is set: */
+                    if (route_lir_user_unknown_no >= 0) {
+                        /* exec routing script */
+                        init_run_actions_ctx(&ra_ctx);
+                        if (run_actions(&ra_ctx, main_rt.rlist[route_uar_user_unknown_no], t->uas.request) < 0) {
+                            DBG("icscf: error while trying script\n");
+                        }
+                    } else {
+                        cscf_reply_transactional_async(t, t->uas.request, 604, MSG_604_USER_UNKNOWN);
+                    }
+                    result = CSCF_RETURN_BREAK;
+                    goto done;
+                case RC_IMS_DIAMETER_ERROR_IDENTITY_NOT_REGISTERED:
+                    cscf_reply_transactional_async(t, t->uas.request, 480, MSG_480_NOT_REGISTERED);
+                    result = CSCF_RETURN_BREAK;
+                    goto done;
+
+                case RC_IMS_DIAMETER_UNREGISTERED_SERVICE:
+                    goto success;
+
+                default:
+                    cscf_reply_transactional_async(t, t->uas.request, 403, MSG_403_UNKOWN_EXPERIMENTAL_RC);
+                    result = CSCF_RETURN_BREAK;
+                    goto done;
+            }
+            break;
+
+        case AAA_UNABLE_TO_COMPLY:
+            cscf_reply_transactional_async(t, t->uas.request, 403, MSG_403_UNABLE_TO_COMPLY);
+            result = CSCF_RETURN_BREAK;
+            goto done;
+
+        case AAA_SUCCESS:
+            goto success;
+
+        default:
+            cscf_reply_transactional_async(t, t->uas.request, 403, MSG_403_UNKOWN_RC);
+            result = CSCF_RETURN_BREAK;
+            goto done;
+    }
+
+success:
+    if (server_name.len) {
+        list = new_scscf_entry(server_name, MAXINT, data->orig);
+    } else {
+        list = I_get_capab_ordered(server_name, m_capab, m_capab_cnt, o_capab, o_capab_cnt, p_server_names, p_server_names_cnt, data->orig);
+    }
+
+    if (!list) {
+        cscf_reply_transactional_async(t, t->uas.request, 600, MSG_600_EMPTY_LIST);
+        result = CSCF_RETURN_BREAK;
+        goto done;
+    }
+    call_id = cscf_get_call_id(t->uas.request, 0);
+    if (!call_id.len || !add_scscf_list(call_id, list)) {
+        cscf_reply_transactional_async(t, t->uas.request, 500, MSG_500_ERROR_SAVING_LIST);
+        result = CSCF_RETURN_BREAK;
+        goto done;
+    }
+
+    result = CSCF_RETURN_TRUE;
+
+done:
+    //free capabilities if they exist
+    if (m_capab) shm_free(m_capab);
+    if (o_capab) shm_free(o_capab);
+    if (p_server_names) shm_free(p_server_names);
+
+    LM_DBG("DBG:UAR Async CDP callback: ... Done resuming transaction\n");
+    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from);
+    set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to);
+    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from);
+    set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to);
+    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from);
+    set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to);
+
+    create_lia_return_code(result);
+
+    if (t)tmb.unref_cell(t);
+    //free memory
+    if (lia) cdpb.AAAFreeMessage(&lia);
+
+    tmb.t_continue(data->tindex, data->tlabel, data->act);
+    free_saved_lir_transaction_data(data);
+    return;
+
+error:
+    if (t)tmb.unref_cell(t);
+    //free memory
+    if (lia) cdpb.AAAFreeMessage(&lia);
+
+    tmb.t_continue(data->tindex, data->tlabel, data->act);
+    free_saved_lir_transaction_data(data);
+}
+
+
+/**
+ * Sends an LIR and returns the a parsed LIA structure.
+ * @param msg - the SIP message
+ * @param public_identity - the public identity
+ * @returns the LIA parsed structure or NULL on error
+ */
+//struct parsed_lia* cxdx_send_lir(struct sip_msg *msg, str public_identity) {
+
+int cxdx_send_lir(struct sip_msg *msg, str public_identity, saved_lir_transaction_t* transaction_data) {
+
+    AAAMessage *lir = 0;
+    AAASession *session = 0;
+
+
+    session = cdpb.AAACreateSession(0);
+
+    lir = cdpb.AAACreateRequest(IMS_Cx, IMS_LIR, Flag_Proxyable, session);
+    if (session) {
+        cdpb.AAADropSession(session);
+        session = 0;
+    }
+    if (!lir) goto error1;
+    if (!cxdx_add_destination_realm(lir, cxdx_dest_realm)) goto error1;
+    if (!cxdx_add_vendor_specific_appid(lir, IMS_vendor_id_3GPP, IMS_Cx, 0/*IMS_Cx*/)) goto error1;
+    if (!cxdx_add_auth_session_state(lir, 1)) goto error1;
+    if (!cxdx_add_public_identity(lir, public_identity)) goto error1;
+
+    if (cxdx_forced_peer.len)
+        cdpb.AAASendMessageToPeer(lir, &cxdx_forced_peer, (void*) async_cdp_lir_callback, (void*) transaction_data);
+    else
+        cdpb.AAASendMessage(lir, (void*) async_cdp_lir_callback, (void*) transaction_data);
+
+    LM_DBG("Successfully sent async diameter\n");
+
+    return 0;
+
+error1:
+    //Only free UAR IFF it has not been passed to CDP
+    if (lir) cdpb.AAAFreeMessage(&lir);
+    LM_ERR("Error occurred trying to send LIR\n");
+    return -1;
+
+}
+
+

+ 88 - 0
modules/icscf/cxdx_lir.h

@@ -0,0 +1,88 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+
+
+#ifndef CXDX_LIR_H
+#define CXDX_LIR_H
+
+
+
+extern struct cdp_binds cdpb;
+extern str cxdx_forced_peer; /**< FQDN of the Diameter peer to send requests to */
+extern str cxdx_dest_realm; 
+
+struct sip_msg;
+
+
+typedef struct lir_param {
+	int type;
+	cfg_action_t *paction;
+} lir_param_t;
+
+typedef struct saved_lir_transaction {
+	unsigned int tindex;
+	unsigned int tlabel;
+	unsigned int ticks;
+        int orig;
+	cfg_action_t *act;
+} saved_lir_transaction_t;
+
+void free_saved_lir_transaction_data(saved_lir_transaction_t* data);
+
+
+/**
+ * Sends an LIR asynchronously
+ * @param msg - the SIP message
+ * @param public_identity - the public identity
+ * @param realm - Realm
+ */
+int cxdx_send_lir(struct sip_msg *msg, str public_identity, saved_lir_transaction_t* transaction_data);
+
+
+int create_lia_return_code(int result);
+
+#endif
+

+ 312 - 0
modules/icscf/cxdx_uar.c

@@ -0,0 +1,312 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#include "stats.h"
+#include "../cdp/cdp_load.h"
+#include "../../modules/tm/tm_load.h"
+#include "../../modules/dialog2/dlg_load.h"
+#include "cxdx_avp.h"
+#include "cxdx_uar.h"
+#include "registration.h"
+#include "mod.h"
+
+
+//we use pseudo variables to communicate back to config file this takes the result and converys to a return code, publishes it a pseudo variable
+int create_uaa_return_code(int result) {
+    int rc;
+    int_str avp_val, avp_name;
+    avp_name.s.s = "uaa_return_code";
+    avp_name.s.len = 15;
+
+    //build avp spec for uaa_return_code
+    avp_val.n = result;
+
+    rc = add_avp(AVP_NAME_STR, avp_name, avp_val);
+
+    if (rc < 0)
+        LM_ERR("couldnt create AVP\n");
+    else
+        LM_INFO("created AVP successfully : [%.*s]\n", avp_name.s.len, avp_name.s.s);
+
+    return 1;
+}
+
+void free_saved_uar_transaction_data(saved_uar_transaction_t* data) {
+    if (!data)
+        return;
+
+    if (data->callid.s && data->callid.len) {
+        shm_free(data->callid.s);
+        data->callid.len = 0;
+    }
+    shm_free(data);
+}
+
+void async_cdp_uar_callback(int is_timeout, void *param, AAAMessage *uaa, long elapsed_msecs) {
+    struct run_act_ctx ra_ctx;
+    str server_name;
+    int *m_capab = 0, m_capab_cnt = 0;
+    int *o_capab = 0, o_capab_cnt = 0;
+    str *p_server_names = 0;
+    int p_server_names_cnt = 0;
+    int rc = -1, experimental_rc = -1;
+    saved_uar_transaction_t* data = (saved_uar_transaction_t*) param;
+    struct cell *t = 0;
+    int result = CSCF_RETURN_TRUE;
+    scscf_entry *list = 0;
+
+    if (tmb.t_lookup_ident(&t, data->tindex, data->tlabel) < 0) {
+        LM_ERR("ERROR: t_continue: transaction not found\n");
+        //result = CSCF_RETURN_ERROR;//not needed we set by default to error!
+        goto error;
+    }
+
+    if (is_timeout != 0) {
+        LM_ERR("Error timeout when  sending message via CDP\n");
+        update_stat(stat_uar_timeouts, 1);
+        goto error;
+    }
+
+    //update stats on response time
+    update_stat(uar_replies_received, 1);
+    update_stat(uar_replies_response_time, elapsed_msecs);
+
+    if (!uaa) {
+        LM_ERR("Error sending message via CDP\n");
+        //result = CSCF_RETURN_ERROR;//not needed we set by default to error!
+        goto error;
+    }
+
+    server_name = cxdx_get_server_name(uaa);
+    if (!server_name.len) {
+        cxdx_get_capabilities(uaa, &m_capab, &m_capab_cnt, &o_capab,
+                &o_capab_cnt, &p_server_names, &p_server_names_cnt);
+    }
+
+    cxdx_get_result_code(uaa, &rc);
+    cxdx_get_experimental_result_code(uaa, &experimental_rc);
+
+    if (rc && !experimental_rc) {
+        LM_ERR("No result code or experimental result code - responding 480\n");
+        cscf_reply_transactional_async(t, t->uas.request, 480, MSG_480_DIAMETER_MISSING_AVP);
+        result = CSCF_RETURN_FALSE;
+        goto done;
+    }
+
+    switch (rc) {
+        case -1:
+            switch (experimental_rc) {
+                case RC_IMS_DIAMETER_ERROR_USER_UNKNOWN:
+                    /* Check, if route is set: */
+                    if (route_uar_user_unknown_no >= 0) {
+                        /* exec routing script */
+                        init_run_actions_ctx(&ra_ctx);
+                        if (run_actions(&ra_ctx, main_rt.rlist[route_uar_user_unknown_no], t->uas.request) < 0) {
+                            LM_DBG("icscf: error while trying script\n");
+                        }
+                    } else {
+                        cscf_reply_transactional_async(t, t->uas.request, 403, MSG_403_USER_UNKNOWN);
+                    }
+                    LM_ERR("RC_IMS_DIAMETER_ERROR_USER_UNKNOWN\n");
+                    result = CSCF_RETURN_FALSE;
+                    goto done;
+                case RC_IMS_DIAMETER_ERROR_IDENTITIES_DONT_MATCH:
+                    LM_ERR("RC_IMS_DIAMETER_ERROR_IDENTITIES_DONT_MATCH returning 403\n");
+                    cscf_reply_transactional_async(t, t->uas.request, 403, MSG_403_IDENTITIES_DONT_MATCH);
+                    result = CSCF_RETURN_FALSE;
+                    goto done;
+                case RC_IMS_DIAMETER_ERROR_ROAMING_NOT_ALLOWED:
+                    LM_ERR("RC_IMS_DIAMETER_ERROR_ROAMING_NOT_ALLOWED returning 403\n");
+                    cscf_reply_transactional_async(t, t->uas.request, 403, MSG_403_ROAMING_NOT_ALLOWED);
+                    result = CSCF_RETURN_FALSE;
+                    goto done;
+                case RC_IMS_DIAMETER_ERROR_IDENTITY_NOT_REGISTERED:
+                    LM_ERR("RC_IMS_DIAMETER_ERROR_IDENTITY_NOT_REGISTERED returning 403\n");
+                    cscf_reply_transactional_async(t, t->uas.request, 403, MSG_403_IDENTITY_NOT_REGISTERED);
+                    result = CSCF_RETURN_FALSE;
+                    goto done;
+                case RC_IMS_DIAMETER_FIRST_REGISTRATION:
+                    goto success;
+                case RC_IMS_DIAMETER_SUBSEQUENT_REGISTRATION:
+                    goto success;
+                case RC_IMS_DIAMETER_SERVER_SELECTION:
+                    goto success;
+
+                default:
+                    LM_ERR("MSG_403_UNKOWN_EXPERIMENTAL_RC returning 403\n");
+                    cscf_reply_transactional_async(t, t->uas.request, 403, MSG_403_UNKOWN_EXPERIMENTAL_RC);
+                    result = CSCF_RETURN_FALSE;
+                    goto done;
+            }
+            break;
+
+        case AAA_AUTHORIZATION_REJECTED:
+            LM_ERR("AAA_AUTHORIZATION_REJECTED returning 403\n");
+            cscf_reply_transactional_async(t, t->uas.request, 403, MSG_403_AUTHORIZATION_REJECTED);
+            result = CSCF_RETURN_FALSE;
+            goto done;
+        case AAA_UNABLE_TO_COMPLY:
+            LM_ERR("AAA_UNABLE_TO_COMPLY returning 403\n");
+            cscf_reply_transactional_async(t, t->uas.request, 403, MSG_403_UNABLE_TO_COMPLY);
+            result = CSCF_RETURN_FALSE;
+            goto done;
+
+        case AAA_SUCCESS:
+            goto success;
+
+        default:
+            LM_ERR("MSG_403_UNKOWN_RC returning 403\n");
+            cscf_reply_transactional_async(t, t->uas.request, 403, MSG_403_UNKOWN_RC);
+            result = CSCF_RETURN_FALSE;
+            goto done;
+    }
+
+success:
+    LM_DBG("successful UAA response\n");
+    list = I_get_capab_ordered(server_name, m_capab, m_capab_cnt, o_capab, o_capab_cnt, p_server_names, p_server_names_cnt, 0);
+
+    if (!list) {
+        LM_ERR("Empty capability list returning 600\n");
+        cscf_reply_transactional_async(t, t->uas.request, 600, MSG_600_EMPTY_LIST);
+        result = CSCF_RETURN_FALSE;
+        goto done;
+    }
+
+    if (!data->callid.len || !add_scscf_list(data->callid, list)) {
+        LM_ERR("Error saving capability list 500\n");
+        cscf_reply_transactional_async(t, t->uas.request, 500, MSG_500_ERROR_SAVING_LIST);
+        result = CSCF_RETURN_FALSE;
+        goto done;
+    }
+
+    result = CSCF_RETURN_TRUE;
+
+done:
+	//free capabilities if they exist
+	if (m_capab) shm_free(m_capab);
+	if (o_capab) shm_free(o_capab);
+	if (p_server_names) shm_free(p_server_names);
+
+    LM_DBG("DBG:UAR Async CDP callback: ... Done resuming transaction\n");
+    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from);
+    set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to);
+    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from);
+    set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to);
+    set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from);
+    set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to);
+
+    create_uaa_return_code(result);
+
+    if (t)tmb.unref_cell(t);
+    //free memory
+    if (uaa) cdpb.AAAFreeMessage(&uaa);
+
+    tmb.t_continue(data->tindex, data->tlabel, data->act);
+    free_saved_uar_transaction_data(data);
+    return;
+
+error:
+    if (t)tmb.unref_cell(t);
+    //free memory
+    if (uaa) cdpb.AAAFreeMessage(&uaa);
+
+    tmb.t_continue(data->tindex, data->tlabel, data->act);
+    free_saved_uar_transaction_data(data);
+
+
+}
+
+/**
+ * Sends an UAR and returns the parsed UAA struct.
+ * @param msg - the SIP message
+ * @param private_identity - the username
+ * @param public_identity - the public identity
+ * @param visited_network_id - id of the roaming network
+ * @param authorization_type - if registration or de-registration
+ * @returns the status of sending the async UAR - 0 for success, !0 for failure
+ */
+int cxdx_send_uar(struct sip_msg *msg, str private_identity, str public_identity, str visited_network_id,
+        int authorization_type, int sos_reg, saved_uar_transaction_t* transaction_data) {
+    AAAMessage *uar = 0;
+    AAASession *session = 0;
+
+    session = cdpb.AAACreateSession(0);
+
+    uar = cdpb.AAACreateRequest(IMS_Cx, IMS_UAR, Flag_Proxyable, session);
+    if (session) {
+        cdpb.AAADropSession(session);
+        session = 0;
+    }
+    if (!uar) goto error1;
+
+    if (!cxdx_add_destination_realm(uar, cxdx_dest_realm)) goto error1;
+
+    if (!cxdx_add_vendor_specific_appid(uar, IMS_vendor_id_3GPP, IMS_Cx, 0)) goto error1;
+    if (!cxdx_add_auth_session_state(uar, 1)) goto error1;
+
+    if (!cxdx_add_user_name(uar, private_identity)) goto error1;
+    if (!cxdx_add_public_identity(uar, public_identity)) goto error1;
+    if (!cxdx_add_visited_network_id(uar, visited_network_id)) goto error1;
+    if (!cxdx_add_UAR_flags(uar, sos_reg)) goto error1;
+    if (authorization_type != AVP_IMS_UAR_REGISTRATION)
+        if (!cxdx_add_authorization_type(uar, authorization_type)) goto error1;
+
+    if (cxdx_forced_peer.len)
+        cdpb.AAASendMessageToPeer(uar, &cxdx_forced_peer, (void*) async_cdp_uar_callback, (void*) transaction_data);
+    else
+        cdpb.AAASendMessage(uar, (void*) async_cdp_uar_callback, (void*) transaction_data);
+
+    LM_DBG("Successfully sent async diameter\n");
+
+    return 0;
+
+error1:
+    //Only free UAR IFF it has not been passed to CDP
+    if (uar) cdpb.AAAFreeMessage(&uar);
+    LM_ERR("Error occurred trying to send UAR\n");
+    return -1;
+}
+
+

+ 87 - 0
modules/icscf/cxdx_uar.h

@@ -0,0 +1,87 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#ifndef ICXDX_UAR_H
+#define ICXDX_UAR_H
+
+#include "../../mod_fix.h"
+
+extern struct cdp_binds cdpb; /**< Structure with pointers to cdp funcs 		*/
+extern str cxdx_forced_peer; /**< FQDN of the Diameter peer to send requests to */
+extern str cxdx_dest_realm;
+
+typedef struct uar_param {
+	int type;
+	gparam_t *ivalue;
+	cfg_action_t *paction;
+} uar_param_t;
+
+typedef struct saved_transaction {
+	unsigned int tindex;
+	unsigned int tlabel;
+	unsigned int ticks;
+	cfg_action_t *act;
+	str callid;
+} saved_uar_transaction_t;
+
+void free_saved_uar_transaction_data(saved_uar_transaction_t* data);
+
+/**
+ * Sends an UAR and returns the parsed UAA struct.
+ * @param msg - the SIP message
+ * @param private_identity - the username
+ * @param public_identity - the public identity
+ * @param visited_network_id - id of the roaming network
+ * @param authorization_type - if registration or de-registration
+ * @param realm - Realm
+ * @returns 0 on success
+ */
+int cxdx_send_uar(struct sip_msg *msg, str private_identity, str public_identity, str visited_network_id,
+        int authorization_type, int sos_reg, saved_uar_transaction_t* transaction_data);
+
+int create_uaa_return_code(int result);
+
+#endif
+

+ 381 - 0
modules/icscf/db.c

@@ -0,0 +1,381 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+ 
+/**
+ * \file
+ * 
+ * Interrogating-CSCF - Database operations
+ * 
+ * 
+ *  \author Dragos Vingarzan vingarzan -at- fokus dot fraunhofer dot de
+ * 
+ */
+
+#include "db.h"
+
+#include "../../lib/srdb1/db.h"
+#include "../../mem/shm_mem.h"
+
+#include "mod.h"
+
+static db_func_t dbf;						/**< db function bindings*/
+extern char * icscf_db_url;					/**< DB URL */
+extern char * icscf_db_nds_table;			/**< NDS table in DB */
+extern char * icscf_db_scscf_table;			/**< S-CSCF table in db */
+extern char * icscf_db_capabilities_table;	/**< S-CSCF capabilities table in db */
+
+static db1_con_t *hdl_db=0;				/**< handle for the database queries */
+
+
+/**
+ *  Bind to the database module.
+ * @param db_url - URL of the database
+ * @returns 0 on success, -1 on error
+ */
+int icscf_db_bind(char* db_url)
+{
+
+	str db_url_str={db_url,strlen(db_url)};
+	
+	if (db_bind_mod(&db_url_str, &dbf) < 0) {
+		LM_ERR("icscf_db_bind: cannot bind to database module! "
+		"Did you forget to load a database module ?\n");
+		return -1;
+	}
+	return 0;
+}
+
+
+/**
+ *  Init the database connection 
+ * @param db_url - URL of the database
+ * @param db_table_nds - name of the NDS table
+ * @param db_table_scscf - name of the S-CSCF table
+ * @param db_table_capabilities - name of the S-CSCF capabilities table
+ * @returns 0 on success, -1 on error
+ */
+int icscf_db_init(char* db_url,
+	char* db_table_nds,
+	char* db_table_scscf,
+	char* db_table_capabilities)
+{
+	str db_url_str={db_url,strlen(db_url)};
+	
+	if (dbf.init==0){
+		LM_ERR("BUG:cscf_db_init: unbound database module\n");
+		return -1;
+	}
+
+	hdl_db=dbf.init(&db_url_str);
+
+	if (hdl_db==0){
+		LM_ERR("ERR:icscf_db_init: cannot initialize database connection\n");
+		goto error;
+	}	
+
+	return 0;
+
+error:
+	if (hdl_db){
+		dbf.close(hdl_db);
+		hdl_db=0;
+	}
+	return -1;
+}
+
+/**
+ *  Close the database connection.
+ */
+void icscf_db_close()
+{
+	if (!dbf.close) return;
+	if (hdl_db){
+		dbf.close(hdl_db);
+		hdl_db=0;
+	}
+}
+
+/**
+ * Simply check if the database connection was initialized and connect if not.
+ * @param db_hdl - database handle to test
+ * @returns 1 if connected, 0 if not
+ */
+static inline int icscf_db_check_init(db1_con_t *db_hdl)
+{
+	if (db_hdl) return 1;
+	return (icscf_db_init( icscf_db_url,
+		icscf_db_nds_table,
+		icscf_db_scscf_table,
+		icscf_db_capabilities_table)==0);		
+}
+
+
+static str s_trusted_domain={"trusted_domain",14};
+/**
+ *  Get the NDS list from the database.
+ * @param d - array of string to fill with the db contents
+ * @returns 1 on success, 0 on error 
+ */
+int icscf_db_get_nds(str *d[])
+{	
+	db_key_t   keys_ret[] = {&s_trusted_domain};
+	db1_res_t   * res = 0 ;	
+	str db_table_nds_str={icscf_db_nds_table,strlen(icscf_db_nds_table)};
+
+	str s;
+	int i;
+
+	if (!icscf_db_check_init(hdl_db))
+		goto error;
+
+	LM_DBG("DBG:icscf_db_get_nds: fetching list of NDS for I-CSCF \n");
+
+	if (dbf.use_table(hdl_db, &db_table_nds_str)<0) {
+		LM_ERR("ERR:icscf_db_init: cannot select table \"%s\"\n",db_table_nds_str.s);
+		goto error;
+	}
+
+	if (dbf.query(hdl_db, 0, 0, 0, keys_ret, 0, 1, NULL, & res) < 0) {
+		LM_ERR("ERR:icscf_db_get_nds: db_query failed\n");
+		goto error;
+	}
+
+	if (res->n == 0) {
+		LM_DBG("DBG:icscf_db_get_nds: I-CSCF has no NDS trusted domains in db\n");
+		*d=shm_malloc(sizeof(str));
+		if (*d==NULL){
+			LM_ERR("ERR:icscf_db_get_nds: failed shm_malloc for 0 domains\n");
+			goto error;
+		}	
+		(*d)[0].s=0;
+		(*d)[0].len=0;
+	}
+	else {
+		*d=shm_malloc(sizeof(str)*(res->n+1));
+		if (*d==NULL){
+			LM_ERR("ERR:icscf_db_get_nds: failed shm_malloc for %d domains\n",
+				res->n);
+			goto error;
+		}	
+		for(i=0;i<res->n;i++){
+			s.s = (char*) res->rows[i].values[0].val.string_val;
+			s.len = strlen(s.s);
+			(*d)[i].s = shm_malloc(s.len);
+			if ((*d)[i].s==NULL) {
+				LM_ERR("ERR:icscf_db_get_nds: failed shm_malloc for %d bytes\n",
+					s.len);
+				(*d)[i].len = 0;
+			}else{
+				(*d)[i].len = s.len;
+				memcpy((*d)[i].s,s.s,s.len);
+			}
+		}
+		(*d)[res->n].s=0;
+		(*d)[res->n].len=0;
+	}
+
+	LM_DBG("INF:icscf_db_get_nds: Loaded %d trusted domains\n",
+		res->n);
+
+	dbf.free_result( hdl_db, res);
+	return 1;
+error:
+	if (res)
+		dbf.free_result( hdl_db, res);
+	*d=shm_malloc(sizeof(str));
+	if (*d==NULL)
+		LM_ERR("ERR:icscf_db_get_nds: failed shm_malloc for 0 domains\n");
+	else {
+		(*d)[0].s=0;
+		(*d)[0].len=0;
+	}
+	return 0;
+}
+
+
+static str s_id={"id",2};
+static str s_s_cscf_uri={"s_cscf_uri",10};
+/**
+ *  Get the S-CSCF names from the database and create the S-CSCF set.
+ * @param cap - array of scscf_capabilities to fill with the db contents for the S-CSCF names
+ * @returns 1 on success, 0 on error 
+ */
+int icscf_db_get_scscf(scscf_capabilities *cap[])
+{
+
+	db_key_t   keys_ret[] = {&s_id,&s_s_cscf_uri};
+	db_key_t   key_ord = &s_id;
+	db1_res_t   * res = 0 ;	
+	str db_table_scscf_str={icscf_db_scscf_table,strlen(icscf_db_scscf_table)};
+
+	int i;
+
+	*cap = 0;
+		
+	if (!icscf_db_check_init(hdl_db))
+		goto error;
+
+	LM_DBG("DBG:icscf_db_get_scscf: fetching S-CSCFs \n");
+
+	if (dbf.use_table(hdl_db, &db_table_scscf_str)<0) {
+		LM_ERR("ERR:icscf_db_init: cannot select table \"%s\"\n",db_table_scscf_str.s);
+		goto error;
+	}
+	
+	if (dbf.query(hdl_db, 0, 0, 0, keys_ret, 0, 2, key_ord, & res) < 0) {
+		LM_ERR("ERR:icscf_db_get_scscf: db_query failed\n");
+		goto error;
+	}
+
+	if (res->n == 0) {
+		LM_ERR("ERR:icscf_db_get_scscf:  no S-CSCFs found\n");
+		goto error;
+	}
+	else {
+		*cap = shm_malloc(sizeof(scscf_capabilities)*res->n);
+		if (!(*cap)) {
+			LM_ERR("ERR:icscf_db_get_scscf: Error allocating %lx bytes\n",
+				sizeof(scscf_capabilities)*res->n);
+			goto error;
+		}
+		memset((*cap),0,sizeof(scscf_capabilities)*res->n);
+		for(i=0;i<res->n;i++){
+			(*cap)[i].id_s_cscf = res->rows[i].values[0].val.int_val;
+			(*cap)[i].scscf_name.len = strlen(res->rows[i].values[1].val.string_val);
+			(*cap)[i].scscf_name.s = shm_malloc((*cap)[i].scscf_name.len);
+			if (!(*cap)[i].scscf_name.s){
+				LM_ERR("ERR:icscf_db_get_scscf: Error allocating %d bytes\n",
+					(*cap)[i].scscf_name.len);
+				(*cap)[i].scscf_name.len=0;
+				goto error;
+			}
+			memcpy((*cap)[i].scscf_name.s,res->rows[i].values[1].val.string_val,
+				(*cap)[i].scscf_name.len);
+		}
+	}
+
+	dbf.free_result( hdl_db, res);
+	
+	// return the size of scscf set  
+	return i;
+	
+error:
+	if (res)
+		dbf.free_result( hdl_db, res);
+	return 0;
+}
+
+static str s_id_s_cscf={"id_s_cscf",9};
+static str s_capability={"capability",10};
+/**
+ *  Get the S-CSCF capabilities from the database and fill the S-CSCF set.
+ * @param cap - array of scscf_capabilities to fill with capabilities
+ * @returns 1 on success, 0 on error 
+ */
+int icscf_db_get_capabilities(scscf_capabilities *cap[],int cap_cnt)
+{
+	db_key_t   keys_ret[] = {&s_id_s_cscf,&s_capability};
+	db_key_t   key_ord = &s_id_s_cscf;
+	db1_res_t   * res = 0 ;	
+	str db_table_capabilities_str={icscf_db_capabilities_table,strlen(icscf_db_capabilities_table)};	
+
+
+	int i,j;
+	int ccnt=0;
+	int cnt;
+
+
+	if (!icscf_db_check_init(hdl_db))
+		goto error;
+
+	LM_DBG("DBG:icscf_db_get_capabilities: fetching list of Capabilities for I-CSCF\n");
+
+	if (dbf.use_table(hdl_db, &db_table_capabilities_str)<0) {
+		LM_ERR("ERR:icscf_db_init: cannot select table \"%s\"\n",db_table_capabilities_str.s);
+		goto error;
+	}
+	
+	if (dbf.query(hdl_db, 0, 0, 0, keys_ret, 0, 2, key_ord, & res) < 0) {
+		LM_ERR("ERR:icscf_db_get_capabilities: db_query failed\n");
+		goto error;
+	}
+
+	if (res->n == 0) {
+		LM_DBG("DBG:icscf_db_get_capabilities: No Capabilites found... not critical...\n");
+		return 1;
+	}
+	else {
+		for(i=0;i<cap_cnt;i++){
+			cnt = 0;
+			for(j=0;j<res->n;j++)
+				if (res->rows[j].values[0].val.int_val == (*cap)[i].id_s_cscf)
+					cnt++;
+			(*cap)[i].capabilities = shm_malloc(sizeof(int)*cnt);
+			if (!(*cap)[i].capabilities) {
+				LM_ERR("ERR:icscf_db_get_capabilities: Error allocating %lx bytes\n",
+					sizeof(int)*cnt);
+				(*cap)[i].cnt=0;
+					goto error;
+			}			
+			cnt=0;
+			for(j=0;j<res->n;j++)
+				if (res->rows[j].values[0].val.int_val == (*cap)[i].id_s_cscf) {
+					(*cap)[i].capabilities[cnt++]=res->rows[j].values[1].val.int_val;
+					ccnt++;
+				}
+			(*cap)[i].cnt=cnt;					
+		}
+			
+	} 
+	LM_DBG("INF:icscf_db_get_capabilities: Loaded %d capabilities for %d S-CSCFs (%d invalid entries in db)\n",
+		ccnt,cap_cnt,res->n-ccnt);
+	dbf.free_result( hdl_db, res);
+	return 1;
+	
+error:
+	if (res)
+		dbf.free_result( hdl_db, res);
+	return 0;
+}

+ 73 - 0
modules/icscf/db.h

@@ -0,0 +1,73 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+ 
+/**
+ * \file
+ * 
+ * Interrogating-CSCF - Database operations
+ * 
+ * 
+ *  \author Dragos Vingarzan vingarzan -at- fokus dot fraunhofer dot de
+ * 
+ */
+ 
+#ifndef I_CSCF_DB_H
+#define I_CSCF_DB_H
+
+#include "../../sr_module.h"
+#include "registration.h"
+
+int icscf_db_bind(char* db_url);
+int icscf_db_init(char* db_url,
+	char* db_table_nds,
+	char* db_table_scscf,
+	char* db_table_capabilities);
+void icscf_db_close();
+
+int icscf_db_get_nds(str *d[]);
+int icscf_db_get_scscf(scscf_capabilities *cap[]);
+int icscf_db_get_capabilities(scscf_capabilities *cap[],int cap_cnt);
+
+#endif /* I_CSCF_DB_H */

+ 4 - 0
modules/icscf/doc/Makefile

@@ -0,0 +1,4 @@
+docs = icscf.xml
+
+docbook_dir = ../../../docbook
+include $(docbook_dir)/Makefile.module

+ 65 - 0
modules/icscf/doc/icscf.xml

@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+]>
+<book>
+  <bookinfo>
+    <title>auth_ims Module</title>
+
+    <authorgroup>
+      <author>
+        <firstname>Dragos Vingarzan</firstname>
+
+        <surname/>
+
+        <affiliation>
+          <orgname>FhG Fokus</orgname>
+        </affiliation>
+
+        <email>[email protected]</email>
+      </author>
+
+      <author>
+        <firstname>Jason</firstname>
+
+        <surname>Penton</surname>
+
+        <affiliation>
+          <orgname>Smile Communications</orgname>
+        </affiliation>
+
+        <email>[email protected]</email>
+      </author>
+
+      <author>
+        <firstname>Richard</firstname>
+
+        <surname>Good</surname>
+        <affiliation>
+          <orgname>Smile Communications</orgname>
+        </affiliation>
+
+        <email>[email protected]</email>
+      </author>
+    </authorgroup>
+
+    <copyright>
+      <year>2007</year>
+      <holder>FhG FOKUS</holder>
+    </copyright>
+
+    <copyright>
+      <year>2012</year>
+
+      <holder>Smile Communications</holder>
+    </copyright>
+  </bookinfo>
+
+  <toc/>
+
+  <xi:include href="icscf_admin.xml"
+              xmlns:xi="http://www.w3.org/2001/XInclude"/>
+</book>

+ 448 - 0
modules/icscf/doc/icscf_admin.xml

@@ -0,0 +1,448 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
+<!-- Include general documentation entities -->
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
+%docentities;
+]>
+<!-- I-CSCF Module User's Guide -->
+<chapter>
+  <title>&adminguide;</title>
+
+  <section>
+    <title>Overview</title>
+
+    <para>This module provides all functionality to build an ICSCF.</para>
+  </section>
+
+  <section>
+    <title>Dependencies</title>
+
+    <section>
+      <title>&kamailio; Modules</title>
+
+      <para>The Following mouldes must be loaded before this module:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>TM - Transaction Manager</para>
+        </listitem>
+
+        <listitem>
+          <para>SL - Stateless Reply</para>
+        </listitem>
+
+        <listitem>
+          <para>CDP - C Diameter Peer</para>
+        </listitem>
+
+        <listitem>
+          <para>CDP_AVP - CDP AVP Applications</para>
+        </listitem>
+      </itemizedlist>
+    </section>
+
+    <section>
+      <title>External Libraries or Applications</title>
+
+      <para>This modules requires the Kamailio internal IMS library.</para>
+    </section>
+  </section>
+
+  <section>
+    <title>Parameters</title>
+
+    <section>
+      <title><varname>name</varname> (string)</title>
+
+      <para>This is the name of the SCSCF as identified in communication with
+      the HSS (Server-Name AVP of MAR).</para>
+
+      <para><emphasis> Default value is 'sip:scscf.ims.smilecoms.com:6060'.
+      </emphasis></para>
+
+      <example>
+        <title><varname>name</varname> parameter usage</title>
+
+        <programlisting format="linespecific">
+...
+modparam("auth_ims", "name", "sip:scscf3.ims.smilecoms.com:6060")
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><varname>name</varname> (string)</title>
+
+      <para>This is the name of the SCSCF as identified in communication with
+      the HSS (Server-Name AVP of MAR).</para>
+
+      <para><emphasis> Default value is 'sip:scscf.ims.smilecoms.com:6060'.
+      </emphasis></para>
+
+      <example>
+        <title><varname>name</varname> parameter usage</title>
+
+        <programlisting format="linespecific">
+...
+modparam("auth_ims", "name", "sip:scscf3.ims.smilecoms.com:6060")
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><varname>auth_data_hash_size</varname> (integer)</title>
+
+      <para>This is the size of the hash table used to store auth vectors
+      (AV). Default value is fine for most people. Use the parameter if you
+      really need to change it.</para>
+
+      <para>Default value is <quote>1024</quote>.</para>
+
+      <example>
+        <title><varname>auth_data_hash_size</varname> parameter usage</title>
+
+        <programlisting format="linespecific">
+...
+modparam("auth_ims", "auth_data_hash_size", 1024)
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><varname>auth_vector_timeout</varname> (integer)</title>
+
+      <para>This is the time, in seconds, that a SENTauth vector is valid for.
+      If there is no response ...</para>
+
+      <para>Default value is <quote>60</quote>.</para>
+
+      <example>
+        <title><varname>auth_vector_timeout</varname> parameter usage</title>
+
+        <programlisting format="linespecific">
+...
+modparam("auth_ims", "auth_vector_timeout", "domain")
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><varname>auth_data_timeout</varname> (int)</title>
+
+      <para>Time, in seconds, a used auth vector is valid for.</para>
+
+      <para>Default value is <quote>60</quote>.</para>
+
+      <example>
+        <title><varname>password_column</varname> parameter usage</title>
+
+        <programlisting format="linespecific">
+...
+modparam("auth_ims", "auth_data_timeout", 60)
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><varname>av_request_at_once</varname> (integer)</title>
+
+      <para>How many auth vectors to request in MAR.</para>
+
+      <para>Default value is 1</para>
+
+      <example>
+        <title><varname>av_request_at_once</varname> parameter usage</title>
+
+        <programlisting format="linespecific">
+...
+modparam("auth_ims", "av_request_at_once", 1)
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><varname>av_request_at_sync</varname> (integer)</title>
+
+      <para>How many auth vectors to request at sync. Default value is
+      1.</para>
+
+      <example>
+        <title><varname>av_request_at_sync</varname> parameter usage</title>
+
+        <programlisting format="linespecific">
+...
+modparam("auth_ims", "av_request_at_sync", 1)
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><varname>registration_default_algorithm</varname>
+      (string)</title>
+
+      <para>The default authentication algorithm to use for registration if
+      one is not specified.</para>
+
+      <para>Options are: <itemizedlist>
+          <listitem>
+            <para><emphasis>AKAV1-MD5</emphasis></para>
+          </listitem>
+
+          <listitem>
+            <para><emphasis>AKAV2-MD5</emphasis></para>
+          </listitem>
+
+          <listitem>
+            <para><emphasis>MD5</emphasis></para>
+          </listitem>
+
+          <listitem>
+            <para>HSS-Selected - HSS will decide on auth algorithm</para>
+          </listitem>
+        </itemizedlist>Default value is <quote>AKAv1-MD5</quote>.</para>
+
+      <example>
+        <title><varname>registration_default_algorithm</varname> parameter
+        usage</title>
+
+        <programlisting format="linespecific">
+...
+modparam("auth_ims", "registration_default_algorithm", "HSS-Selected")
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><varname>registration_qop</varname> (string)</title>
+
+      <para>The QOP options to put in the authorisation challenges.</para>
+
+      <para>Default value of this parameter is
+      <quote>auth,auth-int</quote>.</para>
+
+      <example>
+        <title><varname>load_credentials</varname> parameter usage</title>
+
+        <programlisting format="linespecific">
+...
+modparam("auth_ims", "load_credentials", "auth-int")
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><varname>cxdx_forced_peer</varname> (string)</title>
+
+      <para>FQDN of Diameter Peer (HSS) to use for communication (MAR)</para>
+
+      <para>Default value is <quote/>.</para>
+
+      <example>
+        <title><varname>cxdx_forced_peer</varname> parameter usage</title>
+
+        <programlisting format="linespecific">
+...
+modparam("auth_ims", "cxdx_forced_peer", "hss.ims.smilecoms.com")
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><varname>cxdx_dest_realm</varname> (string)</title>
+
+      <para>Destination realm to be used in Diameter messags to HSS</para>
+
+      <para>Default value is <quote>ims.smilecoms.com</quote>.</para>
+
+      <example>
+        <title><varname>version_table</varname> parameter usage</title>
+
+        <programlisting format="linespecific">
+...
+modparam("auth_ims", "cxdx_dest_realm", "ims.smilecoms.com")
+...
+</programlisting>
+      </example>
+    </section>
+  </section>
+
+  <section>
+    <title>Functions</title>
+
+    <section>
+      <title><function
+      moreinfo="none">I_scscf_select(initial)</function></title>
+
+      <para>This function is used to retrieve the next unused SCSCF from
+      thelist for this request (based on callid).</para>
+
+      <para>A positive return code (1) means an SCSCF was found and is armed
+      for routing.</para>
+
+      <para>Meaning of the parameters is as follows:</para>
+
+      <itemizedlist>
+        <listitem>
+          <para><emphasis>initial</emphasis> - Signal whether or not this is
+          an original or subsequent.</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>This function can be used from REQUEST_ROUTE |
+      FAILURE_ROUTE.</para>
+
+      <example>
+        <title><function moreinfo="none">I_scscf_select</function>
+        usage</title>
+
+        <programlisting format="linespecific">...
+if (I_scscf_select("0")) {
+     #there is an S-CSCF list - no need to do a UAR
+     t_on_reply("register_reply");
+     t_on_failure("register_failure");
+     t_relay();
+}
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><function moreinfo="none">I_scscf_drop()</function></title>
+
+      <para>Drop the list of SCSCFs for this request (based on callid).</para>
+
+      <para>This function can be used from REQUEST_ROUTE | FAILURE_ROUTE |
+      REPLY_ROUTE</para>
+
+      <example>
+        <title><function moreinfo="none">I_scscf_drop</function> usage</title>
+
+        <programlisting format="linespecific">...
+I_scscf_drop();
+...
+</programlisting>
+      </example>
+
+      <para>.</para>
+    </section>
+
+    <section>
+      <title><function
+      moreinfo="none">I_perform_user_authorization_request(capabalities)</function></title>
+
+      <para>Perform a UAR on Diameter CXDX interface. This function will build
+      a list of SCSCFs to be used and populate the SCSCF list for the request.
+      On a succesful return of this message you can get the next available
+      SCSCF by using the I_scscf_select functoin in 4.1.</para>
+
+      <itemizedlist>
+        <listitem>
+          <para>capabilities - whether to request capabilities or not "1" -
+          with capabilities, "0" - no capabilities.</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>This function can be used from REQUEST_ROUTE.</para>
+
+      <para>p.s. this is executed asynchronously. See example on how to
+      retrieve return value</para>
+
+      <example>
+        <title>I_perform_user_authorization_request usage</title>
+
+        <programlisting format="linespecific">
+...
+            I_perform_user_authorization_request("0"); #0=REG/DEREG; 1=REG+Capabilities
+            #this is async so to know status we have to check the reply avp
+            switch ($avp(s:uaa_return_code)){
+                case 1: #success
+                    if (I_scscf_select("0")){
+                        t_on_failure("register_failure");
+                        t_on_reply("register_reply");
+                        if (!t_relay()) {
+                            t_reply("500", "Error forwarding to SCSCF");
+                        }
+                    } else {#select failed
+                        I_scscf_drop();
+                        t_reply("500", "Server error on SCSCF Select (UAR)");
+                    }
+                    break;
+                case -1: #failure
+                    xlog("L_ERR", "UAR failure - error response sent from module");
+                    break;
+                case -2: #error
+                    xlog("L_ERR", "UAR error - sending error response now");
+                    t_reply("500", "UAR failed");
+                    break;
+                default:
+                    xlog("L_ERR", "Unknown return code from UAR, value is [$avp(s:uaa_return_code)]");
+                    t_reply("500", "Unknown response code from UAR"); 
+                    break;
+            }
+...
+</programlisting>
+      </example>
+    </section>
+
+    <section>
+      <title><function
+      moreinfo="none">I_perform_location_information_request()</function></title>
+
+      <para>This function can be used from REQUEST_ROUTE.</para>
+
+      <example>
+        <title>proxy_authorize usage</title>
+
+        <programlisting format="linespecific">
+...
+if (!proxy_authorize("$fd", "subscriber)) {
+proxy_challenge("$fd", "1");  # Realm will be autogenerated
+};
+...
+</programlisting>
+      </example>
+    </section>
+  </section>
+
+  <section>
+    <title>Statistics</title>
+
+    <section>
+      <title>Average UAR Response Time (uar_avg_response_time)</title>
+
+      <para>The average response time in milliseconds for UAR-UAA
+      transaction.</para>
+    </section>
+
+    <section>
+      <title>UAR Timeouts (uar_timeouts)</title>
+
+      <para>The number of UAR timeouts.</para>
+    </section>
+
+    <section>
+      <title>Average LIR Response Time (lir_avg_response_time)</title>
+
+      <para>The average response time in milliseconds for LIR-LIA
+      transaction.</para>
+    </section>
+
+    <section>
+      <title>LIR Timeouts (lir_timeouts)</title>
+
+      <para>The number of LIR timeouts.</para>
+    </section>
+  </section>
+</chapter>

+ 153 - 0
modules/icscf/location.c

@@ -0,0 +1,153 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#include "location.h"
+#include "../../action.h" /* run_actions */
+#include "cxdx_lir.h"
+
+extern int route_lir_user_unknown_no; 
+
+/**
+ * Perform an LIR
+ * @param msg - sip message
+ * @returns 1 on success or 0 on failure
+ */
+int I_perform_location_information_request(struct sip_msg* msg, char* str1, char* str2) {
+    str public_identity = {0, 0};
+    int orig = 0;
+    
+    tm_cell_t *t = 0;
+    saved_lir_transaction_t* saved_t;
+    
+     cfg_action_t* cfg_action;
+
+    lir_param_t* ap = (lir_param_t*) str1;
+    cfg_action = ap->paction->next;
+    
+    LM_DBG("DBG:I_LIR: Starting ...\n");
+    /* check if we received what we should */
+    if (msg->first_line.type != SIP_REQUEST) {
+        LM_ERR("ERR:I_LIR: The message is not a request\n");
+        return CSCF_RETURN_BREAK;
+    }
+
+    /* check orig uri parameter in topmost Route */
+    if (cscf_has_originating(msg, str1, str2) == CSCF_RETURN_TRUE) {
+        orig = 1;
+        LM_DBG("DBG:I_LIR: orig\n");
+    }
+
+    /* extract data from message */
+    if (orig) {
+        public_identity = cscf_get_asserted_identity(msg);
+    } else {
+        public_identity = cscf_get_public_identity_from_requri(msg);
+    }
+    if (!public_identity.len) {
+        LM_ERR("ERR:I_LIR: Public Identity not found, responding with 400\n");
+        if (orig)
+            cscf_reply_transactional(msg, 400, MSG_400_NO_PUBLIC_FROM);
+        else
+            cscf_reply_transactional(msg, 400, MSG_400_NO_PUBLIC);
+        return CSCF_RETURN_BREAK;
+    }
+    
+    
+    //before we send lets suspend the transaction
+    t = tmb.t_gett();
+    if (t == NULL || t == T_UNDEFINED) {
+        if (tmb.t_newtran(msg) < 0) {
+            LM_ERR("cannot create the transaction for UAR async\n");
+            cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR);
+            return CSCF_RETURN_BREAK;
+        }
+        t = tmb.t_gett();
+        if (t == NULL || t == T_UNDEFINED) {
+            LM_ERR("cannot lookup the transaction\n");
+            cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR);
+            return CSCF_RETURN_BREAK;
+        }
+    }
+
+    saved_t = shm_malloc(sizeof (saved_lir_transaction_t));
+    if (!saved_t) {
+        LM_ERR("no more memory trying to save transaction state\n");
+        return CSCF_RETURN_ERROR;
+
+    }
+    memset(saved_t, 0, sizeof (saved_lir_transaction_t));
+    saved_t->act = cfg_action;
+    
+    saved_t->orig = orig;
+    
+    LM_DBG("Setting default AVP return code used for async callbacks to default as ERROR \n");
+    create_lia_return_code(CSCF_RETURN_ERROR);
+    
+    LM_DBG("Suspending SIP TM transaction\n");
+    if (tmb.t_suspend(msg, &saved_t->tindex, &saved_t->tlabel) < 0) {
+        LM_ERR("failed to suspend the TM processing\n");
+        free_saved_lir_transaction_data(saved_t);
+
+        cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR);
+        return CSCF_RETURN_BREAK;
+    }
+    
+    if (cxdx_send_lir(msg, public_identity, saved_t) != 0) {
+        LM_ERR("ERR:I_LIR: Error sending LIR or LIR time-out\n");
+        tmb.t_cancel_suspend(saved_t->tindex, saved_t->tlabel);
+        free_saved_lir_transaction_data(saved_t);
+        cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR);
+        
+        if (public_identity.s && !orig)
+        shm_free(public_identity.s); // shm_malloc in cscf_get_public_identity_from_requri		
+        return CSCF_RETURN_BREAK;
+
+    }
+    if (public_identity.s && !orig)
+        shm_free(public_identity.s); // shm_malloc in cscf_get_public_identity_from_requri		
+    
+    //we use async replies therefore we send break and not true when successful
+    return CSCF_RETURN_BREAK;
+}

+ 67 - 0
modules/icscf/location.h

@@ -0,0 +1,67 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#ifndef ICSCF_LOCATION_H
+#define ICSCF_LOCATION_H
+
+
+#include "scscf_list.h"
+#include <stdio.h>
+#include "mod.h"
+#include "sip_messages.h"
+#include "../../lib/ims/ims_getters.h"
+
+extern struct cdp_binds cdpb;//cdp binds functions
+
+/**
+ * Perform an LIR
+ * @param msg - sip message
+ * @returns 1 on success or 0 on failure
+ */
+int I_perform_location_information_request(struct sip_msg* msg, char* str1, char* str2);
+
+
+#endif
+

+ 311 - 0
modules/icscf/mod.c

@@ -0,0 +1,311 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#include "../../timer.h"
+#include "../../modules/sl/sl.h"
+
+#include "mod.h"
+#include "scscf_list.h"
+#include "cxdx_uar.h"
+#include "cxdx_lir.h"
+#include "db.h"
+#include "nds.h"
+
+MODULE_VERSION
+
+struct tm_binds tmb;
+struct cdp_binds cdpb;
+cdp_avp_bind_t *cdp_avp;
+
+/** SL API structure */
+sl_api_t slb;
+
+
+//module parameters
+char* icscf_db_url="mysql://icscf:heslo@localhost/hssdata";     /**< DB URL */
+char* icscf_db_nds_table="nds_trusted_domains";                         /**< NDS table in DB */
+char* icscf_db_scscf_table="s_cscf";                                            /**< S-CSCF table in db */
+char* icscf_db_capabilities_table="s_cscf_capabilities";        /**< S-CSCF capabilities table in db */
+
+int icscf_hash_size = 128;
+int scscf_entry_expiry = 300;
+
+/* parameters storage */
+char* cxdx_dest_realm_s = "ims.smilecoms.com";
+str cxdx_dest_realm;
+
+//Only used if we want to force the Rx peer
+//Usually this is configured at a stack level and the first request uses realm routing
+char* cxdx_forced_peer_s = "";
+str cxdx_forced_peer;
+
+/** 
+ * Name of the route, if a user is not found in the HSS (LIR)
+ */
+char* route_lir_user_unknown=0; /* default is the main route */
+/** 
+ * Number of the route, if a user is not found in the HSS (LIR)
+ */
+int route_lir_user_unknown_no=-1;
+
+/** 
+ * Name of the route, if a user is not found in the HSS (UAR)
+ */
+char* route_uar_user_unknown=0; /* default is the main route */
+/** 
+ * Number of the route, if a user is not found in the HSS (UAR)
+ */
+int route_uar_user_unknown_no=-1;
+
+
+/** module functions */
+static int mod_init(void);
+static int fixup_uar(void** param, int param_no);
+static int fixup_lir(void** param, int param_no);
+
+static cmd_export_t cmds[] = {
+    {"I_perform_user_authorization_request", (cmd_function) I_perform_user_authorization_request, 1, fixup_uar, 0, REQUEST_ROUTE},
+    {"I_perform_location_information_request", (cmd_function) I_perform_location_information_request, 0, fixup_lir, 0, REQUEST_ROUTE},
+    {"I_scscf_select", (cmd_function) I_scscf_select, 1, 0, 0, REQUEST_ROUTE | FAILURE_ROUTE},
+    {"I_scscf_drop", (cmd_function) I_scscf_drop, 0, 0, 0, REQUEST_ROUTE | ONREPLY_ROUTE | FAILURE_ROUTE},
+    { 0, 0, 0, 0, 0, 0}
+};
+
+static param_export_t params[] = {
+    {"route_lir_user_unknown", PARAM_STRING, &route_lir_user_unknown},
+    {"route_uar_user_unknown", PARAM_STRING, &route_uar_user_unknown},
+    {"scscf_entry_expiry", INT_PARAM, &scscf_entry_expiry},
+    {"db_url", 					STR_PARAM, &icscf_db_url},
+    {"db_nds_table", 			STR_PARAM, &icscf_db_nds_table},
+    {"db_scscf_table", 			STR_PARAM, &icscf_db_scscf_table},
+    {"db_capabilities_table", 	STR_PARAM, &icscf_db_capabilities_table},
+    {"cxdx_forced_peer", STR_PARAM, &cxdx_forced_peer_s},
+    {"cxdx_dest_realm", STR_PARAM, &cxdx_dest_realm_s},
+    {0, 0, 0}
+};
+
+stat_export_t mod_stats[] = {
+	{"uar_avg_response_time" ,  	STAT_IS_FUNC, 	(stat_var**)get_avg_uar_response_time	},
+	{"lir_avg_response_time" ,  	STAT_IS_FUNC, 	(stat_var**)get_avg_lir_response_time	},
+	{"uar_timeouts" ,  				0, 				(stat_var**)&stat_uar_timeouts  		},
+	{"lir_timeouts" ,  				0, 				(stat_var**)&stat_lir_timeouts  		},
+	{0,0,0}
+};
+
+/** module exports */
+struct module_exports exports = {
+    "icscf",
+    DEFAULT_DLFLAGS, /* dlopen flags */
+    cmds, /* Exported functions */
+    params,
+    mod_stats, /* exported statistics */
+    0, /* exported MI functions */
+    0, /* exported pseudo-variables */
+    0, /* extra processes */
+    mod_init, /* module initialization function */
+    0,
+    0,
+    0 /* per-child init function */
+};
+
+static int fix_parameters() {
+    cxdx_forced_peer.s = cxdx_forced_peer_s;
+    cxdx_forced_peer.len = strlen(cxdx_forced_peer_s);
+
+    cxdx_dest_realm.s = cxdx_dest_realm_s;
+    cxdx_dest_realm.len = strlen(cxdx_dest_realm_s);
+    return 1;
+}
+/**
+ * init module function
+ */
+static int mod_init(void) {
+	cdp_avp = 0;
+	int route_no;
+
+	/* fix the parameters */
+	if (!fix_parameters()) goto error;
+
+#ifdef STATISTICS
+	if (register_module_stats( exports.name, mod_stats) != 0) {
+		LM_ERR("failed to register core statistics\n");
+		goto error;
+	}
+	if (!register_stats()){
+		LM_ERR("Unable to register statistics\n");
+		goto error;
+	}
+#endif
+
+	/* initialising hash table*/
+	if (!i_hash_table_init(icscf_hash_size)) {
+		LM_ERR("Error initializing the Hash Table for stored S-CSCF lists\n");
+		goto error;
+	}
+
+	/* load the TM API */
+	if (load_tm_api(&tmb) != 0) {
+		LM_ERR("can't load TM API\n");
+		goto error;
+	}
+
+	/* load the CDP API */
+	if (load_cdp_api(&cdpb) != 0) {
+		LM_ERR("can't load CDP API\n");
+		goto error;
+	}
+
+	cdp_avp = load_cdp_avp();
+	if (!cdp_avp) {
+		LM_ERR("can't load CDP_AVP API\n");
+		goto error;
+	}
+
+	/* cache the trusted domain names and capabilities */
+	/* bind to the db module */
+	if (icscf_db_bind(icscf_db_url) < 0)
+		goto error;
+
+	/* bind the SL API */
+	if (sl_load_api(&slb) != 0) {
+		LM_ERR("cannot bind to SL API\n");
+		return -1;
+	}
+
+	icscf_db_init(icscf_db_url, icscf_db_nds_table, icscf_db_scscf_table,
+			icscf_db_capabilities_table);
+
+	I_NDS_get_trusted_domains();
+	I_get_capabilities();
+
+	icscf_db_close();
+
+	if (!i_hash_table_init(icscf_hash_size)) {
+		LOG(
+				L_ERR,
+				"ERR"M_NAME":mod_init: Error initializing the Hash Table for stored S-CSCF lists\n");
+		goto error;
+	}
+
+	/* register global timer used to get rid of stale scscf_lists*/
+	if (register_timer(icscf_timer_routine, 0, 60) < 0) {
+		LM_ERR("failed to register timer \n");
+		return -1;
+	}
+	
+	/* try to fix the xmlrpc route */
+	if (route_lir_user_unknown){
+		route_no=route_get(&main_rt, route_lir_user_unknown);
+		if (route_no==-1){
+			ERR("icscf: failed to fix route \"%s\": route_get() failed\n",
+					route_lir_user_unknown);
+			return -1;
+		}
+		if (main_rt.rlist[route_no]==0){
+			WARN("icscf: icscf route \"%s\" is empty / doesn't exist\n",
+					route_lir_user_unknown);
+		}
+		route_lir_user_unknown_no=route_no;
+	}
+	/* try to fix the xmlrpc route */
+	if (route_uar_user_unknown){
+		route_no=route_get(&main_rt, route_uar_user_unknown);
+		if (route_no==-1){
+			ERR("icscf: failed to fix route \"%s\": route_get() failed\n",
+					route_uar_user_unknown);
+			return -1;
+		}
+		if (main_rt.rlist[route_no]==0){
+			WARN("icscf: icscf route \"%s\" is empty / doesn't exist\n",
+					route_uar_user_unknown);
+		}
+		route_uar_user_unknown_no=route_no;
+	}
+
+	LM_DBG("ICSCF module successfully initialised\n");
+
+	return 0;
+	error:
+	LM_ERR("Failed to initialise ICSCF module\n");
+	return -1;
+}
+
+static int fixup_uar(void** param, int param_no)
+{
+	uar_param_t *ap;
+	if(param_no!=1)
+		return 0;
+	ap = (uar_param_t*)pkg_malloc(sizeof(uar_param_t));
+	if(ap==NULL)
+	{
+		LM_ERR("no more pkg\n");
+		return -1;
+	}
+	memset(ap, 0, sizeof(uar_param_t));
+	ap->paction = get_action_from_param(param, param_no);
+	if(fixup_igp_null(param, param_no)<0)
+		return -1;
+	ap->ivalue = (gparam_t*)(*param);
+	*param = (void*)ap;
+	return 0;
+}
+
+static int fixup_lir(void** param, int param_no)
+{
+	lir_param_t *ap;
+	if(param_no!=1)
+		return 0;
+	ap = (lir_param_t*)pkg_malloc(sizeof(lir_param_t));
+	if(ap==NULL)
+	{
+		LM_ERR("no more pkg\n");
+		return -1;
+	}
+	memset(ap, 0, sizeof(lir_param_t));
+	ap->paction = get_action_from_param(param, param_no);
+	*param = (void*)ap;
+	return 0;
+}
+

+ 89 - 0
modules/icscf/mod.h

@@ -0,0 +1,89 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+ 
+/**
+ * \file
+ * 
+ * Interrogating-CSCF - SER module interface
+ * 
+ * Scope:
+ * - Exports parameters and functions
+ * - Initialization functions
+ * 
+ *  \author Dragos Vingarzan vingarzan -at- fokus dot fraunhofer dot de
+ * 
+ */
+
+
+#ifndef I_CSCF_MOD_H
+#define I_CSCF_MOD_H
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "stats.h"
+#include "registration.h"
+#include "location.h"
+#include "../../sr_module.h"
+#include "../../modules/tm/tm_load.h"
+#include "../../modules/dialog2/dlg_load.h"
+#include "../cdp_avp/mod_export.h"
+
+#define MOD_NAME "icscf"
+
+/** Return and break the execution of routng script */
+#define CSCF_RETURN_BREAK	0 
+/** Return true in the routing script */
+#define CSCF_RETURN_TRUE	1
+/** Return false in the routing script */
+#define CSCF_RETURN_FALSE -1
+/** Return error in the routing script */
+#define CSCF_RETURN_ERROR -2
+
+extern int route_uar_user_unknown_no; 
+extern int route_lir_user_unknown_no; 
+
+#endif /* I_CSCF_MOD_H */

+ 219 - 0
modules/icscf/nds.c

@@ -0,0 +1,219 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+ 
+/**
+ * \file
+ * 
+ * Interrogating-CSCF - Network Domain Security Operations
+ * 
+ *  \author Dragos Vingarzan vingarzan -at- fokus dot fraunhofer dot de
+ * 
+ */
+#include "nds.h"
+
+#include "../../parser/hf.h"
+#include "../../parser/msg_parser.h"
+#include "../../parser/parse_via.h"
+#include "../../mem/shm_mem.h"
+#include "../../modules/sl/sl.h"
+
+#include "mod.h"
+#include "db.h"
+
+extern sl_api_t slb;
+
+
+/** Defines the untrusted headers */
+str untrusted_headers[]={
+	{"P-Asserted-Identity",19},
+	{"P-Access-Network-Info",21},
+	{"P-Charging-Vector",17},
+	{"P-Charging-Function-Addresses",29},
+	{0,0}	
+}; 
+
+/** The cached list of trusted domains */
+static str *trusted_domains=0;
+
+
+
+/**
+ * Checks if a request comes from a trusted domain.
+ * If not calls function to respond with 403 to REGISTER or clean the message of
+ * untrusted headers
+ * @param msg - the SIP message
+ * @param str1 - not used
+ * @param str2 - not used
+ * @returns #CSCF_RETURN_TRUE if trusted, #CSCF_RETURN_FALSE if not , #CSCF_RETURN_ERROR on REGISTER or error 
+ */
+int I_NDS_check_trusted(struct sip_msg* msg, char* str1, char* str2)
+{
+	int result;
+	LM_DBG("DBG:I_NDS_check_trusted: Starting ...\n");
+	if (msg->first_line.type!=SIP_REQUEST) {
+		LM_ERR("ERR:I_NDS_check_trusted: The message is not a request\n");
+		result = CSCF_RETURN_TRUE;	
+		goto done;
+	}
+	if (I_NDS_is_trusted(msg,str1,str2)){
+		LM_DBG("INF:I_NDS_check_trusted: Message comes from a trusted domain\n");
+		result = CSCF_RETURN_TRUE;	
+		goto done;
+	} else {
+		LM_DBG("INF:I_NDS_check_trusted: Message comes from an untrusted domain\n");
+		result = CSCF_RETURN_FALSE;					
+		if (msg->first_line.u.request.method.len==8 &&
+			memcmp(msg->first_line.u.request.method.s,"REGISTER",8)==0){
+			slb.sreply(msg,403,&str_msg_403);
+			LM_DBG("INF:I_NDS_check_trusted: REGISTER request terminated.\n");
+		} else {
+			if (!I_NDS_strip_headers(msg,str1,str2)){
+				result = CSCF_RETURN_ERROR;
+				slb.sreply(msg,500,&str_msg_500);
+				LM_DBG("INF:I_NDS_check_trusted: Stripping untrusted headers failed, Responding with 500.\n");				
+			}
+		}					
+	}
+	
+done:	
+	LM_DBG("DBG:I_NDS_check_trusted: ... Done\n");
+	return result;
+}
+
+/**
+ * Decides if a message comes from a trusted domain.
+ * \todo - SOLVE THE LOCKING PROBLEM - THIS IS A READER
+ * @param msg - the SIP request message
+ * @param str1 - not used
+ * @param str2 - not used
+ * @returns #CSCF_RETURN_TRUE if trusted, #CSCF_RETURN_FALSE 
+ */
+int I_NDS_is_trusted(struct sip_msg *msg, char* str1, char* str2)
+{
+	struct via_body *vb;
+	str subdomain;
+	int i;
+	
+	vb = msg->via1;
+	if (!vb) {
+		LM_ERR("ERR:I_NDS_is_trusted: Error VIA1 hdr not found\n");
+		return 0;
+	}
+	subdomain=vb->host;
+	LM_DBG("DBG:I_NDS_is_trusted: Message comes from <%.*s>\n",
+		subdomain.len,subdomain.s);
+		
+	i=0;
+	while(trusted_domains[i].len){
+		if (trusted_domains[i].len<=subdomain.len){
+			if (strncasecmp(subdomain.s+subdomain.len-trusted_domains[i].len,
+				trusted_domains[i].s,
+				trusted_domains[i].len)==0 &&
+					(trusted_domains[i].len==subdomain.len ||
+					 subdomain.s[subdomain.len-trusted_domains[i].len-1]=='.'))
+			{  					
+				LM_DBG("DBG:I_NDS_is_trusted: <%.*s> matches <%.*s>\n",
+					subdomain.len,subdomain.s,trusted_domains[i].len,trusted_domains[i].s);
+				return CSCF_RETURN_TRUE;
+			} else {
+//				LM_DBG("DBG:I_NDS_is_trusted: <%.*s> !matches <%.*s>\n",
+//					subdomain.len,subdomain.s,trusted_domains[i].len,trusted_domains[i].s);
+			}					
+		}
+		i++;
+	}
+	return CSCF_RETURN_FALSE;
+}
+
+
+
+/**
+ * Strips untrusty headers from a SIP request.
+ * Searched headers are declared in untrusted_headers 
+ * @param msg - the SIP request message
+ * @param str1 - not used
+ * @param str2 - not used
+ * @returns the number of headers stripped
+ */
+int I_NDS_strip_headers(struct sip_msg *msg, char* str1, char* str2)
+{
+	struct hdr_field *hdr;
+	int i,cnt=0;
+	if (parse_headers(msg,HDR_EOH_F,0)<0) return 0;
+	for (hdr = msg->headers;hdr;hdr = hdr->next)
+		for (i=0;untrusted_headers[i].len;i++)
+			if (hdr->name.len == untrusted_headers[i].len &&
+				strncasecmp(hdr->name.s,untrusted_headers[i].s,hdr->name.len)==0){				
+				//if (!cscf_del_header(msg,hdr)) return 0; TODO
+				cnt++;
+			}
+	LM_DBG("DBG:I_NDS_strip_headers: Deleted %d headers\n",cnt);			
+	return cnt;
+}
+
+
+
+/**
+ * Refreshes the trusted domain list reading them from the db.
+ * Drops the old cache and queries the db
+ * \todo - IMPLEMENT A WAY TO PUSH AN EXTERNAL EVENT FOR THIS
+ * \todo - SOLVE THE LOCKING PROBLEM - THIS IS A WRITER
+ * @returns 1 on success, 0 on failure
+ */
+int I_NDS_get_trusted_domains()
+{
+	int i;
+	/* free the old cache */
+	if (trusted_domains!=0){
+		i=0;
+		while(trusted_domains[i].s){
+			shm_free(trusted_domains[i].s);
+			i++;
+		}
+		shm_free(trusted_domains);
+	}
+	return icscf_db_get_nds(&trusted_domains);
+}
+

+ 76 - 0
modules/icscf/nds.h

@@ -0,0 +1,76 @@
+
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+ 
+/**
+ * \file
+ * 
+ * Interrogating-CSCF - Network Domain Security Operations
+ * 
+ *  \author Dragos Vingarzan vingarzan -at- fokus dot fraunhofer dot de
+ * 
+ */
+
+
+#ifndef I_CSCF_NDS_H
+#define I_CSCF_NDS_H
+
+#include "../../sr_module.h"
+ 
+#define MSG_403 "Forbidden" 
+#define MSG_500 "I-CSCF Error while stripping untrusted headers"
+
+static str str_msg_403 = {MSG_403, 9};
+static str str_msg_500 = {MSG_500, 46};
+
+int I_NDS_check_trusted(struct sip_msg* msg, char* str1, char* str2);
+
+int I_NDS_is_trusted(struct sip_msg *msg, char* str1, char* str2);
+
+int I_NDS_strip_headers(struct sip_msg *msg, char* str1, char* str2);
+
+int I_NDS_get_trusted_domains();
+
+#endif /* I_CSCF_NDS_H */

+ 211 - 0
modules/icscf/registration.c

@@ -0,0 +1,211 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+
+#include "registration.h"
+#include "../../action.h" /* run_actions */
+#include "cxdx_uar.h"
+
+extern int route_uar_user_unknown_no;
+
+/**
+ * Perform User Authorization Request.
+ * creates and send the user authorization query
+ * @param msg - the SIP message
+ * @param str1 - the realm
+ * @param str2 - if to do capabilities
+ * @returns true if OK, false if not
+ */
+int I_perform_user_authorization_request(struct sip_msg* msg, char* str1, char* str2) {
+    str private_identity, public_identity, visited_network_id;
+    int authorization_type = AVP_IMS_UAR_REGISTRATION;
+    int expires = 3600;
+    struct hdr_field *hdr;
+    str realm;
+    contact_t *c;
+    int sos_reg = 0;
+    contact_body_t *b = 0;
+    str call_id;
+    saved_uar_transaction_t* saved_t;
+    tm_cell_t *t = 0;
+    int intvalue_param;
+    cfg_action_t* cfg_action;
+
+    uar_param_t* ap = (uar_param_t*) str1;
+    if (fixup_get_ivalue(msg, ap->ivalue, &intvalue_param) != 0) {
+        LM_ERR("no int value param passed\n");
+        return CSCF_RETURN_ERROR;
+    }
+    cfg_action = ap->paction->next;
+
+    realm = cscf_get_realm_from_ruri(msg);
+
+    //check if we received what we should, we do this even though it should be done in cfg file - double checking!
+    if (msg->first_line.type != SIP_REQUEST) {
+        LM_ERR("ERR:I_UAR: The message is not a request\n");
+        return CSCF_RETURN_ERROR;
+    }
+    if (msg->first_line.u.request.method.len != 8 ||
+            memcmp(msg->first_line.u.request.method.s, "REGISTER", 8) != 0) {
+        LM_ERR("ERR:I_UAR: The method is not a REGISTER\n");
+        return CSCF_RETURN_ERROR;
+    }
+
+    private_identity = cscf_get_private_identity(msg, realm);
+    if (!private_identity.len) {
+        LM_ERR("ERR:I_UAR: Private Identity not found, responding with 400\n");
+        cscf_reply_transactional(msg, 400, MSG_400_NO_PRIVATE);
+        return CSCF_RETURN_BREAK;
+    }
+
+    public_identity = cscf_get_public_identity(msg);
+    if (!public_identity.len) {
+        LM_ERR("ERR:I_UAR: Public Identity not found, responding with 400\n");
+        cscf_reply_transactional(msg, 400, MSG_400_NO_PUBLIC);
+        return CSCF_RETURN_BREAK;
+
+    }
+
+    b = cscf_parse_contacts(msg);
+
+    if (!b || (!b->contacts && !b->star)) {
+        LM_DBG("DBG:I_UAR: No contacts found\n");
+        return CSCF_RETURN_ERROR;
+    }
+
+    for (c = b->contacts; c; c = c->next) {
+
+        sos_reg = cscf_get_sos_uri_param(c->uri);
+        if (sos_reg == -1) {
+            //error case
+            LM_ERR("ERR:I_UAR: MSG_400_MALFORMED_CONTACT, responding with 400\n");
+            cscf_reply_transactional(msg, 400, MSG_400_MALFORMED_CONTACT);
+            return CSCF_RETURN_BREAK;
+        } else if (sos_reg == -2) {
+            LM_ERR("ERR:I_UAR: MSG_500_SERVER_ERROR_OUT_OF_MEMORY, responding with 500\n");
+            cscf_reply_transactional(msg, 500, MSG_500_SERVER_ERROR_OUT_OF_MEMORY);
+            return CSCF_RETURN_BREAK;
+        }
+    }
+
+    visited_network_id = cscf_get_visited_network_id(msg, &hdr);
+    if (!visited_network_id.len) {
+        LM_ERR("ERR:I_UAR: Visited Network Identity not found, responding with 400\n");
+        cscf_reply_transactional(msg, 400, MSG_400_NO_VISITED);
+        return CSCF_RETURN_BREAK;
+    }
+
+    if (atoi(str1)) authorization_type = AVP_IMS_UAR_REGISTRATION_AND_CAPABILITIES;
+    else {
+        expires = cscf_get_max_expires(msg, 0);
+        if (expires == 0) authorization_type = AVP_IMS_UAR_DE_REGISTRATION;
+    }
+
+    LM_DBG("SENDING UAR: PI: [%.*s], PU: [%.*s], VNID: [%.*s]\n", private_identity.len, private_identity.s,
+            public_identity.len, public_identity.s,
+            visited_network_id.len, visited_network_id.s);
+
+    //before we send lets suspend the transaction
+    t = tmb.t_gett();
+    if (t == NULL || t == T_UNDEFINED) {
+        if (tmb.t_newtran(msg) < 0) {
+            LM_ERR("cannot create the transaction for UAR async\n");
+            cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR);
+            return CSCF_RETURN_BREAK;
+        }
+        t = tmb.t_gett();
+        if (t == NULL || t == T_UNDEFINED) {
+            LM_ERR("cannot lookup the transaction\n");
+            cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR);
+            return CSCF_RETURN_BREAK;
+        }
+    }
+
+    saved_t = shm_malloc(sizeof (saved_uar_transaction_t));
+    if (!saved_t) {
+        LM_ERR("no more memory trying to save transaction state\n");
+        return CSCF_RETURN_ERROR;
+
+    }
+    memset(saved_t, 0, sizeof (saved_uar_transaction_t));
+    saved_t->act = cfg_action;
+
+    call_id = cscf_get_call_id(msg, 0);
+    saved_t->callid.s = (char*) shm_malloc(call_id.len + 1);
+    if (!saved_t->callid.s) {
+    	LM_ERR("no more memory trying to save transaction state : callid\n");
+    	shm_free(saved_t);
+    	return CSCF_RETURN_ERROR;
+    }
+    memset(saved_t->callid.s, 0, call_id.len + 1);
+    memcpy(saved_t->callid.s, call_id.s, call_id.len);
+    saved_t->callid.len = call_id.len;
+
+    LM_DBG("Setting default AVP return code used for async callbacks to default as ERROR \n");
+    create_uaa_return_code(CSCF_RETURN_ERROR);
+    
+    LM_DBG("Suspending SIP TM transaction\n");
+    if (tmb.t_suspend(msg, &saved_t->tindex, &saved_t->tlabel) < 0) {
+        LM_ERR("failed to suspend the TM processing\n");
+        free_saved_uar_transaction_data(saved_t);
+
+        cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR);
+        return CSCF_RETURN_BREAK;
+    }
+
+    if (cxdx_send_uar(msg, private_identity, public_identity, visited_network_id, authorization_type, sos_reg, saved_t) != 0) {
+        LM_ERR("ERR:I_UAR: Error sending UAR or UAR time-out\n");
+        tmb.t_cancel_suspend(saved_t->tindex, saved_t->tlabel);
+        free_saved_uar_transaction_data(saved_t);
+        cscf_reply_transactional(msg, 480, MSG_480_DIAMETER_ERROR);
+        return CSCF_RETURN_BREAK;
+
+    }
+    //we use async replies therefore we send break and not true when successful
+    return CSCF_RETURN_BREAK;
+}
+
+
+

+ 70 - 0
modules/icscf/registration.h

@@ -0,0 +1,70 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#ifndef CXDX_UAR_H
+#define CXDX_UAR_H
+
+#include "scscf_list.h"
+#include <stdio.h>
+#include "mod.h"
+#include "../../lib/ims/ims_getters.h"
+
+extern struct cdp_binds cdpb;
+
+/**
+ * Perform User Authorization Request.
+ * creates and send the user authorization query
+ * @param msg - the SIP message
+ * @param str1 - the realm
+ * @param str2 - if to do capabilities
+ * @returns true if OK, false if not
+ */
+int I_perform_user_authorization_request(struct sip_msg* msg, char* str1, char* str2);
+
+
+
+
+#endif
+

+ 586 - 0
modules/icscf/scscf_list.c

@@ -0,0 +1,586 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#include "scscf_list.h"
+#include "db.h"
+#include "../../lib/ims/useful_defs.h"
+
+extern int scscf_entry_expiry; //time for scscf entries to remain the scscf_list
+
+extern struct tm_binds tmb; //Structure with pointers to tm funcs
+
+int i_hash_size;
+i_hash_slot *i_hash_table = 0;
+
+scscf_capabilities *SCSCF_Capabilities = 0;
+int SCSCF_Capabilities_cnt = 0;
+
+/**
+ * Refreshes the capabilities list reading them from the db.
+ * Drops the old cache and queries the db
+ * \todo - IMPLEMENT A WAY TO PUSH AN EXTERNAL EVENT FOR THIS
+ * \todo - SOLVE THE LOCKING PROBLEM - THIS IS A WRITER
+ * @returns 1 on success, 0 on failure
+ */
+int I_get_capabilities() {
+    int i, j, r;
+    /* free the old cache */
+    if (SCSCF_Capabilities != 0) {
+        for (i = 0; i < SCSCF_Capabilities_cnt; i++) {
+            if (SCSCF_Capabilities[i].capabilities)
+                shm_free(SCSCF_Capabilities[i].capabilities);
+        }
+        shm_free(SCSCF_Capabilities);
+    }
+
+    SCSCF_Capabilities_cnt = icscf_db_get_scscf(&SCSCF_Capabilities);
+
+    r = icscf_db_get_capabilities(&SCSCF_Capabilities, SCSCF_Capabilities_cnt);
+
+    LM_DBG("DBG:------  S-CSCF Map with Capabilities  begin ------\n");
+    if (SCSCF_Capabilities != 0) {
+        for (i = 0; i < SCSCF_Capabilities_cnt; i++) {
+            LM_DBG("DBG:S-CSCF [%d] <%.*s>\n", SCSCF_Capabilities[i].id_s_cscf, SCSCF_Capabilities[i].scscf_name.len, SCSCF_Capabilities[i].scscf_name.s);
+            for (j = 0; j < SCSCF_Capabilities[i].cnt; j++)
+                LM_DBG("DBG:       \t [%d]\n", SCSCF_Capabilities[i].capabilities[j]);
+        }
+    }
+    LM_DBG("DBG:------  S-CSCF Map with Capabilities  end ------\n");
+
+    return r;
+}
+
+/**
+ * Adds the name to the list starting at root, ordered by score.
+ * Returns the new root
+ */
+static inline scscf_entry* I_add_to_scscf_list(scscf_entry *root, str name, int score, int originating) {
+    scscf_entry *x, *i;
+
+    //duplicate?
+    for (i = root; i; i = i->next)
+        if (name.len == i->scscf_name.len &&
+                strncasecmp(name.s, i->scscf_name.s, name.len) == 0)
+            return root;
+
+    x = new_scscf_entry(name, score, originating);
+    if (!x) return root;
+
+    if (!root) {
+        return x;
+    }
+    if (root->score < x->score) {
+        x->next = root;
+        return x;
+    }
+    i = root;
+    while (i->next && i->next->score > x->score)
+        i = i->next;
+    x->next = i->next;
+    i->next = x;
+    return root;
+}
+
+/**
+ * Initialize the hash with S-CSCF lists
+ */
+int i_hash_table_init(int hash_size) {
+    int i;
+
+    i_hash_size = hash_size;
+    i_hash_table = shm_malloc(sizeof (i_hash_slot) * i_hash_size);
+
+    if (!i_hash_table) return 0;
+
+    memset(i_hash_table, 0, sizeof (i_hash_slot) * i_hash_size);
+
+    for (i = 0; i < i_hash_size; i++) {
+        i_hash_table[i].lock = lock_alloc();
+        if (!i_hash_table[i].lock) {
+            LM_ERR("ERR:i_hash_table_init(): Error creating lock\n");
+            return 0;
+        }
+        i_hash_table[i].lock = lock_init(i_hash_table[i].lock);
+    }
+
+    return 1;
+}
+
+/**
+ * Frees memory for scscf list
+ */
+void free_scscf_list(scscf_list *sl) {
+    scscf_entry *i;
+    if (!sl) return;
+    if (sl->call_id.s) shm_free(sl->call_id.s);
+    while (sl->list) {
+        i = sl->list->next;
+        if (sl->list->scscf_name.s) shm_free(sl->list->scscf_name.s);
+        shm_free(sl->list);
+        sl->list = i;
+    }
+    shm_free(sl);
+}
+
+/**
+ * Returns a list of S-CSCFs that we should try on, based on the
+ * capabilities requested
+ * \todo - order the list according to matched optionals - r
+ * @param scscf_name - the first S-CSCF if specified
+ * @param m - mandatory capabilities list
+ * @param mcnt - mandatory capabilities list size
+ * @param o - optional capabilities list
+ * @param ocnt - optional capabilities list size
+ * @param orig - indicates originating session case
+ * @returns list of S-CSCFs, terminated with a str={0,0}
+ */
+scscf_entry* I_get_capab_ordered(str scscf_name, int *m, int mcnt, int *o, int ocnt, str *p, int pcnt, int orig) {
+    scscf_entry *list = 0;
+    int i, r;
+
+    if (scscf_name.len) list = I_add_to_scscf_list(list, scscf_name, MAXINT, orig);
+
+    for (i = 0; i < pcnt; i++)
+        list = I_add_to_scscf_list(list, p[i], MAXINT - i, orig);
+
+    for (i = 0; i < SCSCF_Capabilities_cnt; i++) {
+        r = I_get_capab_match(SCSCF_Capabilities + i, m, mcnt, o, ocnt);
+        if (r != -1) {
+            list = I_add_to_scscf_list(list, SCSCF_Capabilities[i].scscf_name, r, orig);
+            LM_DBG("DBG:I_get_capab_ordered: <%.*s> Added to the list, orig=%d\n",
+                    SCSCF_Capabilities[i].scscf_name.len, SCSCF_Capabilities[i].scscf_name.s, orig);
+        }
+    }
+    return list;
+}
+
+/**
+ * Creates new scscf entry structure
+ */
+scscf_entry* new_scscf_entry(str name, int score, int orig) {
+    scscf_entry *x = 0;
+    x = shm_malloc(sizeof (scscf_entry));
+    if (!x) {
+        LM_ERR("ERR:new_scscf_entry: Error allocating %lx bytes\n",
+                sizeof (scscf_entry));
+        return 0;
+    }
+    /* duplicate always the scscf_name because of possible list reloads and scscf_name coming in LIA/UAA */
+    if (orig) x->scscf_name.s = shm_malloc(name.len + 5);
+    else x->scscf_name.s = shm_malloc(name.len);
+    if (!x->scscf_name.s) {
+        LM_ERR("ERR:new_scscf_entry: Error allocating %d bytes\n",
+                orig ? name.len + 5 : name.len);
+        shm_free(x);
+        return 0;
+    }
+    memcpy(x->scscf_name.s, name.s, name.len);
+    x->scscf_name.len = name.len;
+    if (orig) {
+        memcpy(x->scscf_name.s + name.len, ";orig", 5);
+        x->scscf_name.len += 5;
+    }
+
+    LM_DBG("INFO:new_scscf_entry:  <%.*s>\n", x->scscf_name.len, x->scscf_name.s);
+
+    x->score = score;
+
+    x->start_time = time(0);
+
+    x->next = 0;
+    return x;
+}
+
+/**
+ * Returns the matching rank of a S-CSCF
+ * \todo - optimize the search as O(n^2) is hardly desireable
+ * @param c - the capabilities of the S-CSCF
+ * @param m - mandatory capabilities list requested
+ * @param mcnt - mandatory capabilities list size
+ * @param o - optional capabilities list
+ * @param ocnt - optional capabilities list sizeint I_get_capab_match(icscf_capabilities *c,int *m,int mcnt,int *o,int ocnt)
+ * @returns - -1 if mandatory not satisfied, else count of matched optional capab
+ */
+int I_get_capab_match(scscf_capabilities *c, int *m, int mcnt, int *o, int ocnt) {
+    int r = 0, i, j, t = 0;
+    for (i = 0; i < mcnt; i++) {
+        t = 0;
+        for (j = 0; j < c->cnt; j++)
+            if (m[i] == c->capabilities[j]) {
+                t = 1;
+                break;
+            }
+        if (!t) return -1;
+    }
+    for (i = 0; i < ocnt; i++) {
+        for (j = 0; j < c->cnt; j++)
+            if (o[i] == c->capabilities[j]) r++;
+    }
+    return r;
+}
+
+int add_scscf_list(str call_id, scscf_entry *sl) {
+    scscf_list *l;
+    unsigned int hash = get_call_id_hash(call_id, i_hash_size);
+
+    l = new_scscf_list(call_id, sl);
+    if (!l) return 0;
+
+    i_lock(hash);
+    l->prev = 0;
+    l->next = i_hash_table[hash].head;
+    if (l->next) l->next->prev = l;
+    i_hash_table[hash].head = l;
+    if (!i_hash_table[hash].tail) i_hash_table[hash].tail = l;
+    i_unlock(hash);
+
+    return 1;
+}
+
+/**
+ * Computes the hash for a string.
+ */
+inline unsigned int get_call_id_hash(str callid, int hash_size) {
+#define h_inc h+=v^(v>>3)
+    char* p;
+    register unsigned v;
+    register unsigned h;
+
+    h = 0;
+    for (p = callid.s; p <= (callid.s + callid.len - 4); p += 4) {
+        v = (*p << 24)+(p[1] << 16)+(p[2] << 8) + p[3];
+        h_inc;
+    }
+    v = 0;
+    for (; p < (callid.s + callid.len); p++) {
+        v <<= 8;
+        v += *p;
+    }
+    h_inc;
+
+    h = ((h)+(h >> 11))+((h >> 13)+(h >> 23));
+    return (h) % hash_size;
+#undef h_inc
+}
+
+scscf_list* new_scscf_list(str call_id, scscf_entry *sl) {
+    scscf_list *l;
+
+    l = shm_malloc(sizeof (scscf_list));
+    if (!l) {
+        LM_ERR("ERR:new_scscf_list(): Unable to alloc %lx bytes\n",
+                sizeof (scscf_list));
+        goto error;
+    }
+    memset(l, 0, sizeof (scscf_list));
+
+    STR_SHM_DUP(l->call_id, call_id, "shm");
+    l->list = sl;
+
+    return l;
+error:
+    out_of_memory :
+    if (l) {
+        shm_free(l);
+    }
+    return 0;
+}
+
+/**
+ * Locks the required part of hash with S-CSCF lists
+ */
+inline void i_lock(unsigned int hash) {
+
+    lock_get(i_hash_table[(hash)].lock);
+
+}
+
+/**
+ * UnLocks the required part of hash with S-CSCF lists
+ */
+inline void i_unlock(unsigned int hash) {
+    lock_release(i_hash_table[(hash)].lock);
+
+}
+
+static str route_hdr_s = {"Route: <", 8};
+static str route_hdr_e = {">\r\n", 3};
+
+int I_scscf_select(struct sip_msg* msg, char* str1, char* str2) {
+    str call_id, scscf_name = {0, 0};
+    struct sip_msg *req;
+    int result;
+    str hdr = {0, 0};
+
+    call_id = cscf_get_call_id(msg, 0);
+    LM_DBG("I_scscf_select() for call-id <%.*s>\n", call_id.len, call_id.s);
+    if (!call_id.len)
+        return CSCF_RETURN_FALSE;
+
+    scscf_name = take_scscf_entry(call_id);
+
+    if (!scscf_name.len) {
+        LM_DBG("no scscf entry for callid [%.*s]\n", call_id.len, call_id.s);
+        return CSCF_RETURN_FALSE;
+    }
+
+    if (msg->first_line.u.request.method.len == 8 &&
+            strncasecmp(msg->first_line.u.request.method.s, "REGISTER", 8) == 0) {
+        /* REGISTER fwding */
+        if (str1 && str1[0] == '0') {
+            /* first time */
+            if (rewrite_uri(msg, &(scscf_name)) < 0) {
+                LM_ERR("I_UAR_forward: Unable to Rewrite URI\n");
+                result = CSCF_RETURN_FALSE;
+            } else
+                result = CSCF_RETURN_TRUE;
+        } else {
+            /* subsequent */
+            req = msg;
+            append_branch(req, &scscf_name, 0, 0, Q_UNSPECIFIED, 0, 0, 0, 0);
+            result = CSCF_RETURN_TRUE;
+        }
+    } else {
+        /* Another request */
+        result = CSCF_RETURN_TRUE;
+
+        hdr.len = route_hdr_s.len + scscf_name.len + route_hdr_e.len;
+        hdr.s = pkg_malloc(hdr.len);
+        if (!hdr.s) {
+            LM_ERR("ERR:Mw_REQUEST_forward: Error allocating %d bytes\n",
+                    hdr.len);
+            result = CSCF_RETURN_TRUE;
+        }
+        hdr.len = 0;
+        STR_APPEND(hdr, route_hdr_s);
+        STR_APPEND(hdr, scscf_name);
+        STR_APPEND(hdr, route_hdr_e);
+
+        if (!cscf_add_header_first(msg, &hdr, HDR_ROUTE_T)) {
+            pkg_free(hdr.s);
+            result = CSCF_RETURN_TRUE;
+        }
+
+        if (msg->dst_uri.s) pkg_free(msg->dst_uri.s);
+        STR_PKG_DUP(msg->dst_uri, scscf_name, "pkg");
+    }
+
+    return result;
+out_of_memory:
+    if (scscf_name.s) shm_free(scscf_name.s);
+    return CSCF_RETURN_ERROR;
+}
+
+/**
+ * Takes on S-CSCF name for the respective Call-ID from the respective name list.
+ * Don't free the result.s - it is freed later!
+ * @param call_id - the id of the call
+ * @returns the shm_malloced S-CSCF name if found or empty string if list is empty or does not exists
+ */
+str take_scscf_entry(str call_id) {
+    str scscf = {0, 0};
+    scscf_list *l = 0;
+    unsigned int hash = get_call_id_hash(call_id, i_hash_size);
+
+    i_lock(hash);
+    l = i_hash_table[hash].head;
+    while (l) {
+        if (l->call_id.len == call_id.len &&
+                strncasecmp(l->call_id.s, call_id.s, call_id.len) == 0) {
+            if (l->list) {
+                scscf = l->list->scscf_name;
+            }
+            break;
+        }
+        l = l->next;
+    }
+    i_unlock(hash);
+    return scscf;
+}
+
+int I_scscf_drop(struct sip_msg* msg, char* str1, char* str2) {
+    str call_id;
+    //print_scscf_list(L_DBG);
+    call_id = cscf_get_call_id(msg, 0);
+    LM_DBG("DBG:I_scscf_drop(): <%.*s>\n", call_id.len, call_id.s);
+    if (!call_id.len)
+        return CSCF_RETURN_FALSE;
+
+    del_scscf_list(call_id);
+    return CSCF_RETURN_TRUE;
+}
+
+void del_scscf_list(str call_id) {
+    scscf_list *l = 0;
+    unsigned int hash = get_call_id_hash(call_id, i_hash_size);
+
+    i_lock(hash);
+    l = i_hash_table[hash].head;
+    while (l) {
+        if (l->call_id.len == call_id.len &&
+                strncasecmp(l->call_id.s, call_id.s, call_id.len) == 0) {
+            if (l->prev) l->prev->next = l->next;
+            else i_hash_table[hash].head = l->next;
+            if (l->next) l->next->prev = l->prev;
+            else i_hash_table[hash].tail = l->prev;
+            i_unlock(hash);
+            free_scscf_list(l);
+            return;
+        }
+        l = l->next;
+    }
+    i_unlock(hash);
+}
+
+void print_scscf_list(int log_level) {
+    scscf_list *l;
+    int i;
+    scscf_entry *sl;
+    LM_DBG("INF:----------  S-CSCF Lists begin --------------\n");
+    for (i = 0; i < i_hash_size; i++) {
+        i_lock(i);
+        l = i_hash_table[i].head;
+        while (l) {
+            LM_DBG("INF:[%4d] Call-ID: <%.*s> \n", i,
+                    l->call_id.len, l->call_id.s);
+            sl = l->list;
+            while (sl) {
+                LM_DBG("INF:         Score:[%4d] S-CSCF: <%.*s> \n",
+                        sl->score,
+                        sl->scscf_name.len, sl->scscf_name.s);
+                sl = sl->next;
+            }
+            l = l->next;
+        }
+        i_unlock(i);
+    }
+    LM_DBG("INF:----------  S-CSCF Lists end   --------------\n");
+
+}
+
+/**
+ * Transactional SIP response - tries to create a transaction if none found.
+ * @param msg - message to reply to
+ * @param code - the Status-code for the response
+ * @param text - the Reason-Phrase for the response
+ * @returns the tmb.t_repy() result
+ */
+int cscf_reply_transactional(struct sip_msg *msg, int code, char *text) {
+    unsigned int hash, label;
+    if (tmb.t_get_trans_ident(msg, &hash, &label) < 0) {
+
+        LM_DBG("INF:cscf_reply_transactional: Failed to get SIP transaction - creating new one\n");
+        if (tmb.t_newtran(msg) < 0)
+            LM_DBG("INF:cscf_reply_transactional: Failed creating SIP transaction\n");
+    }
+    return tmb.t_reply(msg, code, text);
+}
+
+int cscf_reply_transactional_async(struct cell* t, struct sip_msg *msg, int code, char *text) {
+    return tmb.t_reply_trans(t, msg, code, text);
+}
+
+/**
+ * Timeout routine called every x seconds and determines if scscf_list entries should be expired
+ * @param msg - message to reply to
+ * @param code - the Status-code for the response
+ * @param text - the Reason-Phrase for the response
+ * @returns the tmb.t_repy() result
+ */
+
+void icscf_timer_routine() {
+    //run through scscf_list and decide if they should be removed!
+    scscf_list *l, *tmp;
+    int i;
+    scscf_entry *sl;
+
+    int delete_list = -1;
+
+    LM_DBG("INF: ICSCF timer routine");
+    //run through all entries and remove the whole list if one entry has expired
+    for (i = 0; i < i_hash_size; i++) {
+        i_lock(i);
+        l = i_hash_table[i].head;
+        while (l) {
+
+            LM_DBG("INF:[%4d] Call-ID: <%.*s> \n", i,
+                    l->call_id.len, l->call_id.s);
+
+            sl = l->list;
+            while (sl) {
+
+                LM_DBG("INF: Score:[%4d] Start_time [%ld] S-CSCF: <%.*s> \n",
+                        sl->score,
+                        sl->start_time,
+                        sl->scscf_name.len, sl->scscf_name.s);
+                time_t now = time(0);
+                time_t time_elapsed = now - sl->start_time;
+                if (time_elapsed > scscf_entry_expiry) {
+
+                    LM_DBG("Scscf entry expired: Time now %ld Start time %ld - elapsed %ld\n", now, sl->start_time, time_elapsed);
+                    delete_list = 1; //if any of the entries in this list have expired remove the whole list!
+
+                }
+                sl = sl->next;
+            }
+
+            if (delete_list == 1) {
+                //if any of the entries in this list have expired remove the whole list!
+                //remove the list for call_id
+                tmp = l->next;
+                if (l->prev) l->prev->next = l->next;
+                else i_hash_table[i].head = l->next;
+                if (l->next) l->next->prev = l->prev;
+                else i_hash_table[i].tail = l->prev;
+                free_scscf_list(l);
+                l = tmp;
+                delete_list = -1;
+            } else {
+                l = l->next;
+            }
+        }
+        i_unlock(i);
+    }
+}

+ 177 - 0
modules/icscf/scscf_list.h

@@ -0,0 +1,177 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#ifndef I_CSCF_SCSCF_LIST_H
+#define I_CSCF_SCSCF_LIST_H
+
+#include "../../sr_module.h"
+#include "../../modules/tm/tm_load.h"
+#include "mod.h"
+#include <values.h>
+
+#include "../../mem/shm_mem.h"
+
+#include "../../dset.h"
+
+#include "../../timer.h"
+
+
+/** S-CSCF list element */ 
+typedef struct _scscf_entry {
+	str scscf_name;	/**< SIP URI of the S-CSCF */
+	int score;		/**< score of the match */
+	time_t start_time;
+        
+	struct _scscf_entry *next; /**< next S-CSCF in the list */
+} scscf_entry;
+
+/** S-CSCF list */
+typedef struct _scscf_list {
+	str call_id;			/**< Call-Id from the request */
+	scscf_entry *list;		/**< S-CSCF list */
+	
+	struct _scscf_list *next;	/**< Next S-CSCF list in the hash slot */
+	struct _scscf_list *prev;	/**< Previous S-CSCF list in the hash slot */
+} scscf_list;
+
+/** hash slot for S-CSCF lists */
+typedef struct {
+	scscf_list *head;					/**< first S-CSCF list in this slot */
+	scscf_list *tail;					/**< last S-CSCF list in this slot */
+	gen_lock_t *lock;				/**< slot lock 					*/	
+} i_hash_slot;
+
+
+/** S-CSCF with attached capabilities */
+typedef struct _scscf_capabilities {
+	int id_s_cscf;					/**< S-CSCF id in the DB */
+	str scscf_name;					/**< S-CSCF SIP URI */
+	int *capabilities;				/**< S-CSCF array of capabilities*/
+	int cnt;						/**< size of S-CSCF array of capabilities*/
+} scscf_capabilities;
+
+
+extern struct tm_binds tmb;
+
+/**
+ * Initialize the hash with S-CSCF lists
+ */
+int i_hash_table_init(int hash_size);
+
+/**
+ * Frees memory for scscf list
+ */
+void free_scscf_list(scscf_list *sl);
+
+/**
+ * Returns a list of S-CSCFs that we should try on, based on the
+ * capabilities requested
+ * \todo - order the list according to matched optionals -
+ * @param scscf_name - the first S-CSCF if specified
+ * @param m - mandatory capabilities list
+ * @param mcnt - mandatory capabilities list size
+ * @param o - optional capabilities list
+ * @param ocnt - optional capabilities list size
+ * @param orig - indicates originating session case
+ * @returns list of S-CSCFs, terminated with a str={0,0}
+ */
+scscf_entry* I_get_capab_ordered(str scscf_name,int *m,int mcnt,int *o,int ocnt, str *p, int pcnt,int orig);
+
+/**
+ * Creates new scscf entry structure
+ */
+scscf_entry* new_scscf_entry(str name, int score, int orig);
+
+/**
+ * Returns the matching rank of a S-CSCF
+ * \todo - optimize the search as O(n^2) is hardly desireable
+ * @param c - the capabilities of the S-CSCF
+ * @param m - mandatory capabilities list requested
+ * @param mcnt - mandatory capabilities list size
+ * @param o - optional capabilities list
+ * @param ocnt - optional capabilities list sizeint I_get_capab_match(icscf_capabilities *c,int *m,int mcnt,int *o,int ocnt)
+ * @returns - -1 if mandatory not satisfied, else count of matched optional capab
+ */
+int I_get_capabilities();
+int I_get_capab_match(scscf_capabilities *c,int *m,int mcnt,int *o,int ocnt);
+int add_scscf_list(str call_id,scscf_entry *sl);
+scscf_list* new_scscf_list(str call_id,scscf_entry *sl);
+inline unsigned int get_call_id_hash(str callid,int hash_size);
+inline void i_lock(unsigned int hash);
+inline void i_unlock(unsigned int hash);
+int I_scscf_select(struct sip_msg* msg, char* str1, char* str2);
+
+/**
+ * Takes on S-CSCF name for the respective Call-ID from the respective name list.
+ * Don't free the result.s - it is freed later!
+ * @param call_id - the id of the call
+ * @returns the shm_malloced S-CSCF name if found or empty string if list is empty or does not exists 
+ */
+str take_scscf_entry(str call_id);
+int I_scscf_drop(struct sip_msg* msg, char* str1, char* str2);
+void del_scscf_list(str call_id);
+void print_scscf_list(int log_level);
+
+/**
+ * Transactional SIP response - tries to create a transaction if none found.
+ * @param msg - message to reply to
+ * @param code - the Status-code for the response
+ * @param text - the Reason-Phrase for the response
+ * @returns the tmb.t_repy() result
+ */
+int cscf_reply_transactional(struct sip_msg *msg, int code, char *text);
+int cscf_reply_transactional_async(struct cell* t, struct sip_msg *msg, int code, char *text);
+
+/**
+ * Timeout routine called every x seconds and determines if scscf_list entries should be expired
+ * @param msg - message to reply to
+ * @param code - the Status-code for the response
+ * @param text - the Reason-Phrase for the response
+ * @returns the tmb.t_repy() result
+ */
+
+void icscf_timer_routine();
+
+#endif

+ 76 - 0
modules/icscf/sip_messages.h

@@ -0,0 +1,76 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+  
+#ifndef ICSCF_SIP_MESSAGES_H_
+#define ICSCF_SIP_MESSAGES_H_
+
+#define MSG_400_NO_PUBLIC_FROM "Bad Request - Public ID in P-Asserted-Identity or From header missing"
+#define MSG_400_NO_PUBLIC "Bad Request - Public ID in To header or Request-URI missing" 
+#define MSG_400_NO_PRIVATE "Bad Request - Private ID in Authorization / username token missing" 
+#define MSG_400_MALFORMED_CONTACT "Bad Request - Error parsing Contact parameters"
+#define MSG_400_NO_VISITED "Bad Request - P-Visited-Network-ID header missing" 
+
+#define MSG_403_UNKOWN_EXPERIMENTAL_RC "Forbidden - HSS responded with unknown Experimental Result Code"
+#define MSG_403_UNABLE_TO_COMPLY "Forbidden - HSS Unable to comply"
+#define MSG_403_UNKOWN_RC "Forbidden - HSS responded with unknown Result Code"
+#define MSG_403_USER_UNKNOWN "Forbidden - HSS User Unknown"
+#define MSG_403_IDENTITIES_DONT_MATCH "Forbidden - HSS Identities don't match"
+#define MSG_403_ROAMING_NOT_ALLOWED "Forbidden - HSS Roaming not allowed"
+#define MSG_403_IDENTITY_NOT_REGISTERED "Forbidden - HSS Identity not registered"
+#define MSG_403_AUTHORIZATION_REJECTED "Forbidden - HSS Authorization Rejected"
+
+#define MSG_480_DIAMETER_ERROR "Temporarily Unavailable - Diameter Cx interface failed"
+#define MSG_480_DIAMETER_MISSING_AVP "Temporarily unavailable - Missing AVP in UAA from HSS"
+#define MSG_480_NOT_REGISTERED "Temporarily Unavailable - HSS Identity not registered"
+
+#define MSG_500_ERROR_SAVING_LIST "Server Error while saving S-CSCF list on I-CSCF"
+#define MSG_500_SERVER_ERROR_OUT_OF_MEMORY "Server Error - Out of memory" 
+
+#define MSG_600_EMPTY_LIST "Busy everywhere - Empty list of S-CSCFs"
+#define MSG_600_FORWARDING_FAILED "Busy everywhere - Forwarding to S-CSCF failed"
+
+#define MSG_604_USER_UNKNOWN "Does not exist anywhere - HSS User Unknown"
+
+#endif

+ 95 - 0
modules/icscf/stats.c

@@ -0,0 +1,95 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#include "stats.h"
+
+int register_stats() {
+	//UAR
+	if (register_stat(MOD_NAME, "uar_replies_response_time", &uar_replies_response_time,0 )
+			!= 0) {
+		LM_ERR("failed to register stat\n");
+		return -1;
+	}
+	if (register_stat(MOD_NAME, "uar_replies_received", &uar_replies_received, 0) != 0) {
+		LM_ERR("failed to register stat\n");
+		return -1;
+	}
+
+	//LIR
+	if (register_stat(MOD_NAME, "lir_replies_response_time", &lir_replies_response_time,0 )
+			!= 0) {
+		LM_ERR("failed to register stat\n");
+		return -1;
+	}
+	if (register_stat(MOD_NAME, "lir_replies_received", &lir_replies_received, 0)
+			!= 0) {
+		LM_ERR("failed to register stat\n");
+		return -1;
+	}
+
+	return 1;
+}
+
+unsigned long get_avg_uar_response_time() {
+
+	long rpls_received = get_stat_val(uar_replies_received);
+	if (!rpls_received)
+		return 0;
+
+	return get_stat_val(uar_replies_response_time)/rpls_received;
+}
+
+unsigned long get_avg_lir_response_time() {
+
+	long rpls_received = get_stat_val(lir_replies_received);
+	if (!rpls_received)
+		return 0;
+
+	return get_stat_val(lir_replies_response_time)/rpls_received;
+}
+
+
+
+

+ 63 - 0
modules/icscf/stats.h

@@ -0,0 +1,63 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * Copyright (C) 2012 Smile Communications, [email protected]
+ * 
+ * The initial version of this code was written by Dragos Vingarzan
+ * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
+ * Fruanhofer Institute. It was and still is maintained in a separate
+ * branch of the original SER. We are therefore migrating it to
+ * Kamailio/SR and look forward to maintaining it from here on out.
+ * 2011/2012 Smile Communications, Pty. Ltd.
+ * ported/maintained/improved by 
+ * Jason Penton (jason(dot)penton(at)smilecoms.com and
+ * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
+ * effort to add full IMS support to Kamailio/SR using a new and
+ * improved architecture
+ * 
+ * NB: Alot of this code was originally part of OpenIMSCore,
+ * FhG Fokus. 
+ * Copyright (C) 2004-2006 FhG Fokus
+ * Thanks for great work! This is an effort to 
+ * break apart the various CSCF functions into logically separate
+ * components. We hope this will drive wider use. We also feel
+ * that in this way the architecture is more complete and thereby easier
+ * to manage in the Kamailio/SR environment
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ */
+
+#ifndef STATISTICS_H_
+#define STATISTICS_H_
+
+#include "../../lib/kcore/statistics.h"
+
+stat_var* stat_uar_timeouts;
+stat_var* stat_lir_timeouts;
+stat_var* uar_replies_received;
+stat_var* lir_replies_received;
+stat_var* uar_replies_response_time;
+stat_var* lir_replies_response_time;
+
+int register_stats();
+unsigned long get_avg_uar_response_time();
+unsigned long get_avg_lir_response_time();
+
+
+#endif /* STATISTICS_H_ */