Browse Source

modules/ims_qos: store AAR flow descriptions in CDP session
When flow_descriptions are installed save the active and new
This allows Rx to fallback to previous flow descriptions if there is an upstream failure

Richard Good 11 years ago
parent
commit
e5c9f00606

+ 1 - 2
modules/ims_qos/cdpeventprocessor.c

@@ -265,8 +265,7 @@ void cdp_cb_event_process() {
 
 
                 //free callback data
                 //free callback data
                 if (p_session_data) {
                 if (p_session_data) {
-                    shm_free(p_session_data);
-                    p_session_data = 0;
+		    free_callsessiondata(p_session_data);
                 }
                 }
                 break;
                 break;
             default:
             default:

+ 175 - 17
modules/ims_qos/mod.c

@@ -332,25 +332,169 @@ AAAMessage* callback_cdp_request(AAAMessage *request, void *param) {
     return 0;
     return 0;
 }
 }
 
 
-void callback_dialog_terminated(struct dlg_cell* dlg, int type, struct dlg_cb_params * params) {
-    LM_DBG("Dialog has ended - we need to terminate Rx bearer session\n");
+const str match_cseq_method = {"INVITE", 6};
 
 
+void callback_dialog(struct dlg_cell* dlg, int type, struct dlg_cb_params * params) {
+    
+    struct sip_msg* msg = params->rpl;
+    struct cseq_body *parsed_cseq;
     str *rx_session_id;
     str *rx_session_id;
     rx_session_id = (str*) * params->param;
     rx_session_id = (str*) * params->param;
+    AAASession *auth = 0;
+    rx_authsessiondata_t* p_session_data = 0;
+    flow_description_t *current_fd = 0;
+    flow_description_t *new_fd = 0;
+    int current_has_video = 0;
+    int new_has_video = 0;
+    int must_unlock_aaa = 1;
+    
+    //getting session data
+    
+    LM_DBG("Dialog callback of type %d received\n", type);
+    
+    if(type == DLGCB_TERMINATED || type == DLGCB_DESTROY || type == DLGCB_EXPIRED){
+	   LM_DBG("Dialog has ended - we need to terminate Rx bearer session\n");
 
 
-    if (!rx_session_id) {
-        LM_ERR("Invalid Rx session id");
-        return;
-    }
+	LM_DBG("Received notification of termination of dialog with Rx session ID: [%.*s]\n",
+		rx_session_id->len, rx_session_id->s);
 
 
-    LM_DBG("Received notification of termination of dialog with Rx session ID: [%.*s]\n",
-            rx_session_id->len, rx_session_id->s);
+	LM_DBG("Sending STR\n");
+	rx_send_str(rx_session_id);
+    } else if (type == DLGCB_CONFIRMED){
+	
+	LM_DBG("Callback for confirmed dialog - copy new flow description into current flow description\n");
+	if (!rx_session_id || !rx_session_id->s || !rx_session_id->len) {
+	    LM_ERR("Dialog has no Rx session associated\n");
+	    goto error;
+	}
 
 
-    LM_DBG("Retrieving Rx auth data for this session id");
+	//getting auth session
+	auth = cdpb.AAAGetAuthSession(*rx_session_id);
+	if (!auth) {
+	    LM_DBG("Could not get Auth Session for session id: [%.*s] - this is fine as this might have been started by already sending an STR\n", rx_session_id->len, rx_session_id->s);
+	    goto error;
+	}
 
 
-    LM_DBG("Sending STR\n");
-    rx_send_str(rx_session_id);
+	//getting session data
+	p_session_data = (rx_authsessiondata_t*) auth->u.auth.generic_data;
+	if (!p_session_data) {
+	    LM_DBG("Could not get session data on Auth Session for session id: [%.*s]\n", rx_session_id->len, rx_session_id->s);
+	    goto error;
+	}
+
+	//check if there is a new flow description - if there is then free the current flow description and replace it with the new flow description
+	if(p_session_data->first_new_flow_description) {
+	    //free the current
+	    LM_DBG("Free-ing the current fd\n");
+	    free_flow_description(p_session_data, 1);
+	    //point the current to the new
+	    LM_DBG("Point the first current fd to the first new fd\n");
+	    p_session_data->first_current_flow_description = p_session_data->first_new_flow_description;
+	    //point the new to 0
+	    LM_DBG("Point the first new fd to 0\n");
+	    p_session_data->first_new_flow_description = 0;
+	} else {
+	    LM_ERR("There is no new flow description - this shouldn't happen\n");
+	}
+	
+	show_callsessiondata(p_session_data);
+	if (auth) cdpb.AAASessionsUnlock(auth->hash);
+    
+    } else if (type == DLGCB_RESPONSE_WITHIN){
+	
+	LM_DBG("Dialog has received a response to a request within dialog\n");
+	if (!rx_session_id || !rx_session_id->s || !rx_session_id->len) {
+	    LM_ERR("Dialog has no Rx session associated\n");
+	    goto error;
+	}
 
 
+	//getting auth session
+	auth = cdpb.AAAGetAuthSession(*rx_session_id);
+	if (!auth) {
+	    LM_DBG("Could not get Auth Session for session id: [%.*s] - this is fine as this might have been started by already sending an STR\n", rx_session_id->len, rx_session_id->s);
+	    goto error;
+	}
+
+	//getting session data
+	p_session_data = (rx_authsessiondata_t*) auth->u.auth.generic_data;
+
+	if (!p_session_data) {
+	    LM_DBG("Could not get session data on Auth Session for session id: [%.*s]\n", rx_session_id->len, rx_session_id->s);
+	    goto error;
+	}
+	
+	show_callsessiondata(p_session_data);
+
+	if (msg->first_line.type == SIP_REPLY) {
+	    LM_DBG("This is a SIP REPLY\n");
+	    if (msg->cseq && (parsed_cseq = get_cseq(msg)) && memcmp(parsed_cseq->method.s, match_cseq_method.s, match_cseq_method.len)==0) {
+		LM_DBG("This response has a cseq method [%.*s]\n", match_cseq_method.len, match_cseq_method.s);
+		
+		if (msg->first_line.u.reply.statuscode == 200) {
+		    LM_DBG("Response is 200 - this is success\n");
+		    //check if there is a new flow description - if there is then free the current flow description and replace it with the new flow description
+		    if(p_session_data->first_new_flow_description) {
+			//free the current
+			free_flow_description(p_session_data, 1);
+			//point the current to the new
+			p_session_data->first_current_flow_description = p_session_data->first_new_flow_description;
+			//point the new to 0
+			p_session_data->first_new_flow_description = 0;
+		    } else {
+			LM_DBG("There is no new flow description - duplicate dialog callback - we ignore.\n");
+		    }
+		} else if (msg->first_line.u.reply.statuscode > 299) {
+		    LM_DBG("Response is more than 299 so this is an error code\n");
+		    
+		    new_fd = p_session_data->first_new_flow_description;
+		    //check if there is video in the new flow description
+		    while(new_fd) {
+			if (strncmp(new_fd->media.s, "video", 5) == 0) {
+			    LM_DBG("The new flow has a video fd in it\n");
+			    new_has_video = 1;
+			    
+			}
+			new_fd = new_fd->next;
+		    }
+		    //check if there is video in the current flow description
+		    current_fd = p_session_data->first_current_flow_description;
+		    while(current_fd) {
+			if (strncmp(current_fd->media.s, "video", 5) == 0) {
+			    LM_DBG("The current flow has a video fd in it\n");
+			    current_has_video = 1;
+			    
+			}
+			current_fd = current_fd->next;
+		    }
+		    if(new_has_video && !current_has_video) {
+			LM_DBG("New flow description has video in it, and current does not - this means we added video and it failed further upstream - "
+				"so we must remove the video\n");
+			//We need to send AAR asynchronously with current fd
+			rx_send_aar_update_no_video(auth);
+			must_unlock_aaa = 0;
+			
+		    } 
+		    //free the new flow description
+		    free_flow_description(p_session_data, 0);
+		}
+	    }
+	}
+	
+	show_callsessiondata(p_session_data);
+		
+	if(must_unlock_aaa)
+	{
+	    LM_DBG("Unlocking AAA session");
+	    cdpb.AAASessionsUnlock(auth->hash);
+	}
+    } else {
+	LM_DBG("Callback type not supported - just returning");
+    }
+    
+    return;
+    
+    error:
+	if (auth) cdpb.AAASessionsUnlock(auth->hash);
     return;
     return;
 }
 }
 
 
@@ -390,6 +534,7 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) {
     
     
     str route_name;
     str route_name;
     str identifier, ip;
     str identifier, ip;
+    int ip_version = 0;
     int must_free_asserted_identity = 0;
     int must_free_asserted_identity = 0;
     sdp_session_cell_t* sdp_session;
     sdp_session_cell_t* sdp_session;
 
 
@@ -508,6 +653,8 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) {
     memset(saved_t_data->ftag.s, 0, ftag.len + 1);
     memset(saved_t_data->ftag.s, 0, ftag.len + 1);
     memcpy(saved_t_data->ftag.s, ftag.s, ftag.len);
     memcpy(saved_t_data->ftag.s, ftag.s, ftag.len);
     saved_t_data->ftag.len = ftag.len;
     saved_t_data->ftag.len = ftag.len;
+    
+    saved_t_data->aar_update = 0;//by default we say this is not an aar update - if it is we set it below
 
 
     //store branch
     //store branch
     int branch;
     int branch;
@@ -564,6 +711,7 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) {
 		    goto error;
 		    goto error;
 	    }
 	    }
 	    ip = sdp_session->ip_addr;
 	    ip = sdp_session->ip_addr;
+	    ip_version = sdp_session->pf;
 	    free_sdp((sdp_info_t**) (void*) &t->uas.request->body);
 	    free_sdp((sdp_info_t**) (void*) &t->uas.request->body);
 	    
 	    
 	} else {
 	} else {
@@ -585,11 +733,12 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) {
 		    goto error;
 		    goto error;
 	    }
 	    }
 	    ip = sdp_session->ip_addr;
 	    ip = sdp_session->ip_addr;
+	    ip_version = sdp_session->pf;
 	    free_sdp((sdp_info_t**) (void*) &msg->body);
 	    free_sdp((sdp_info_t**) (void*) &msg->body);
 	    
 	    
 	}
 	}
 
 
-        int ret = create_new_callsessiondata(&callid, &ftag, &ttag, &identifier, &ip, &rx_authdata_p);
+        int ret = create_new_callsessiondata(&callid, &ftag, &ttag, &identifier, &ip, ip_version, &rx_authdata_p);
         if (!ret) {
         if (!ret) {
             LM_DBG("Unable to create new media session data parcel\n");
             LM_DBG("Unable to create new media session data parcel\n");
             goto error;
             goto error;
@@ -607,8 +756,7 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) {
             LM_ERR("Rx: unable to create new Rx Media Session\n");
             LM_ERR("Rx: unable to create new Rx Media Session\n");
             if (auth_session) cdpb.AAASessionsUnlock(auth_session->hash);
             if (auth_session) cdpb.AAASessionsUnlock(auth_session->hash);
             if (rx_authdata_p) {
             if (rx_authdata_p) {
-                shm_free(rx_authdata_p);
-                rx_authdata_p = 0;
+		free_callsessiondata(rx_authdata_p);
             }
             }
             goto error;
             goto error;
         }
         }
@@ -625,18 +773,28 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) {
     } else {
     } else {
         LM_DBG("Update AAR session for this dialog in mode %s\n", direction);
         LM_DBG("Update AAR session for this dialog in mode %s\n", direction);
 	auth_session = cdpb.AAAGetAuthSession(*rx_session_id);
 	auth_session = cdpb.AAAGetAuthSession(*rx_session_id);
+	
+	    if (!auth_session) {
+	    LM_ERR("Could not get Auth Session for session id: [%.*s] on AAR update\n", rx_session_id->len, rx_session_id->s);
+	    result = CSCF_RETURN_FALSE; //here we return FALSE this just drops the message in the config file
+	    goto error;
+	}
+	
 	if(auth_session->u.auth.state != AUTH_ST_OPEN)
 	if(auth_session->u.auth.state != AUTH_ST_OPEN)
 	{
 	{
 	    LM_DBG("This session is not state open, packet will be dropped");
 	    LM_DBG("This session is not state open, packet will be dropped");
+	    if (auth_session) cdpb.AAASessionsUnlock(auth_session->hash);
 	    result = CSCF_RETURN_FALSE; //here we return FALSE this just drops the message in the config file
 	    result = CSCF_RETURN_FALSE; //here we return FALSE this just drops the message in the config file
 	    goto error;
 	    goto error;
 	}
 	}
+	saved_t_data->aar_update = 1;//this is an update aar - we set this so on async_aar we know this is an update and act accordingly
     }
     }
 
 
     LM_DBG("Suspending SIP TM transaction\n");
     LM_DBG("Suspending SIP TM transaction\n");
     if (tmb.t_suspend(msg, &saved_t_data->tindex, &saved_t_data->tlabel) < 0) {
     if (tmb.t_suspend(msg, &saved_t_data->tindex, &saved_t_data->tlabel) < 0) {
         LM_ERR("failed to suspend the TM processing\n");
         LM_ERR("failed to suspend the TM processing\n");
-        goto error;
+	if (auth_session) cdpb.AAASessionsUnlock(auth_session->hash);
+	goto error;
     }
     }
 
 
     LM_DBG("Sending Rx AAR");
     LM_DBG("Sending Rx AAR");
@@ -645,7 +803,7 @@ static int w_rx_aar(struct sip_msg *msg, char *route, char* str1, char* bar) {
     if (!ret) {
     if (!ret) {
         LM_ERR("Failed to send AAR\n");
         LM_ERR("Failed to send AAR\n");
         tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel);
         tmb.t_cancel_suspend(saved_t_data->tindex, saved_t_data->tlabel);
-        goto error;
+	goto error;
 
 
 
 
     } else {
     } else {
@@ -666,7 +824,7 @@ error:
 	    must_free_asserted_identity = 1;
 	    must_free_asserted_identity = 1;
     }
     }
 
 
-     return result;
+    return result;
 }
 }
 
 
 /* Wrapper to send AAR from config file - only used for registration */
 /* Wrapper to send AAR from config file - only used for registration */

+ 1 - 1
modules/ims_qos/mod.h

@@ -57,7 +57,7 @@ struct pcontact;
 AAAMessage* callback_cdp_request(AAAMessage *request, void *param);
 AAAMessage* callback_cdp_request(AAAMessage *request, void *param);
 void callback_for_cdp_session(int event,void *session);
 void callback_for_cdp_session(int event,void *session);
 
 
-void callback_dialog_terminated(struct dlg_cell* dlg, int type, struct dlg_cb_params * params);
+void callback_dialog(struct dlg_cell* dlg, int type, struct dlg_cb_params * params);
 
 
 void callback_pcscf_contact_cb(struct pcontact *c, int type, void *param);
 void callback_pcscf_contact_cb(struct pcontact *c, int type, void *param);
 
 

+ 217 - 19
modules/ims_qos/rx_aar.c

@@ -135,14 +135,17 @@ void async_aar_callback(int is_timeout, void *param, AAAMessage *aaa, long elaps
         LM_DBG("Success, received code: [%i] from PCRF for AAR request\n", cdp_result);
         LM_DBG("Success, received code: [%i] from PCRF for AAR request\n", cdp_result);
 
 
         LM_DBG("Auth session ID [%.*s]", aaa->sessionId->data.len, aaa->sessionId->data.s);
         LM_DBG("Auth session ID [%.*s]", aaa->sessionId->data.len, aaa->sessionId->data.s);
-
-        str * passed_rx_session_id = shm_malloc(sizeof (struct _str));
-        passed_rx_session_id->s = 0;
-        passed_rx_session_id->len = 0;
-        STR_SHM_DUP(*passed_rx_session_id, aaa->sessionId->data, "cb_passed_rx_session_id");
-        LM_DBG("passed rx session id [%.*s]", passed_rx_session_id->len, passed_rx_session_id->s);
-
-        dlgb.register_dlgcb_nodlg(&data->callid, &data->ftag, &data->ttag, DLGCB_TERMINATED | DLGCB_DESTROY | DLGCB_EXPIRED, callback_dialog_terminated, (void*) (passed_rx_session_id), free_dialog_data);
+	
+	if(!data->aar_update) {
+	    LM_DBG("This is an AAA response to an initial AAR");
+	    str * passed_rx_session_id = shm_malloc(sizeof (struct _str));
+	    passed_rx_session_id->s = 0;
+	    passed_rx_session_id->len = 0;
+	    STR_SHM_DUP(*passed_rx_session_id, aaa->sessionId->data, "cb_passed_rx_session_id");
+	    LM_DBG("passed rx session id [%.*s]", passed_rx_session_id->len, passed_rx_session_id->s);
+
+	    dlgb.register_dlgcb_nodlg(&data->callid, &data->ftag, &data->ttag, DLGCB_TERMINATED | DLGCB_DESTROY | DLGCB_EXPIRED | DLGCB_RESPONSE_WITHIN | DLGCB_CONFIRMED, callback_dialog, (void*) (passed_rx_session_id), free_dialog_data);
+	} 
         result = CSCF_RETURN_TRUE;
         result = CSCF_RETURN_TRUE;
     } else {
     } else {
         LM_DBG("Received negative reply from PCRF for AAR Request\n");
         LM_DBG("Received negative reply from PCRF for AAR Request\n");
@@ -316,10 +319,33 @@ int rx_process_aaa(AAAMessage *aaa, unsigned int * rc) {
     return ret;
     return ret;
 }
 }
 
 
+/** Helper function for adding media component AVPs - uses previously stored flow descriptions not SDP from messages*/
+int add_media_components_using_current_flow_description(AAAMessage* aar, rx_authsessiondata_t *p_session_data) {
+    
+    flow_description_t *flow_description;
+    
+    flow_description = p_session_data->first_current_flow_description;
+    if(!flow_description) {
+	return -1;
+    }
+    while (flow_description) {
+        rx_add_media_component_description_avp(aar, flow_description->stream_num,
+	    &flow_description->media, &flow_description->req_sdp_ip_addr,
+	    &flow_description->req_sdp_port, &flow_description->rpl_sdp_ip_addr,
+	    &flow_description->rpl_sdp_port, &flow_description->rpl_sdp_transport,
+	    &flow_description->req_sdp_raw_stream,
+	    &flow_description->rpl_sdp_raw_stream, flow_description->direction);
+	
+	flow_description = flow_description->next;
+    }
+    return 0;
+}
+
+
+
 /** Helper function for adding media component AVPs for each SDP stream*/
 /** Helper function for adding media component AVPs for each SDP stream*/
 int add_media_components(AAAMessage* aar, struct sip_msg *req,
 int add_media_components(AAAMessage* aar, struct sip_msg *req,
-        struct sip_msg *rpl, enum dialog_direction direction,
-        uint16_t *ip_version) {
+        struct sip_msg *rpl, enum dialog_direction direction, AAASession* auth) {
     int sdp_session_num;
     int sdp_session_num;
     int sdp_stream_num;
     int sdp_stream_num;
     sdp_session_cell_t* req_sdp_session, *rpl_sdp_session;
     sdp_session_cell_t* req_sdp_session, *rpl_sdp_session;
@@ -359,13 +385,6 @@ int add_media_components(AAAMessage* aar, struct sip_msg *req,
             break;
             break;
         }
         }
 
 
-	//we only populate ip if its not already populated
-        if (direction == DLG_MOBILE_ORIGINATING) {
-            *ip_version = req_sdp_session->pf;
-        } else if (direction == DLG_MOBILE_TERMINATING) {
-            *ip_version = rpl_sdp_session->pf;
-        }
-
         sdp_stream_num = 0;
         sdp_stream_num = 0;
         for (;;) {
         for (;;) {
             req_sdp_stream = get_sdp_stream(req, sdp_session_num,
             req_sdp_stream = get_sdp_stream(req, sdp_session_num,
@@ -383,7 +402,17 @@ int add_media_components(AAAMessage* aar, struct sip_msg *req,
 		int intportA = atoi(req_sdp_stream->port.s);
 		int intportA = atoi(req_sdp_stream->port.s);
 		int intportB = atoi(rpl_sdp_stream->port.s);
 		int intportB = atoi(rpl_sdp_stream->port.s);
 		if(intportA != 0 && intportB != 0){
 		if(intportA != 0 && intportB != 0){
-                	rx_add_media_component_description_avp(aar, sdp_stream_num + 1,
+		    
+			//add this to auth session data
+			
+			add_flow_description((rx_authsessiondata_t*) auth->u.auth.generic_data, sdp_stream_num + 1,
+                        	&req_sdp_stream->media, &req_sdp_session->ip_addr,
+	                        &req_sdp_stream->port, &rpl_sdp_session->ip_addr,
+        	                &rpl_sdp_stream->port, &rpl_sdp_stream->transport,
+                	        &req_sdp_stream->raw_stream,
+                        	&rpl_sdp_stream->raw_stream, direction, 0 /*This is a new mcd, we are not setting it as active*/);
+		    
+			rx_add_media_component_description_avp(aar, sdp_stream_num + 1,
                         	&req_sdp_stream->media, &req_sdp_session->ip_addr,
                         	&req_sdp_stream->media, &req_sdp_session->ip_addr,
 	                        &req_sdp_stream->port, &rpl_sdp_session->ip_addr,
 	                        &req_sdp_stream->port, &rpl_sdp_session->ip_addr,
         	                &rpl_sdp_stream->port, &rpl_sdp_stream->transport,
         	                &rpl_sdp_stream->port, &rpl_sdp_stream->transport,
@@ -402,6 +431,171 @@ int add_media_components(AAAMessage* aar, struct sip_msg *req,
     return 0;
     return 0;
 }
 }
 
 
+/**
+ * Sends the Authorization Authentication Request - specifically this is an asynchronous AAR sent if another update adding video has failed so we need to remove video
+ */
+
+int rx_send_aar_update_no_video(AAASession* auth) {
+
+    AAAMessage* aar = 0;
+    int must_free_asserted_identity = 0;
+    
+    str identifier;
+    int identifier_type;
+
+
+    AAA_AVP* avp = 0;
+    char x[4];
+    int ret = 0;
+
+    str ip;
+    uint16_t ip_version;
+
+    //we get ip and identifier for the auth session data 
+    rx_authsessiondata_t* p_session_data = 0;
+    p_session_data = (rx_authsessiondata_t*) auth->u.auth.generic_data;
+    identifier = p_session_data->identifier;
+    ip = p_session_data->ip;
+    ip_version = p_session_data->ip_version;
+    
+    aar = cdpb.AAACreateRequest(IMS_Rx, IMS_AAR, Flag_Proxyable, auth);
+
+    LM_DBG("Sending AAR update to remove a video bearer\n");
+    show_callsessiondata(p_session_data);
+
+    if (!aar)
+        goto error;
+
+    /*Adding AVPs*/
+
+    LM_DBG("Adding auth app id AVP...\n");
+    /* Add Auth-Application-Id AVP */
+    if (!rx_add_auth_application_id_avp(aar, IMS_Rx))
+        goto error;
+    if (!rx_add_vendor_specific_application_id_group(aar, IMS_vendor_id_3GPP,
+            IMS_Rx))
+        goto error;
+
+    LM_DBG("Adding dest realm if not there already...\n");
+    /* Add Destination-Realm AVP, if not already there */
+    avp = cdpb.AAAFindMatchingAVP(aar, aar->avpList.head, AVP_Destination_Realm,
+            0, AAA_FORWARD_SEARCH);
+    if (!avp) {
+        str realm = rx_dest_realm;
+        if (realm.len && !rx_add_destination_realm_avp(aar, realm))
+            goto error;
+    }
+
+    LM_DBG("Adding AF App identifier...\n");
+    /* Add AF-Application-Identifier AVP */
+    str af_id = {0, 0};
+    af_id = IMS_Serv_AVP_val;
+    if (!rx_add_avp(aar, af_id.s, af_id.len, AVP_IMS_AF_Application_Identifier,
+            AAA_AVP_FLAG_MANDATORY, IMS_vendor_id_3GPP, AVP_DUPLICATE_DATA,
+            __FUNCTION__))
+        goto error;
+
+    LM_DBG("Adding service info status...\n");
+    /* Add Service-Info-Status AVP, if prelimiary
+     * by default(when absent): final status is considered*/
+    
+    set_4bytes(x,
+	    AVP_EPC_Service_Info_Status_Preliminary_Service_Information);
+    if (!rx_add_avp(aar, x, 4, AVP_IMS_Service_Info_Status,
+	    AAA_AVP_FLAG_MANDATORY, IMS_vendor_id_3GPP, AVP_DUPLICATE_DATA,
+	    __FUNCTION__))
+	goto error;
+
+    /* Add Auth lifetime AVP */LM_DBG("auth_lifetime %u\n", rx_auth_expiry); //TODO check why this is 0 all the time
+    if (rx_auth_expiry) {
+        set_4bytes(x, rx_auth_expiry);
+        if (!rx_add_avp(aar, x, 4, AVP_Authorization_Lifetime,
+                AAA_AVP_FLAG_MANDATORY, 0, AVP_DUPLICATE_DATA, __FUNCTION__))
+            goto error;
+    }
+
+    LM_DBG("Adding subscription id...\n");
+
+    if (strncasecmp(identifier.s,"tel:",4)==0) {
+	identifier_type = AVP_Subscription_Id_Type_E164; //
+    }else{
+	identifier_type = AVP_Subscription_Id_Type_SIP_URI; //default is END_USER_SIP_URI
+    }
+    
+    
+    rx_add_subscription_id_avp(aar, identifier, identifier_type);
+    if (must_free_asserted_identity) {
+            pkg_free(identifier.s);
+    }
+
+
+    LM_DBG("Adding reservation priority...\n");
+    /* Add Reservation Priority AVP*/
+    set_4bytes(x, 0);
+    if (!rx_add_avp(aar, x, 4, AVP_ETSI_Reservation_Priority,
+            AAA_AVP_FLAG_VENDOR_SPECIFIC, IMS_vendor_id_ETSI,
+            AVP_DUPLICATE_DATA, __FUNCTION__))
+        goto error;
+
+    LM_DBG("Adding media component...\n");
+    //Note we add this AVP first as it gets the IP address which we need to create the auth session
+    //Could and maybe should have a separate method that retrieves the IP from SDP - TODO
+
+    /*---------- 2. Create and add Media-Component-Description AVP ----------*/
+
+    /*
+     *  See 3GPP TS29214
+     *
+     *  <Media-Component-Description> = {Media-Component-Number}
+     * 								 	[Media-Sub-Component]
+     * 								 	[AF-Application-Identifier]
+     * 								 	[Media-Type]
+     * 								 	[Max-Requested-Bandwidth-UL]
+     * 									[Max-Requested-Bandwidth-DL]
+     * 									[Flow-Status]
+     * 									[Reservation-Priority] (Not used yet)
+     * 								 	[RS-Bandwidth]
+     * 									[RR-Bandwidth]
+     * 									*[Codec-Data]
+     */
+
+    add_media_components_using_current_flow_description(aar, p_session_data);
+
+    LM_DBG("Adding framed ip address [%.*s]\n", ip.len, ip.s);
+    /* Add Framed IP address AVP*/
+    if (!rx_add_framed_ip_avp(&aar->avpList, ip, ip_version)) {
+        LM_ERR("Unable to add framed IP AVP\n");
+        goto error;
+    }
+    LM_DBG("Unlocking AAA session...\n");
+
+    if (auth)
+        cdpb.AAASessionsUnlock(auth->hash);
+
+    LM_DBG("sending AAR to PCRF\n");
+    if (rx_forced_peer.len)
+        ret = cdpb.AAASendMessageToPeer(aar, &rx_forced_peer,
+            NULL, NULL);
+    else
+        ret = cdpb.AAASendMessage(aar, NULL,
+            NULL);
+
+    return ret;
+
+error:
+    LM_ERR("unexpected error\n");
+    if (aar)
+        cdpb.AAAFreeMessage(&aar);
+    if (auth) {
+        cdpb.AAASessionsUnlock(auth->hash);
+        cdpb.AAADropAuthSession(auth);
+        auth = 0;
+    }
+    return ret;
+}
+
+
+
 /**
 /**
  * Sends the Authorization Authentication Request.
  * Sends the Authorization Authentication Request.
  * @param req - SIP request
  * @param req - SIP request
@@ -433,6 +627,7 @@ int rx_send_aar(struct sip_msg *req, struct sip_msg *res,
     p_session_data = (rx_authsessiondata_t*) auth->u.auth.generic_data;
     p_session_data = (rx_authsessiondata_t*) auth->u.auth.generic_data;
     identifier = p_session_data->identifier;
     identifier = p_session_data->identifier;
     ip = p_session_data->ip;
     ip = p_session_data->ip;
+    ip_version = p_session_data->ip_version;
     
     
     /* find direction for AAR (orig/term) */
     /* find direction for AAR (orig/term) */
     //need this to add the media component details
     //need this to add the media component details
@@ -543,7 +738,7 @@ int rx_send_aar(struct sip_msg *req, struct sip_msg *res,
      * 									*[Codec-Data]
      * 									*[Codec-Data]
      */
      */
 
 
-    add_media_components(aar, req, res, dlg_direction, &ip_version);
+    add_media_components(aar, req, res, dlg_direction, auth);
 
 
     LM_DBG("Adding framed ip address [%.*s]\n", ip.len, ip.s);
     LM_DBG("Adding framed ip address [%.*s]\n", ip.len, ip.s);
     /* Add Framed IP address AVP*/
     /* Add Framed IP address AVP*/
@@ -551,6 +746,9 @@ int rx_send_aar(struct sip_msg *req, struct sip_msg *res,
         LM_ERR("Unable to add framed IP AVP\n");
         LM_ERR("Unable to add framed IP AVP\n");
         goto error;
         goto error;
     }
     }
+    
+    show_callsessiondata(p_session_data);
+    
     LM_DBG("Unlocking AAA session...\n");
     LM_DBG("Unlocking AAA session...\n");
 
 
     if (auth)
     if (auth)

+ 5 - 0
modules/ims_qos/rx_aar.h

@@ -71,6 +71,7 @@ typedef struct saved_transaction {
         str callid;
         str callid;
         str ftag;
         str ftag;
         str ttag;
         str ttag;
+	unsigned int aar_update;
 } saved_transaction_t;
 } saved_transaction_t;
 
 
 typedef struct saved_transaction_local {
 typedef struct saved_transaction_local {
@@ -97,6 +98,10 @@ void free_saved_transaction_global_data(saved_transaction_t* data);
 //AAAMessage *rx_send_aar(struct sip_msg *req, struct sip_msg *res, AAASession* auth, str *callid, str *ftag, str *ttag, char *direction, rx_authsessiondata_t **rx_authdata);
 //AAAMessage *rx_send_aar(struct sip_msg *req, struct sip_msg *res, AAASession* auth, str *callid, str *ftag, str *ttag, char *direction, rx_authsessiondata_t **rx_authdata);
 int rx_send_aar(struct sip_msg *req, struct sip_msg *res, AAASession* auth, char *direction, saved_transaction_t* saved_t_data);
 int rx_send_aar(struct sip_msg *req, struct sip_msg *res, AAASession* auth, char *direction, saved_transaction_t* saved_t_data);
 
 
+//send AAR to remove video after failed AAR update that added video
+int rx_send_aar_update_no_video(AAASession* auth);
+
+
 //TODOD remove - no longer user AOR parm
 //TODOD remove - no longer user AOR parm
 //int rx_send_aar_register(struct sip_msg *msg, AAASession* auth, str *ip_address, uint16_t *ip_version, str *aor, saved_transaction_local_t* saved_t_data);
 //int rx_send_aar_register(struct sip_msg *msg, AAASession* auth, str *ip_address, uint16_t *ip_version, str *aor, saved_transaction_local_t* saved_t_data);
 int rx_send_aar_register(struct sip_msg *msg, AAASession* auth, str *ip_address, uint16_t *ip_version, saved_transaction_local_t* saved_t_data);
 int rx_send_aar_register(struct sip_msg *msg, AAASession* auth, str *ip_address, uint16_t *ip_version, saved_transaction_local_t* saved_t_data);

+ 228 - 2
modules/ims_qos/rx_authdata.c

@@ -103,7 +103,7 @@ int create_new_regsessiondata(str* domain, str* aor, rx_authsessiondata_t** sess
 	return 1;
 	return 1;
 }
 }
 
 
-int create_new_callsessiondata(str* callid, str* ftag, str* ttag, str* identifier, str* ip, rx_authsessiondata_t** session_data) {
+int create_new_callsessiondata(str* callid, str* ftag, str* ttag, str* identifier, str* ip, int ip_version, rx_authsessiondata_t** session_data) {
 
 
 	int len = callid->len + ftag->len + ttag->len + identifier->len + ip->len + sizeof(rx_authsessiondata_t);
 	int len = callid->len + ftag->len + ttag->len + identifier->len + ip->len + sizeof(rx_authsessiondata_t);
 	rx_authsessiondata_t* call_session_data = shm_malloc(len);
 	rx_authsessiondata_t* call_session_data = shm_malloc(len);
@@ -114,7 +114,11 @@ int create_new_callsessiondata(str* callid, str* ftag, str* ttag, str* identifie
 	memset(call_session_data, 0, len);
 	memset(call_session_data, 0, len);
 	call_session_data->subscribed_to_signaling_path_status = 0; //this is for a media session not regitration
 	call_session_data->subscribed_to_signaling_path_status = 0; //this is for a media session not regitration
         call_session_data->must_terminate_dialog = 0; //this is used to determine if the dialog must be torn down when the CDP session terminates
         call_session_data->must_terminate_dialog = 0; //this is used to determine if the dialog must be torn down when the CDP session terminates
-
+	
+	call_session_data->first_current_flow_description=0;
+	call_session_data->first_new_flow_description=0;
+	call_session_data->ip_version = ip_version;
+	
 	char *p = (char*)(call_session_data + 1);
 	char *p = (char*)(call_session_data + 1);
 
 
 	if (callid && callid->len>0 && callid->s) {
 	if (callid && callid->len>0 && callid->s) {
@@ -162,7 +166,229 @@ int create_new_callsessiondata(str* callid, str* ftag, str* ttag, str* identifie
 	return 1;
 	return 1;
 }
 }
 
 
+/* Param current tells us if this a current fd or a new fd to add*/
+int add_flow_description(rx_authsessiondata_t* session_data, int stream_num, str *media, str *req_sdp_ip_addr, str *req_sdp_port,
+			str *rpl_sdp_ip_addr, str *rpl_sdp_port, str *rpl_sdp_transport, str *req_sdp_raw_stream, str *rpl_sdp_raw_stream, int direction, int current) {
+    
+    flow_description_t *fd = 0;
+    flow_description_t *tmp, *tmp1 = 0;
+    
+    int len = media->len + req_sdp_ip_addr->len + req_sdp_port->len + rpl_sdp_ip_addr->len + rpl_sdp_port->len + rpl_sdp_transport->len + req_sdp_raw_stream->len + rpl_sdp_raw_stream->len + sizeof(flow_description_t);
+    fd = shm_malloc(len);
+    if (!fd){
+	    LM_ERR("no more shm mem trying to create new flow description of size %d\n", len);
+	    return -1;
+    }
+    memset(fd, 0, len);
+    
+    fd->direction = direction;
+    fd->stream_num = stream_num;
+    
+    char *p = (char*)(fd + 1);
 
 
+    if (media && media->len>0 && media->s) {
+	    LM_DBG("Copying media [%.*s] into flow description\n", media->len, media->s);
+	    fd->media.s = p;
+	    memcpy(fd->media.s, media->s, media->len);
+	    fd->media.len = media->len;
+	    p+=media->len;
+    }
+    if (req_sdp_ip_addr && req_sdp_ip_addr->len>0 && req_sdp_ip_addr->s) {
+	    LM_DBG("Copying req_sdp_ip_addr [%.*s] into flow description\n", req_sdp_ip_addr->len, req_sdp_ip_addr->s);
+	    fd->req_sdp_ip_addr.s = p;
+	    memcpy(fd->req_sdp_ip_addr.s, req_sdp_ip_addr->s, req_sdp_ip_addr->len);
+	    fd->req_sdp_ip_addr.len = req_sdp_ip_addr->len;
+	    p+=req_sdp_ip_addr->len;
+    }
+    if (req_sdp_port && req_sdp_port->len>0 && req_sdp_port->s) {
+	    LM_DBG("Copying req_sdp_port [%.*s] into flow description\n", req_sdp_port->len, req_sdp_port->s);
+	    fd->req_sdp_port.s = p;
+	    memcpy(fd->req_sdp_port.s, req_sdp_port->s, req_sdp_port->len);
+	    fd->req_sdp_port.len = req_sdp_port->len;
+	    p+=req_sdp_port->len;
+    }
+    if (rpl_sdp_ip_addr && rpl_sdp_ip_addr->len>0 && rpl_sdp_ip_addr->s) {
+	    LM_DBG("Copying rpl_sdp_ip_addr [%.*s] into flow description\n", rpl_sdp_ip_addr->len, rpl_sdp_ip_addr->s);
+	    fd->rpl_sdp_ip_addr.s = p;
+	    memcpy(fd->rpl_sdp_ip_addr.s, rpl_sdp_ip_addr->s, rpl_sdp_ip_addr->len);
+	    fd->rpl_sdp_ip_addr.len = rpl_sdp_ip_addr->len;
+	    p+=rpl_sdp_ip_addr->len;
+    }
+    if (rpl_sdp_port && rpl_sdp_port->len>0 && rpl_sdp_port->s) {
+	    LM_DBG("Copying rpl_sdp_port [%.*s] into flow description\n", rpl_sdp_port->len, rpl_sdp_port->s);
+	    fd->rpl_sdp_port.s = p;
+	    memcpy(fd->rpl_sdp_port.s, rpl_sdp_port->s, rpl_sdp_port->len);
+	    fd->rpl_sdp_port.len = rpl_sdp_port->len;
+	    p+=rpl_sdp_port->len;
+    }
+    if (rpl_sdp_transport && rpl_sdp_transport->len>0 && rpl_sdp_transport->s) {
+	    LM_DBG("Copying rpl_sdp_transport [%.*s] into flow description\n", rpl_sdp_transport->len, rpl_sdp_transport->s);
+	    fd->rpl_sdp_transport.s = p;
+	    memcpy(fd->rpl_sdp_transport.s, rpl_sdp_transport->s, rpl_sdp_transport->len);
+	    fd->rpl_sdp_transport.len = rpl_sdp_transport->len;
+	    p+=rpl_sdp_transport->len;
+    }
+    if (req_sdp_raw_stream && req_sdp_raw_stream->len>0 && req_sdp_raw_stream->s) {
+	    LM_DBG("Copying req_sdp_raw_stream [%.*s] into flow description\n", req_sdp_raw_stream->len, req_sdp_raw_stream->s);
+	    fd->req_sdp_raw_stream.s = p;
+	    memcpy(fd->req_sdp_raw_stream.s, req_sdp_raw_stream->s, req_sdp_raw_stream->len);
+	    fd->req_sdp_raw_stream.len = req_sdp_raw_stream->len;
+	    p+=req_sdp_raw_stream->len;
+    }
+    if (rpl_sdp_raw_stream && rpl_sdp_raw_stream->len>0 && rpl_sdp_raw_stream->s) {
+	    LM_DBG("Copying rpl_sdp_raw_stream [%.*s] into flow description\n", rpl_sdp_raw_stream->len, rpl_sdp_raw_stream->s);
+	    fd->rpl_sdp_raw_stream.s = p;
+	    memcpy(fd->rpl_sdp_raw_stream.s, rpl_sdp_raw_stream->s, rpl_sdp_raw_stream->len);
+	    fd->rpl_sdp_raw_stream.len = rpl_sdp_raw_stream->len;
+	    p+=rpl_sdp_raw_stream->len;
+    }
+	
+    if (p != ((char*)(fd) + len)) {
+	    LM_ERR("buffer under/overflow\n");
+	    shm_free(fd);
+	    return -1;
+    }
 
 
+    fd->next=0;
 
 
+    if(current){
+	LM_DBG("Adding current flow description\n");
+	    if(session_data->first_current_flow_description == 0) {
+		LM_DBG("This is the first\n");
+		session_data->first_current_flow_description = fd;
+	} else{
+	    LM_DBG("This is NOT the first - adding to the list\n");
+	    tmp = session_data->first_current_flow_description;
+	     while (tmp) {
+		tmp1 = tmp->next;
+		if(!tmp1) {
+		    break;
+		}
+		tmp = tmp1;
+	    }
+	    tmp->next = fd;
+	}
+    } else {
+	LM_DBG("Adding new flow description\n");
+	    if(session_data->first_new_flow_description == 0) {
+		LM_DBG("This is the first\n");
+		session_data->first_new_flow_description = fd;
+	} else{
+	    LM_DBG("This is NOT the first - adding to the list\n");
+	    tmp = session_data->first_new_flow_description;
+	    //scrolls to last valid entry
+	    while (tmp) {
+		tmp1 = tmp->next;
+		if(!tmp1) {
+		    break;
+		}
+		tmp = tmp1;
+	    }
+	    tmp->next = fd;
+	}
+    }
+    
+    return 1;
+}
+
+/* Param current tells us if this a current fd or a new fd to add*/
+void free_flow_description(rx_authsessiondata_t* session_data, int current) {
+    
+    flow_description_t *flow_description;
+    flow_description_t *flow_description_tmp;
+    if(!session_data){
+	return;
+    }
+    
+    if(current) {
+	LM_DBG("Destroy current flow description\n");
+	flow_description = session_data->first_current_flow_description;
+	if(!flow_description) {
+	    return;
+	}
+    } else {
+	LM_DBG("Destroy new flow description\n");
+	flow_description = session_data->first_new_flow_description;
+	if(!flow_description) {
+	    return;
+	}
+    }
+    
+    while (flow_description) {
+        flow_description_tmp = flow_description->next;
+        shm_free(flow_description);
+	flow_description = 0;
+	flow_description = flow_description_tmp;
+    }
+}
+
+void free_callsessiondata(rx_authsessiondata_t* session_data) {
+
+    if(!session_data){
+	return;
+    }
+    
+    LM_DBG("Destroy current flow description\n");
+    free_flow_description(session_data, 1);
+    
+    LM_DBG("Destroy new flow description\n");
+    free_flow_description(session_data, 0);
+    
+    LM_DBG("Destroy session data\n");
+    shm_free(session_data);
+    session_data = 0;
+}
+
+void show_callsessiondata(rx_authsessiondata_t* session_data) {
+    
+    flow_description_t *flow_description;
+    
+    if(!session_data){
+	return;
+    }
+    
+    LM_DBG("Session data:\n");
+    LM_DBG("=====================\n");
+    LM_DBG("Call id [%.*s]\n", session_data->callid.len, session_data->callid.s);
+    LM_DBG("Domain [%.*s]\n", session_data->domain.len, session_data->domain.s);
+    LM_DBG("Ftag [%.*s]\n", session_data->ftag.len, session_data->ftag.s);
+    LM_DBG("Ttag [%.*s]\n", session_data->ttag.len, session_data->ttag.s);
+    LM_DBG("Identifier [%.*s]\n", session_data->identifier.len, session_data->identifier.s);
+    LM_DBG("Registration AOR [%.*s]\n", session_data->registration_aor.len, session_data->registration_aor.s);
+    LM_DBG("IP [%.*s]\n", session_data->ip.len, session_data->ip.s);
+    LM_DBG("IP version [%d]\n", session_data->ip_version);
+    LM_DBG("Must terminate dialog [%d]\n", session_data->must_terminate_dialog);
+    LM_DBG("Subscribed to signalling path status [%d]\n", session_data->subscribed_to_signaling_path_status);
+    
+    flow_description = session_data->first_current_flow_description;
+    while(flow_description) {
+	LM_DBG("Current Flow description [%d]\n", flow_description->stream_num);
+	LM_DBG("\tMedia [%.*s]\n", flow_description->media.len, flow_description->media.s);
+	LM_DBG("\tReq_sdp_ip_addr [%.*s]\n", flow_description->req_sdp_ip_addr.len, flow_description->req_sdp_ip_addr.s);
+	LM_DBG("\tReq_sdp_port [%.*s]\n", flow_description->req_sdp_port.len, flow_description->req_sdp_port.s);
+	LM_DBG("\tReq_sdp_raw_stream [%.*s]\n", flow_description->req_sdp_raw_stream.len, flow_description->req_sdp_raw_stream.s);
+	LM_DBG("\tRpl_sdp_ip_addr [%.*s]\n", flow_description->rpl_sdp_ip_addr.len, flow_description->rpl_sdp_ip_addr.s);
+	LM_DBG("\tRpl_sdp_port [%.*s]\n", flow_description->rpl_sdp_port.len, flow_description->rpl_sdp_port.s);
+	LM_DBG("\tRpl_sdp_raw_stream [%.*s]\n", flow_description->rpl_sdp_raw_stream.len, flow_description->rpl_sdp_raw_stream.s);
+	LM_DBG("\tRpl_sdp_transport [%.*s]\n", flow_description->rpl_sdp_transport.len, flow_description->rpl_sdp_transport.s);
+	LM_DBG("\tDirection [%d]\n", flow_description->direction);
+	flow_description = flow_description->next;
+    }
+    flow_description = session_data->first_new_flow_description;
+    while(flow_description) {
+	LM_DBG("New Flow description [%d]\n", flow_description->stream_num);
+	LM_DBG("\tMedia [%.*s]\n", flow_description->media.len, flow_description->media.s);
+	LM_DBG("\tReq_sdp_ip_addr [%.*s]\n", flow_description->req_sdp_ip_addr.len, flow_description->req_sdp_ip_addr.s);
+	LM_DBG("\tReq_sdp_port [%.*s]\n", flow_description->req_sdp_port.len, flow_description->req_sdp_port.s);
+	LM_DBG("\tReq_sdp_raw_stream [%.*s]\n", flow_description->req_sdp_raw_stream.len, flow_description->req_sdp_raw_stream.s);
+	LM_DBG("\tRpl_sdp_ip_addr [%.*s]\n", flow_description->rpl_sdp_ip_addr.len, flow_description->rpl_sdp_ip_addr.s);
+	LM_DBG("\tRpl_sdp_port [%.*s]\n", flow_description->rpl_sdp_port.len, flow_description->rpl_sdp_port.s);
+	LM_DBG("\tRpl_sdp_raw_stream [%.*s]\n", flow_description->rpl_sdp_raw_stream.len, flow_description->rpl_sdp_raw_stream.s);
+	LM_DBG("\tRpl_sdp_transport [%.*s]\n", flow_description->rpl_sdp_transport.len, flow_description->rpl_sdp_transport.s);
+	LM_DBG("\tDirection [%d]\n", flow_description->direction);
+	flow_description = flow_description->next;
+    }
+    
+    LM_DBG("=====================\n");
+}
 
 

+ 25 - 1
modules/ims_qos/rx_authdata.h

@@ -61,21 +61,45 @@ enum dialog_direction {
     DLG_MOBILE_UNKNOWN = 4
     DLG_MOBILE_UNKNOWN = 4
 };
 };
 
 
+typedef struct flow_description {
+    int stream_num;
+    str media;
+    str req_sdp_ip_addr;
+    str req_sdp_port;
+    str rpl_sdp_ip_addr;
+    str rpl_sdp_port;
+    str rpl_sdp_transport;
+    str req_sdp_raw_stream;
+    str rpl_sdp_raw_stream;
+    int direction;
+    struct flow_description *next;
+}flow_description_t;
+
 typedef struct rx_authsessiondata {
 typedef struct rx_authsessiondata {
     str callid;
     str callid;
     str ftag;
     str ftag;
     str ttag;
     str ttag;
     str identifier;
     str identifier;
     str ip;
     str ip;
+    int ip_version;
     //for registration session
     //for registration session
     int subscribed_to_signaling_path_status; // 0 not subscribed 1 is subscribed
     int subscribed_to_signaling_path_status; // 0 not subscribed 1 is subscribed
     str domain;				//the domain the registration aor belongs to (for registration)
     str domain;				//the domain the registration aor belongs to (for registration)
     str registration_aor; //the aor if this rx session is a subscription to signalling status
     str registration_aor; //the aor if this rx session is a subscription to signalling status
     int must_terminate_dialog; //0 means when this session terminates it must not terminate the relevant dialog, 1 means it must terminate the dialog
     int must_terminate_dialog; //0 means when this session terminates it must not terminate the relevant dialog, 1 means it must terminate the dialog
+    flow_description_t *first_current_flow_description;
+    flow_description_t *first_new_flow_description;
 } rx_authsessiondata_t;
 } rx_authsessiondata_t;
 
 
 int create_new_regsessiondata(str* domain, str* aor, rx_authsessiondata_t** session_data);
 int create_new_regsessiondata(str* domain, str* aor, rx_authsessiondata_t** session_data);
-int create_new_callsessiondata(str* callid, str* ftag, str* ttag, str* identifier, str *ip, rx_authsessiondata_t** session_data);
+int create_new_callsessiondata(str* callid, str* ftag, str* ttag, str* identifier, str *ip, int ip_version, rx_authsessiondata_t** session_data);
+void free_callsessiondata(rx_authsessiondata_t* session_data);
+
+int add_flow_description(rx_authsessiondata_t* session_data, int stream_num, str *media, str *req_sdp_ip_addr, str *req_sdp_port,
+			str *rpl_sdp_ip_addr, str *rpl_sdp_port, str *rpl_sdp_transport, str *req_sdp_raw_stream, str *rpl_sdp_raw_stream, int direction, int current);
+void free_flow_description(rx_authsessiondata_t* session_data, int current);
+
+void show_callsessiondata(rx_authsessiondata_t* session_data);
 
 
 #endif
 #endif