12882Svi117747 /*
22882Svi117747  * CDDL HEADER START
32882Svi117747  *
42882Svi117747  * The contents of this file are subject to the terms of the
52882Svi117747  * Common Development and Distribution License (the "License").
62882Svi117747  * You may not use this file except in compliance with the License.
72882Svi117747  *
82882Svi117747  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92882Svi117747  * or http://www.opensolaris.org/os/licensing.
102882Svi117747  * See the License for the specific language governing permissions
112882Svi117747  * and limitations under the License.
122882Svi117747  *
132882Svi117747  * When distributing Covered Code, include this CDDL HEADER in each
142882Svi117747  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152882Svi117747  * If applicable, add the following below this CDDL HEADER, with the
162882Svi117747  * fields enclosed by brackets "[]" replaced with your own identifying
172882Svi117747  * information: Portions Copyright [yyyy] [name of copyright owner]
182882Svi117747  *
192882Svi117747  * CDDL HEADER END
202882Svi117747  */
212882Svi117747 
222882Svi117747 /*
233439Svi117747  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
242882Svi117747  * Use is subject to license terms.
252882Svi117747  */
262882Svi117747 
272882Svi117747 #pragma ident	"%Z%%M%	%I%	%E% SMI"
282882Svi117747 
293439Svi117747 #include <stdio.h>
303439Svi117747 #include <stdlib.h>
313439Svi117747 #include <assert.h>
323439Svi117747 #include <errno.h>
333439Svi117747 #include <pthread.h>
343439Svi117747 #include <strings.h>
353439Svi117747 #include <sip.h>
363439Svi117747 
372882Svi117747 #include "sip_msg.h"
383439Svi117747 #include "sip_miscdefs.h"
392882Svi117747 #include "sip_hash.h"
402882Svi117747 #include "sip_dialog.h"
412882Svi117747 #include "sip_parse_generic.h"
422882Svi117747 
432882Svi117747 #define	SIP_DLG_XCHG_FROM	0
442882Svi117747 #define	SIP_DLG_XCHG_TO		1
452882Svi117747 
462882Svi117747 /*
472882Svi117747  * Dialog state change callback function
482882Svi117747  */
492882Svi117747 void (*sip_dlg_ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int) = NULL;
502882Svi117747 void (*sip_ulp_dlg_del_cb)(sip_dialog_t, sip_msg_t, void *) = NULL;
512882Svi117747 
522882Svi117747 boolean_t	sip_incomplete_dialog(sip_dialog_t);
532882Svi117747 
542882Svi117747 /*
552882Svi117747  * Exchange From/To header
562882Svi117747  */
572882Svi117747 _sip_header_t *sip_dlg_xchg_from_to(sip_msg_t, int);
582882Svi117747 
592882Svi117747 /*
602882Svi117747  * Complete dialog hash table
612882Svi117747  */
622882Svi117747 sip_hash_t sip_dialog_hash[SIP_HASH_SZ];
632882Svi117747 
642882Svi117747 /*
652882Svi117747  * Partial dialog hash table
662882Svi117747  */
672882Svi117747 sip_hash_t sip_dialog_phash[SIP_HASH_SZ];
682882Svi117747 
692882Svi117747 /*
702882Svi117747  * Route set structure
712882Svi117747  */
722882Svi117747 typedef struct sip_dlg_route_set_s  {
732882Svi117747 	char		*sip_dlg_route;
742882Svi117747 	sip_str_t	sip_dlg_ruri;
752882Svi117747 	boolean_t	sip_dlg_route_lr;
762882Svi117747 	struct sip_dlg_route_set_s *sip_dlg_route_next;
772882Svi117747 }sip_dlg_route_set_t;
782882Svi117747 
792882Svi117747 sip_dialog_t		sip_seed_dialog(sip_conn_object_t, _sip_msg_t *,
802882Svi117747 			    boolean_t, int);
812882Svi117747 sip_dialog_t		sip_complete_dialog(_sip_msg_t *, _sip_dialog_t *);
822882Svi117747 int			sip_dialog_process(_sip_msg_t *, sip_dialog_t *);
832882Svi117747 void			sip_dialog_delete(_sip_dialog_t *);
842882Svi117747 void			sip_dialog_init();
852882Svi117747 sip_dialog_t		sip_dialog_find(_sip_msg_t *);
862882Svi117747 boolean_t		sip_dialog_match(void *, void *);
872882Svi117747 boolean_t		sip_dialog_free(void *, void *, int *);
882882Svi117747 sip_dialog_t		sip_update_dialog(sip_dialog_t, _sip_msg_t *);
892882Svi117747 char			*sip_dialog_req_uri(sip_dialog_t);
902882Svi117747 
912882Svi117747 static void		sip_release_dialog_res(_sip_dialog_t *);
922882Svi117747 void			sip_dlg_self_destruct(void *);
932882Svi117747 static int		sip_dialog_get_route_set(_sip_dialog_t *, _sip_msg_t *,
942882Svi117747 			    int);
952882Svi117747 static void		sip_dialog_free_rset(sip_dlg_route_set_t *);
962882Svi117747 
972882Svi117747 /*
982882Svi117747  * Timer object for partial dialogs
992882Svi117747  */
1002882Svi117747 typedef struct sip_dialog_timer_obj_s {
1012882Svi117747 	_sip_dialog_t	*dialog;
1022882Svi117747 	void		(*func)(sip_dialog_t, sip_msg_t, void *);
1032882Svi117747 } sip_dialog_timer_obj_t;
1042882Svi117747 
1052882Svi117747 /*
1062882Svi117747  * To avoid duplication all over the place
1072882Svi117747  */
1082882Svi117747 static void
1092882Svi117747 sip_release_dialog_res(_sip_dialog_t *dialog)
1102882Svi117747 {
1112882Svi117747 
1122882Svi117747 	assert(dialog->sip_dlg_ref_cnt == 0);
1132882Svi117747 	if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
1142882Svi117747 		SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
1152882Svi117747 	if (dialog->sip_dlg_call_id != NULL)
1162882Svi117747 		sip_free_header(dialog->sip_dlg_call_id);
1172882Svi117747 	if (dialog->sip_dlg_local_uri_tag != NULL)
1182882Svi117747 		sip_free_header(dialog->sip_dlg_local_uri_tag);
1192882Svi117747 	if (dialog->sip_dlg_remote_uri_tag != NULL)
1202882Svi117747 		sip_free_header(dialog->sip_dlg_remote_uri_tag);
1212882Svi117747 	if (dialog->sip_dlg_remote_target != NULL)
1222882Svi117747 		sip_free_header(dialog->sip_dlg_remote_target);
123*4702Sgm209912 	if (dialog->sip_dlg_local_contact != NULL)
124*4702Sgm209912 		sip_free_header(dialog->sip_dlg_local_contact);
125*4702Sgm209912 	if (dialog->sip_dlg_new_local_contact != NULL)
126*4702Sgm209912 		sip_free_header(dialog->sip_dlg_new_local_contact);
1272882Svi117747 	if (dialog->sip_dlg_route_set != NULL)
1282882Svi117747 		sip_free_header(dialog->sip_dlg_route_set);
1292882Svi117747 	if (dialog->sip_dlg_event != NULL)
1302882Svi117747 		sip_free_header(dialog->sip_dlg_event);
1312882Svi117747 	if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) {
1322882Svi117747 		free(dialog->sip_dlg_req_uri.sip_str_ptr);
1332882Svi117747 		dialog->sip_dlg_req_uri.sip_str_ptr = NULL;
1342882Svi117747 		dialog->sip_dlg_req_uri.sip_str_len = 0;
1352882Svi117747 	}
1362882Svi117747 	if (dialog->sip_dlg_rset.sip_str_ptr != NULL) {
1372882Svi117747 		free(dialog->sip_dlg_rset.sip_str_ptr);
1382882Svi117747 		dialog->sip_dlg_rset.sip_str_len = 0;
1392882Svi117747 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
1402882Svi117747 	}
1412882Svi117747 	(void) pthread_mutex_destroy(&dialog->sip_dlg_mutex);
1422882Svi117747 	free(dialog);
1432882Svi117747 }
1442882Svi117747 
1452882Svi117747 /*
1462882Svi117747  * Get the route information from the 'value' and add it to the route
1472882Svi117747  * set.
1482882Svi117747  */
1492882Svi117747 static sip_dlg_route_set_t *
1502882Svi117747 sip_add_route_to_set(sip_hdr_value_t *value)
1512882Svi117747 {
1522882Svi117747 	int			vlen = 0;
1532882Svi117747 	sip_dlg_route_set_t	*rset;
1542882Svi117747 	char			*crlf;
1552882Svi117747 	const sip_param_t	*uri_param;
1562882Svi117747 	int			error;
1572882Svi117747 
1582882Svi117747 	rset = calloc(1, sizeof (*rset));
1592882Svi117747 	if (rset == NULL)
1602882Svi117747 		return (NULL);
1612882Svi117747 	rset->sip_dlg_route_next = NULL;
1622882Svi117747 	vlen = value->sip_value_end - value->sip_value_start;
1632882Svi117747 
1642882Svi117747 	/*
1652882Svi117747 	 * check for CRLF
1662882Svi117747 	 */
1672882Svi117747 	crlf = value->sip_value_end - strlen(SIP_CRLF);
1682882Svi117747 	while (crlf != NULL && strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) {
1692882Svi117747 		vlen -= strlen(SIP_CRLF);
1702882Svi117747 		crlf -= strlen(SIP_CRLF);
1712882Svi117747 	}
1722882Svi117747 	rset->sip_dlg_route = calloc(1, vlen + 1);
1732882Svi117747 	if (rset->sip_dlg_route == NULL) {
1742882Svi117747 		free(rset);
1752882Svi117747 		return (NULL);
1762882Svi117747 	}
1772882Svi117747 	/*
1782882Svi117747 	 * loose routing
1792882Svi117747 	 */
1802882Svi117747 	rset->sip_dlg_route_lr = B_FALSE;
1812882Svi117747 	(void) strncpy(rset->sip_dlg_route, value->sip_value_start, vlen);
1822882Svi117747 	rset->sip_dlg_ruri.sip_str_ptr = rset->sip_dlg_route +
1832882Svi117747 	    (value->cftr_uri.sip_str_ptr - value->sip_value_start);
1842882Svi117747 	rset->sip_dlg_ruri.sip_str_len = value->cftr_uri.sip_str_len;
1852882Svi117747 	rset->sip_dlg_route[vlen] = '\0';
1862882Svi117747 
1872882Svi117747 	assert(value->sip_value_parsed_uri != NULL);
1882882Svi117747 	/*
1892882Svi117747 	 * Check if the 'lr' param is present for this route.
1902882Svi117747 	 */
1912882Svi117747 	uri_param = sip_get_uri_params(value->sip_value_parsed_uri, &error);
1922882Svi117747 	if (error != 0) {
1932882Svi117747 		free(rset->sip_dlg_route);
1942882Svi117747 		free(rset);
1952882Svi117747 		return (NULL);
1962882Svi117747 	}
1972882Svi117747 	if (uri_param != NULL) {
1982882Svi117747 		rset->sip_dlg_route_lr = sip_is_param_present(uri_param, "lr",
1992882Svi117747 		    strlen("lr"));
2002882Svi117747 	}
2012882Svi117747 	return (rset);
2022882Svi117747 }
2032882Svi117747 
2042882Svi117747 /*
2052882Svi117747  * Depending on the route-set, determine the request URI.
2062882Svi117747  */
2072882Svi117747 char *
2082882Svi117747 sip_dialog_req_uri(sip_dialog_t dialog)
2092882Svi117747 {
2102882Svi117747 	const sip_str_t		*req_uri;
2112882Svi117747 	char			*uri;
2122882Svi117747 	_sip_dialog_t		*_dialog;
2132882Svi117747 
2142882Svi117747 	_dialog = (_sip_dialog_t *)dialog;
2152882Svi117747 	if (_dialog->sip_dlg_route_set == NULL ||
2162882Svi117747 	    _dialog->sip_dlg_req_uri.sip_str_ptr == NULL) {
2172882Svi117747 		const struct sip_value	*val;
2182882Svi117747 
2192882Svi117747 		val = sip_get_header_value(_dialog->sip_dlg_remote_target,
2202882Svi117747 		    NULL);
2212882Svi117747 		if (val == NULL)
2222882Svi117747 			return (NULL);
2232882Svi117747 		req_uri = &((sip_hdr_value_t *)val)->cftr_uri;
2242882Svi117747 	} else {
2252882Svi117747 		req_uri = &_dialog->sip_dlg_req_uri;
2262882Svi117747 	}
2272882Svi117747 	uri = (char *)malloc(req_uri->sip_str_len + 1);
2282882Svi117747 	if (uri == NULL)
2292882Svi117747 		return (NULL);
2302882Svi117747 	(void) strncpy(uri, req_uri->sip_str_ptr, req_uri->sip_str_len);
2312882Svi117747 	uri[req_uri->sip_str_len] = '\0';
2322882Svi117747 
2332882Svi117747 	return (uri);
2342882Svi117747 }
2352882Svi117747 
2362882Svi117747 /*
2372882Svi117747  * Free the route set.
2382882Svi117747  */
2392882Svi117747 void
2402882Svi117747 sip_dialog_free_rset(sip_dlg_route_set_t *rset)
2412882Svi117747 {
2422882Svi117747 	sip_dlg_route_set_t	*next;
2432882Svi117747 
2442882Svi117747 	while (rset != NULL) {
2452882Svi117747 		next = rset->sip_dlg_route_next;
2462882Svi117747 		rset->sip_dlg_route_next = NULL;
2472882Svi117747 		free(rset->sip_dlg_route);
2482882Svi117747 		free(rset);
2492882Svi117747 		rset = next;
2502882Svi117747 	}
2512882Svi117747 }
2522882Svi117747 
2532882Svi117747 /*
2542882Svi117747  * Recompute route-set
2552882Svi117747  */
2562882Svi117747 static int
2572882Svi117747 sip_dlg_recompute_rset(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what)
2582882Svi117747 {
2592882Svi117747 	int ret;
2602882Svi117747 
2612882Svi117747 	if (dialog->sip_dlg_route_set != NULL) {
2622882Svi117747 		sip_free_header(dialog->sip_dlg_route_set);
2632882Svi117747 		dialog->sip_dlg_route_set = NULL;
2642882Svi117747 	}
2652882Svi117747 	if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) {
2662882Svi117747 		free(dialog->sip_dlg_req_uri.sip_str_ptr);
2672882Svi117747 		dialog->sip_dlg_req_uri.sip_str_ptr = NULL;
2682882Svi117747 		dialog->sip_dlg_req_uri.sip_str_len = 0;
2692882Svi117747 	}
2702882Svi117747 	if (dialog->sip_dlg_rset.sip_str_ptr != NULL) {
2712882Svi117747 		free(dialog->sip_dlg_rset.sip_str_ptr);
2722882Svi117747 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
2732882Svi117747 		dialog->sip_dlg_rset.sip_str_len = 0;
2742882Svi117747 	}
2752882Svi117747 	ret = sip_dialog_get_route_set(dialog, sip_msg, what);
2762882Svi117747 	return (ret);
2772882Svi117747 }
2782882Svi117747 
2792882Svi117747 /*
2802882Svi117747  * If the route set is empty, the UAC MUST place the remote target URI
2812882Svi117747  * into the Request-URI.  The UAC MUST NOT add a Route header field to
2822882Svi117747  * the request.
2832882Svi117747  *
2842882Svi117747  * If the route set is not empty, and the first URI in the route set
2852882Svi117747  * contains the lr parameter (see Section 19.1.1), the UAC MUST place
2862882Svi117747  * the remote target URI into the Request-URI and MUST include a Route
2872882Svi117747  * header field containing the route set values in order, including all
2882882Svi117747  * parameters.
2892882Svi117747  *
2902882Svi117747  * If the route set is not empty, and its first URI does not contain the
2912882Svi117747  * lr parameter, the UAC MUST place the first URI from the route set
2922882Svi117747  * into the Request-URI, stripping any parameters that are not allowed
2932882Svi117747  * in a Request-URI.  The UAC MUST add a Route header field containing
2942882Svi117747  * the remainder of the route set values in order, including all
2952882Svi117747  * parameters.  The UAC MUST then place the remote target URI into the
2962882Svi117747  * Route header field as the last value.
2972882Svi117747  */
2982882Svi117747 int
2992882Svi117747 sip_dialog_set_route_hdr(_sip_dialog_t *dialog, sip_dlg_route_set_t *rset_head,
3002882Svi117747     int rcnt, int rlen)
3012882Svi117747 {
3022882Svi117747 	size_t			rset_len;
3032882Svi117747 	_sip_header_t		*rhdr;
3042882Svi117747 	char			*rset;
3052882Svi117747 	char			*rp;
3062882Svi117747 	char			*rsp;
3072882Svi117747 	int			count;
3082882Svi117747 	sip_dlg_route_set_t	*route;
3092882Svi117747 	boolean_t		first = B_TRUE;
3102882Svi117747 	const sip_str_t		*to_uri;
3112882Svi117747 	char			*uri = NULL;
3122882Svi117747 	int			rspl;
3132882Svi117747 	int			rpl;
3142882Svi117747 
3152882Svi117747 	assert(rcnt > 0);
3162882Svi117747 
3172882Svi117747 	dialog->sip_dlg_rset.sip_str_len = rlen + rcnt - 1;
3182882Svi117747 	dialog->sip_dlg_rset.sip_str_ptr = malloc(rlen + rcnt);
3192882Svi117747 	if (dialog->sip_dlg_rset.sip_str_ptr == NULL)
3202882Svi117747 		return (ENOMEM);
3212882Svi117747 	rsp = dialog->sip_dlg_rset.sip_str_ptr;
3222882Svi117747 	rspl = rlen + rcnt;
3232882Svi117747 	route = rset_head;
3242882Svi117747 	rset_len = rlen;
3252882Svi117747 	if (!route->sip_dlg_route_lr) {
3262882Svi117747 		const struct sip_value	*val;
3272882Svi117747 
3282882Svi117747 		val = sip_get_header_value(dialog->sip_dlg_remote_target, NULL);
3292882Svi117747 		to_uri = &((sip_hdr_value_t *)val)->cftr_uri;
3302882Svi117747 		uri = (char *)malloc(to_uri->sip_str_len + 1);
3312882Svi117747 		if (uri == NULL) {
3322882Svi117747 			free(dialog->sip_dlg_rset.sip_str_ptr);
3332882Svi117747 			dialog->sip_dlg_rset.sip_str_len = 0;
3342882Svi117747 			dialog->sip_dlg_rset.sip_str_ptr = NULL;
3352882Svi117747 			return (ENOMEM);
3362882Svi117747 		}
3372882Svi117747 		(void) strncpy(uri, to_uri->sip_str_ptr, to_uri->sip_str_len);
3382882Svi117747 		uri[to_uri->sip_str_len] = '\0';
3392882Svi117747 		rset_len = rlen - strlen(route->sip_dlg_route) + strlen(uri) +
3402882Svi117747 		    SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN +
3412882Svi117747 		    sizeof (char);
3422882Svi117747 		count = snprintf(rsp, rspl, "%s", route->sip_dlg_route);
3432882Svi117747 		dialog->sip_dlg_req_uri.sip_str_ptr = malloc(
3442882Svi117747 		    route->sip_dlg_ruri.sip_str_len + 1);
3452882Svi117747 		if (dialog->sip_dlg_req_uri.sip_str_ptr == NULL) {
3462882Svi117747 			free(uri);
3472882Svi117747 			free(dialog->sip_dlg_rset.sip_str_ptr);
3482882Svi117747 			dialog->sip_dlg_rset.sip_str_len = 0;
3492882Svi117747 			dialog->sip_dlg_rset.sip_str_ptr = NULL;
3502882Svi117747 			return (ENOMEM);
3512882Svi117747 		}
3522882Svi117747 		(void) strncpy(dialog->sip_dlg_req_uri.sip_str_ptr, rsp +
3532882Svi117747 		    (route->sip_dlg_ruri.sip_str_ptr - route->sip_dlg_route),
3542882Svi117747 		    route->sip_dlg_ruri.sip_str_len);
3552882Svi117747 		dialog->sip_dlg_req_uri.sip_str_ptr[
3562882Svi117747 		    route->sip_dlg_ruri.sip_str_len] = '\0';
3572882Svi117747 		dialog->sip_dlg_req_uri.sip_str_len =
3582882Svi117747 		    route->sip_dlg_ruri.sip_str_len;
3592882Svi117747 
3602882Svi117747 		rsp += count;
3612882Svi117747 		rspl -= count;
3622882Svi117747 		route = route->sip_dlg_route_next;
3632882Svi117747 	}
3642882Svi117747 
3652882Svi117747 	/*
3662882Svi117747 	 * rcnt - 1 is for the number of COMMAs
3672882Svi117747 	 */
3682882Svi117747 	rset_len += strlen(SIP_ROUTE) + SIP_SPACE_LEN + sizeof (char) +
3692882Svi117747 	    SIP_SPACE_LEN + rcnt - 1;
3702882Svi117747 	rset = malloc(rset_len + 1);
3712882Svi117747 	if (rset == NULL) {
3722882Svi117747 		free(dialog->sip_dlg_rset.sip_str_ptr);
3732882Svi117747 		dialog->sip_dlg_rset.sip_str_len = 0;
3742882Svi117747 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
3752882Svi117747 		return (ENOMEM);
3762882Svi117747 	}
3772882Svi117747 	rhdr = sip_new_header(rset_len + strlen(SIP_CRLF));
3782882Svi117747 	if (rhdr == NULL) {
3792882Svi117747 		free(rset);
3802882Svi117747 		free(dialog->sip_dlg_rset.sip_str_ptr);
3812882Svi117747 		dialog->sip_dlg_rset.sip_str_len = 0;
3822882Svi117747 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
3832882Svi117747 		return (ENOMEM);
3842882Svi117747 	}
3852882Svi117747 
3862882Svi117747 	rp = rset;
3872882Svi117747 	rpl = rset_len + 1;
3882882Svi117747 	count = snprintf(rp, rpl, "%s %c ", SIP_ROUTE, SIP_HCOLON);
3892882Svi117747 	rp += count;
3902882Svi117747 	rpl -= count;
3912882Svi117747 
3922882Svi117747 	while (route != NULL) {
3932882Svi117747 		if (first) {
3942882Svi117747 			count = snprintf(rp, rpl, "%s", route->sip_dlg_route);
3952882Svi117747 			rp += count;
3962882Svi117747 			rpl -= count;
3972882Svi117747 			first = B_FALSE;
3982882Svi117747 			if (uri != NULL) {
3992882Svi117747 				count = snprintf(rsp, rspl, "%c%s",
4002882Svi117747 				    SIP_COMMA, route->sip_dlg_route);
4012882Svi117747 			} else {
4022882Svi117747 				count = snprintf(rsp, rspl, "%s",
4032882Svi117747 				    route->sip_dlg_route);
4042882Svi117747 			}
4052882Svi117747 			rsp += count;
4062882Svi117747 			rspl -= count;
4072882Svi117747 		} else {
4082882Svi117747 			count = snprintf(rp, rpl, "%c%s", SIP_COMMA,
4092882Svi117747 			    route->sip_dlg_route);
4102882Svi117747 			rp += count;
4112882Svi117747 			rpl -= count;
4122882Svi117747 			count = snprintf(rsp, rspl, "%c%s", SIP_COMMA,
4132882Svi117747 			    route->sip_dlg_route);
4142882Svi117747 			rsp += count;
4152882Svi117747 			rspl -= count;
4162882Svi117747 		}
4172882Svi117747 		route = route->sip_dlg_route_next;
4182882Svi117747 	}
4192882Svi117747 	assert(rsp <= dialog->sip_dlg_rset.sip_str_ptr +
4202882Svi117747 	    dialog->sip_dlg_rset.sip_str_len);
4212882Svi117747 	dialog->sip_dlg_rset.sip_str_ptr[dialog->sip_dlg_rset.sip_str_len] =
4222882Svi117747 	    '\0';
4232882Svi117747 	if (uri != NULL) {
4242882Svi117747 		if (first) {
4252882Svi117747 			count = snprintf(rp, rpl, "%c %s %c", SIP_LAQUOT,
4262882Svi117747 			    uri, SIP_RAQUOT);
4272882Svi117747 		} else {
4282882Svi117747 			count = snprintf(rp, rpl, "%c%c %s %c", SIP_COMMA,
4292882Svi117747 			    SIP_LAQUOT, uri, SIP_RAQUOT);
4302882Svi117747 		}
4312882Svi117747 		rp += count;
4322882Svi117747 		rpl -= count;
4332882Svi117747 		free(uri);
4342882Svi117747 	}
4352882Svi117747 	assert(rp <= rset + rset_len);
4362882Svi117747 	(void) snprintf(rhdr->sip_hdr_start, rset_len + strlen(SIP_CRLF) + 1,
4372882Svi117747 	    "%s%s", rset, SIP_CRLF);
4382882Svi117747 	free(rset);
4392882Svi117747 	dialog->sip_dlg_route_set = (sip_header_t)rhdr;
4402882Svi117747 	sip_dialog_free_rset(rset_head);
4412882Svi117747 	return (0);
4422882Svi117747 }
4432882Svi117747 
4442882Svi117747 /*
4452882Svi117747  * UAC Behavior
4462882Svi117747  * The route set MUST be set to the list of URIs in the Record-Route
4472882Svi117747  * header field from the response, taken in reverse order and preserving
4482882Svi117747  * all URI parameters.
4492882Svi117747  *
4502882Svi117747  * UAS behavior
4512882Svi117747  * The route set MUST be set to the list of URIs in the Record-Route
4522882Svi117747  * header field from the request, taken in order and preserving all URI
4532882Svi117747  * parameters.
4542882Svi117747  */
4552882Svi117747 static int
4562882Svi117747 sip_dialog_get_route_set(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what)
4572882Svi117747 {
4582882Svi117747 	sip_header_t		rrhdr;
4592882Svi117747 	sip_hdr_value_t		*value;
4602882Svi117747 	int			error;
4612882Svi117747 	sip_dlg_route_set_t	*rset_head = NULL;
4622882Svi117747 	sip_dlg_route_set_t	*rset_tail = NULL;
4632882Svi117747 	sip_dlg_route_set_t	*rset;
4642882Svi117747 	int			rset_cnt = 0;
4652882Svi117747 	int			rset_len = 0;
4662882Svi117747 
4672882Svi117747 	(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
4682882Svi117747 	rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, NULL);
4692882Svi117747 	while (rrhdr != NULL) {
4702882Svi117747 		(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
4712882Svi117747 		value = (sip_hdr_value_t *)sip_get_header_value(rrhdr, &error);
4722882Svi117747 		while (value != NULL && error == 0) {
4732882Svi117747 			char	*crlf;
4742882Svi117747 
4752882Svi117747 			if (value->sip_value_state == SIP_VALUE_BAD) {
4762882Svi117747 				value = (sip_hdr_value_t *)sip_get_next_value(
4772882Svi117747 				    (sip_header_value_t)value, &error);
4782882Svi117747 				continue;
4792882Svi117747 			}
4802882Svi117747 			rset = sip_add_route_to_set(value);
4812882Svi117747 			if (rset == NULL)
4822882Svi117747 				goto r_error;
4832882Svi117747 			/*
4842882Svi117747 			 * Add one for COMMA
4852882Svi117747 			 */
4862882Svi117747 			rset_cnt++;
4872882Svi117747 			rset_len += (value->sip_value_end -
4882882Svi117747 			    value->sip_value_start);
4892882Svi117747 			/*
4902882Svi117747 			 * Check for CRLF
4912882Svi117747 			 */
4922882Svi117747 			crlf = value->sip_value_end - strlen(SIP_CRLF);
4932882Svi117747 			while (crlf != NULL &&
4942882Svi117747 			    strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) {
4952882Svi117747 				rset_len -= strlen(SIP_CRLF);
4962882Svi117747 				crlf -= strlen(SIP_CRLF);
4972882Svi117747 			}
4982882Svi117747 			if (rset_head == NULL) {
4992882Svi117747 				assert(rset_tail == NULL);
5002882Svi117747 				rset_head = rset_tail = rset;
5012882Svi117747 			} else if (what == SIP_UAS_DIALOG) {
5022882Svi117747 				rset_tail->sip_dlg_route_next = rset;
5032882Svi117747 				rset_tail = rset;
5042882Svi117747 			} else if (what == SIP_UAC_DIALOG) {
5052882Svi117747 				rset->sip_dlg_route_next = rset_head;
5062882Svi117747 				rset_head = rset;
5072882Svi117747 			} else {
5082882Svi117747 				assert(0);
5092882Svi117747 			}
5102882Svi117747 			value = (sip_hdr_value_t *)sip_get_next_value(
5112882Svi117747 			    (sip_header_value_t)value, &error);
5122882Svi117747 		}
5132882Svi117747 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
5142882Svi117747 		rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, rrhdr);
5152882Svi117747 	}
5162882Svi117747 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
5172882Svi117747 	if (rset_cnt == 0)
5182882Svi117747 		return (0);
5192882Svi117747 	if (sip_dialog_set_route_hdr(dialog, rset_head, rset_cnt,
5202882Svi117747 	    rset_len) != 0) {
5212882Svi117747 		goto r_error;
5222882Svi117747 	}
5232882Svi117747 	return (0);
5242882Svi117747 r_error:
5252882Svi117747 	sip_dialog_free_rset(rset_head);
5262882Svi117747 	return (ENOMEM);
5272882Svi117747 }
5282882Svi117747 
5292882Svi117747 /*
5302882Svi117747  * UAS behavior:
5312882Svi117747  * The remote sequence number MUST be set to the value of the sequence
5322882Svi117747  * number in the CSeq header field of the request.  The local sequence
5332882Svi117747  * number MUST be empty.  The call identifier component of the dialog ID
5342882Svi117747  * MUST be set to the value of the Call-ID in the request.  The local
5352882Svi117747  * tag component of the dialog ID MUST be set to the tag in the To field
5362882Svi117747  * in the response to the request (which always includes a tag), and the
5372882Svi117747  * remote tag component of the dialog ID MUST be set to the tag from the
5382882Svi117747  * From field in the request.  A UAS MUST be prepared to receive a
5392882Svi117747  * request without a tag in the From field, in which case the tag is
5402882Svi117747  * considered to have a value of null.
5412882Svi117747  * The remote URI MUST be set to the URI in the From field, and the
5422882Svi117747  * local URI MUST be set to the URI in the To field.
5432882Svi117747  * The remote target MUST be set to the URI from the Contact header field
5442882Svi117747  * of the request.
5452882Svi117747  *
5462882Svi117747  * UAC behavior:
5472882Svi117747  * The local sequence number MUST be set to the value of the sequence
5482882Svi117747  * number in the CSeq header field of the request.  The remote sequence
5492882Svi117747  * number MUST be empty (it is established when the remote UA sends a
5502882Svi117747  * request within the dialog).  The call identifier component of the
5512882Svi117747  * dialog ID MUST be set to the value of the Call-ID in the request.
5522882Svi117747  * The local tag component of the dialog ID MUST be set to the tag in
5532882Svi117747  * the From field in the request, and the remote tag component of the
5542882Svi117747  * dialog ID MUST be set to the tag in the To field of the response.  A
5552882Svi117747  * UAC MUST be prepared to receive a response without a tag in the To
5562882Svi117747  * field, in which case the tag is considered to have a value of null.
5572882Svi117747  * The remote URI MUST be set to the URI in the To field, and the local
5582882Svi117747  * URI MUST be set to the URI in the From field.
5592882Svi117747  * The remote target MUST be set to the URI from the Contact header field
5602882Svi117747  * of the response.
5612882Svi117747  */
5622882Svi117747 
5632882Svi117747 
5642882Svi117747 /*
5652882Svi117747  * This is the routine that seeds a dialog.
5662882Svi117747  */
5672882Svi117747 sip_dialog_t
5682882Svi117747 sip_seed_dialog(sip_conn_object_t obj, _sip_msg_t *sip_msg,
5692882Svi117747     boolean_t dlg_on_fork, int dlg_type)
5702882Svi117747 {
5712882Svi117747 	_sip_dialog_t		*dialog;
5722882Svi117747 	int			cseq;
5732882Svi117747 	sip_header_t		fhdr = NULL;
5742882Svi117747 	sip_header_t		thdr = NULL;
5752882Svi117747 	sip_header_t		chdr;
5762882Svi117747 	sip_header_t		cihdr;
5772882Svi117747 	sip_header_t		evhdr = NULL;
5782882Svi117747 	const struct sip_value	*value;
5792882Svi117747 	sip_dialog_timer_obj_t	*tim_obj = NULL;
5802882Svi117747 	const sip_str_t		*callid;
5812882Svi117747 	sip_method_t		method;
5822882Svi117747 	int			timer1 = sip_timer_T1;
5832882Svi117747 	int			error;
5842882Svi117747 
5852882Svi117747 	if (!sip_msg_is_request((sip_msg_t)sip_msg, &error))
5862882Svi117747 		return (NULL);
5872882Svi117747 
5882882Svi117747 	method = sip_get_request_method((sip_msg_t)sip_msg, &error);
5892882Svi117747 	/*
5902882Svi117747 	 * Only INVITE and SUBSCRIBE supported
5912882Svi117747 	 */
5922882Svi117747 	if (error != 0 || (method != INVITE && method != SUBSCRIBE))
5932882Svi117747 		return (NULL);
5942882Svi117747 
5952882Svi117747 	/*
5962882Svi117747 	 * A request outside of a dialog MUST NOT contain a To tag
5972882Svi117747 	 */
5982882Svi117747 	if (sip_get_to_tag((sip_msg_t)sip_msg, NULL) != NULL)
5992882Svi117747 		return (NULL);
6002882Svi117747 
6012882Svi117747 	if (dlg_type == SIP_UAS_DIALOG) {
6022882Svi117747 		thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg,
6032882Svi117747 		    SIP_DLG_XCHG_FROM);
6042882Svi117747 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
6052882Svi117747 	} else {
6062882Svi117747 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
6072882Svi117747 		fhdr = sip_search_for_header(sip_msg, SIP_FROM, NULL);
6082882Svi117747 	}
6092882Svi117747 	cihdr = sip_search_for_header(sip_msg, SIP_CALL_ID, NULL);
6102882Svi117747 	chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
6112882Svi117747 	if (method == SUBSCRIBE)
6122882Svi117747 		evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL);
6132882Svi117747 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
6142882Svi117747 	if ((fhdr == NULL && thdr == NULL) || cihdr == NULL || chdr == NULL ||
6152882Svi117747 	    (method == SUBSCRIBE && evhdr == NULL)) {
6162882Svi117747 		if (thdr != NULL)
6172882Svi117747 			sip_free_header(thdr);
6182882Svi117747 		return (NULL);
6192882Svi117747 	}
6202882Svi117747 
6212882Svi117747 	/*
6222882Svi117747 	 * Sanity check since we just store the headers in the dialog
6232882Svi117747 	 */
6242882Svi117747 	if (sip_get_from_tag((sip_msg_t)sip_msg, NULL) == NULL ||
6252882Svi117747 	    sip_get_from_uri_str((sip_msg_t)sip_msg, NULL) == NULL ||
6262882Svi117747 	    ((cseq = sip_get_callseq_num((sip_msg_t)sip_msg, NULL)) == -1) ||
6272882Svi117747 	    (callid = sip_get_callid((sip_msg_t)sip_msg, NULL)) == NULL ||
6282882Svi117747 	    sip_get_to_uri_str((sip_msg_t)sip_msg, NULL) == NULL ||
6292882Svi117747 	    ((value = sip_get_header_value(chdr, NULL)) == NULL) ||
6302882Svi117747 	    sip_get_contact_uri_str((sip_header_value_t)value, NULL) == NULL) {
6312882Svi117747 		if (thdr != NULL)
6322882Svi117747 			sip_free_header(thdr);
6332882Svi117747 		return (NULL);
6342882Svi117747 	}
6352882Svi117747 
6362882Svi117747 	tim_obj = calloc(1, sizeof (sip_dialog_timer_obj_t));
6372882Svi117747 	if (tim_obj == NULL) {
6382882Svi117747 		if (thdr != NULL)
6392882Svi117747 			sip_free_header(thdr);
6402882Svi117747 		return (NULL);
6412882Svi117747 	}
6422882Svi117747 	dialog = calloc(1, sizeof (_sip_dialog_t));
6432882Svi117747 	if (dialog == NULL) {
6442882Svi117747 		if (thdr != NULL)
6452882Svi117747 			sip_free_header(thdr);
6462882Svi117747 		return (NULL);
6472882Svi117747 	}
6482882Svi117747 	/*
6492882Svi117747 	 * We will take the TO header with the tag when we complete this
6502882Svi117747 	 * dialog
6512882Svi117747 	 */
6522882Svi117747 	if (dlg_type == SIP_UAS_DIALOG) {
6532882Svi117747 		dialog->sip_dlg_remote_uri_tag = thdr;
6542882Svi117747 		/*
6552882Svi117747 		 * We take the remote target from the incoming request on the
6562882Svi117747 		 * UAS. For the UAC, we will take it from the response.
6572882Svi117747 		 */
6582882Svi117747 		if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) ==
6592882Svi117747 		    NULL) {
6602882Svi117747 			goto dia_err;
6612882Svi117747 		}
6622882Svi117747 	} else {
6632882Svi117747 		if ((dialog->sip_dlg_local_uri_tag = sip_dup_header(fhdr)) ==
6642882Svi117747 		    NULL) {
6652882Svi117747 			goto dia_err;
6662882Svi117747 		}
667*4702Sgm209912 		/*
668*4702Sgm209912 		 * We take the local contact from the originating request on
669*4702Sgm209912 		 * UAC. For the UAS, we will take it from the response.
670*4702Sgm209912 		 */
671*4702Sgm209912 		if ((dialog->sip_dlg_local_contact = sip_dup_header(chdr)) ==
672*4702Sgm209912 		    NULL) {
673*4702Sgm209912 			goto dia_err;
674*4702Sgm209912 		} else {
675*4702Sgm209912 			dialog->sip_dlg_new_local_contact = NULL;
676*4702Sgm209912 		}
6772882Svi117747 	}
6782882Svi117747 	if ((dialog->sip_dlg_call_id = sip_dup_header(cihdr)) == NULL)
6792882Svi117747 		goto dia_err;
6802882Svi117747 	if (method == SUBSCRIBE) {
6812882Svi117747 		dialog->sip_dlg_event = sip_dup_header(evhdr);
6822882Svi117747 		if (dialog->sip_dlg_event == NULL) {
6832882Svi117747 			goto dia_err;
6842882Svi117747 		}
6852882Svi117747 	}
6862882Svi117747 	dialog->sip_dlg_rset.sip_str_ptr = NULL;
6872882Svi117747 	dialog->sip_dlg_rset.sip_str_len = 0;
6882882Svi117747 	dialog->sip_dlg_req_uri.sip_str_ptr = NULL;
6892882Svi117747 	dialog->sip_dlg_req_uri.sip_str_len = 0;
6902882Svi117747 	/*
6912882Svi117747 	 * Get the route set from the request, if present
6922882Svi117747 	 */
6932882Svi117747 	if (dlg_type == SIP_UAS_DIALOG &&
6942882Svi117747 	    sip_dialog_get_route_set(dialog, sip_msg, dlg_type) != 0) {
6952882Svi117747 		goto dia_err;
6962882Svi117747 	}
6972882Svi117747 	if (dlg_type == SIP_UAC_DIALOG)
6982882Svi117747 		dialog->sip_dlg_local_cseq = cseq;
6992882Svi117747 	else
7002882Svi117747 		dialog->sip_dlg_remote_cseq = cseq;
7012882Svi117747 	dialog->sip_dlg_type = dlg_type;
7022882Svi117747 	dialog->sip_dlg_on_fork = dlg_on_fork;
7032882Svi117747 	dialog->sip_dlg_method = method;
7042882Svi117747 	/*
7052882Svi117747 	 * Set the partial dialog timer with the INVITE timeout val
7062882Svi117747 	 */
7072882Svi117747 	if (sip_conn_timer1 != NULL)
7082882Svi117747 		timer1 = sip_conn_timer1(obj);
7092882Svi117747 	SIP_INIT_TIMER(dialog->sip_dlg_timer, 64 * timer1);
7102882Svi117747 	tim_obj->dialog = dialog;
7112882Svi117747 	/*
7122882Svi117747 	 * Since at the client we never pass the partial dialog, we need not
7132882Svi117747 	 * invoke the callback when the partial dialog self-destructs.
7142882Svi117747 	 */
7152882Svi117747 	if (dlg_type == SIP_UAS_DIALOG)
7162882Svi117747 		tim_obj->func = sip_ulp_dlg_del_cb;
7172882Svi117747 	SIP_SCHED_TIMER(dialog->sip_dlg_timer, (void *)tim_obj,
7182882Svi117747 	    sip_dlg_self_destruct);
7192882Svi117747 	if (!SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
7202882Svi117747 		goto dia_err;
7212882Svi117747 	(void) pthread_mutex_init(&dialog->sip_dlg_mutex, NULL);
7222882Svi117747 
7232882Svi117747 	if (dlg_type == SIP_UAC_DIALOG) {
7242882Svi117747 		const sip_str_t	*local_tag;
7252882Svi117747 
7262882Svi117747 		local_tag = sip_get_from_tag((sip_msg_t)sip_msg, NULL);
7272882Svi117747 		assert(local_tag != NULL);
7282882Svi117747 		sip_md5_hash(local_tag->sip_str_ptr, local_tag->sip_str_len,
7292882Svi117747 		    callid->sip_str_ptr, callid->sip_str_len,
7302882Svi117747 		    NULL, 0, NULL, 0, NULL, 0, NULL, 0,
7312882Svi117747 		    (uchar_t *)dialog->sip_dlg_id);
7322882Svi117747 
7332882Svi117747 
7342882Svi117747 		/*
7352882Svi117747 		 * Add it to the partial hash table
7362882Svi117747 		 */
7372882Svi117747 		if (sip_hash_add(sip_dialog_phash, (void *)dialog,
7382882Svi117747 		    SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) {
7392882Svi117747 			goto dia_err;
7402882Svi117747 		}
7412882Svi117747 	}
7422882Svi117747 	SIP_DLG_REFCNT_INCR(dialog);
7432882Svi117747 	return ((sip_dialog_t)dialog);
7442882Svi117747 dia_err:
7452882Svi117747 	sip_release_dialog_res(dialog);
7462882Svi117747 	if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
7472882Svi117747 		SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
7482882Svi117747 	if (tim_obj != NULL)
7492882Svi117747 		free(tim_obj);
7502882Svi117747 	return (NULL);
7512882Svi117747 }
7522882Svi117747 
7532882Svi117747 /*
7542882Svi117747  * When creating a dialog from a NOTIFY request, we need to get the FROM
7552882Svi117747  * header for the dialog from the TO header of the NOTIFY.
7562882Svi117747  */
7572882Svi117747 _sip_header_t *
7582882Svi117747 sip_dlg_xchg_from_to(sip_msg_t sip_msg, int what)
7592882Svi117747 {
7602882Svi117747 	int			len;
7612882Svi117747 	_sip_header_t		*newhdr;
7622882Svi117747 	int			cnt;
7632882Svi117747 	const struct sip_header	*hdr;
7642882Svi117747 	int			hdrsize;
7652882Svi117747 	int			error;
7662882Svi117747 
7672882Svi117747 	hdr = sip_get_header(sip_msg, what == SIP_DLG_XCHG_FROM ? SIP_FROM :
7682882Svi117747 	    SIP_TO, NULL, &error);
7692882Svi117747 	if (error != 0 || hdr == NULL)
7702882Svi117747 		return (NULL);
7712882Svi117747 	if (sip_parse_goto_values((_sip_header_t *)hdr) != 0)
7722882Svi117747 		return (NULL);
7732882Svi117747 	len = hdr->sip_hdr_end - hdr->sip_hdr_current;
7742882Svi117747 	if (what == SIP_DLG_XCHG_FROM) {
7752882Svi117747 		hdrsize = len + strlen(SIP_TO) + SIP_SPACE_LEN + sizeof (char) +
7762882Svi117747 		    SIP_SPACE_LEN;
7772882Svi117747 	} else {
7782882Svi117747 		hdrsize = len + strlen(SIP_FROM) + SIP_SPACE_LEN +
7792882Svi117747 		    sizeof (char) + SIP_SPACE_LEN;
7802882Svi117747 	}
7812882Svi117747 	newhdr = sip_new_header(hdrsize);
7822882Svi117747 	if (newhdr == NULL)
7832882Svi117747 		return (NULL);
7842882Svi117747 	if (what == SIP_DLG_XCHG_FROM) {
7852882Svi117747 		cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1,
7862882Svi117747 		    "%s %c ", SIP_TO, SIP_HCOLON);
7872882Svi117747 	} else {
7882882Svi117747 		cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1,
7892882Svi117747 		    "%s %c ", SIP_FROM, SIP_HCOLON);
7902882Svi117747 	}
7912882Svi117747 	newhdr->sip_hdr_current += cnt;
7922882Svi117747 	(void) strncpy(newhdr->sip_hdr_current, hdr->sip_hdr_current, len);
7932882Svi117747 	newhdr->sip_hdr_current += len;
7942882Svi117747 	assert(newhdr->sip_hdr_current == newhdr->sip_hdr_end);
7952882Svi117747 	assert(hdr->sip_header_functions != NULL);
7962882Svi117747 
7972882Svi117747 	/*
7982882Svi117747 	 * FROM and TO have common parsing functions
7992882Svi117747 	 */
8002882Svi117747 	newhdr->sip_header_functions = hdr->sip_header_functions;
8012882Svi117747 	newhdr->sip_hdr_current = newhdr->sip_hdr_start;
8022882Svi117747 
8032882Svi117747 	return (newhdr);
8042882Svi117747 }
8052882Svi117747 
8062882Svi117747 /*
8072882Svi117747  * This is the response that completes the dialog that was created
8082882Svi117747  * in sip_seed_dialog().
8092882Svi117747  */
8102882Svi117747 sip_dialog_t
8112882Svi117747 sip_complete_dialog(_sip_msg_t *sip_msg, _sip_dialog_t *dialog)
8122882Svi117747 {
8132882Svi117747 	_sip_header_t		*thdr;
8142882Svi117747 	_sip_header_t		*evhdr = NULL;
8152882Svi117747 	_sip_header_t		*substate = NULL;
8162882Svi117747 	sip_header_t		chdr = NULL;
8172882Svi117747 	int			resp_code;
8182882Svi117747 	const sip_str_t		*ttag;
8192882Svi117747 	const sip_str_t		*remtag;
8202882Svi117747 	const sip_str_t		*callid;
8212882Svi117747 	const struct sip_value 	*val;
8222882Svi117747 	sip_method_t		method;
8232882Svi117747 	int			error = 0;
8242882Svi117747 	int			prev_state;
8252882Svi117747 	boolean_t		alloc_thdr = B_FALSE;
8262882Svi117747 
8272882Svi117747 	if (sip_msg_is_request((sip_msg_t)sip_msg, &error) && error == 0)
8282882Svi117747 		method = sip_get_request_method((sip_msg_t)sip_msg, &error);
8292882Svi117747 	else
8302882Svi117747 		method = sip_get_callseq_method((sip_msg_t)sip_msg, &error);
8312882Svi117747 	if (error != 0 || dialog == NULL ||
8322882Svi117747 	    (sip_msg_is_request((sip_msg_t)sip_msg, &error) &&
8332882Svi117747 	    (dialog->sip_dlg_method == INVITE || method != NOTIFY))) {
8342882Svi117747 		return (NULL);
8352882Svi117747 	}
8362882Svi117747 	if ((dialog->sip_dlg_type == SIP_UAC_DIALOG && method != NOTIFY &&
8372882Svi117747 	    sip_get_callseq_num((sip_msg_t)sip_msg, NULL) !=
8382882Svi117747 	    dialog->sip_dlg_local_cseq) ||
8392882Svi117747 	    (dialog->sip_dlg_type == SIP_UAS_DIALOG && method != NOTIFY &&
8402882Svi117747 	    sip_get_callseq_num((sip_msg_t)sip_msg, NULL) !=
8412882Svi117747 	    dialog->sip_dlg_remote_cseq)) {
8422882Svi117747 		return (NULL);
8432882Svi117747 	}
8442882Svi117747 	if (method == NOTIFY) {
8452882Svi117747 		const sip_str_t	*sstate;
8462882Svi117747 
8472882Svi117747 		thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg,
8482882Svi117747 		    SIP_DLG_XCHG_FROM);
8492882Svi117747 		if (thdr == NULL)
8502882Svi117747 			return (NULL);
8512882Svi117747 		alloc_thdr = B_TRUE;
8522882Svi117747 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
8532882Svi117747 		chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
8542882Svi117747 		if (chdr == NULL) {
8552882Svi117747 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
8562882Svi117747 			sip_free_header(thdr);
8572882Svi117747 			return (NULL);
8582882Svi117747 		}
8592882Svi117747 		evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL);
8602882Svi117747 		if (evhdr == NULL) {
8612882Svi117747 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
8622882Svi117747 			sip_free_header(thdr);
8632882Svi117747 			return (NULL);
8642882Svi117747 		}
8652882Svi117747 		substate = sip_search_for_header(sip_msg,
8662882Svi117747 		    SIP_SUBSCRIPTION_STATE, NULL);
8672882Svi117747 		if (substate == NULL) {
8682882Svi117747 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
8692882Svi117747 			sip_free_header(thdr);
8702882Svi117747 			return (NULL);
8712882Svi117747 		}
8722882Svi117747 		(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
8732882Svi117747 		sstate = sip_get_substate((sip_msg_t)sip_msg, &error);
8742882Svi117747 		if (sstate == NULL || error != 0) {
8752882Svi117747 			sip_free_header(thdr);
8762882Svi117747 			return (NULL);
8772882Svi117747 		}
8782882Svi117747 		if ((sstate->sip_str_len != strlen("pending") &&
8792882Svi117747 		    sstate->sip_str_len != strlen("active")) ||
8802882Svi117747 		    ((sstate->sip_str_len == strlen("pending") &&
8812882Svi117747 		    strncasecmp(sstate->sip_str_ptr, "pending",
8822882Svi117747 		    strlen("pending")) != 0) ||
8832882Svi117747 		    (sstate->sip_str_len == strlen("active") &&
8842882Svi117747 		    strncasecmp(sstate->sip_str_ptr, "active",
8852882Svi117747 		    strlen("active")) != 0))) {
8862882Svi117747 			sip_free_header(thdr);
8872882Svi117747 			return (NULL);
8882882Svi117747 		}
8892882Svi117747 		ttag = sip_get_from_tag((sip_msg_t)sip_msg, NULL);
8902882Svi117747 	} else {
8912882Svi117747 		if (dialog->sip_dlg_type == SIP_UAS_DIALOG) {
8922882Svi117747 			thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg,
8932882Svi117747 			    SIP_DLG_XCHG_TO);
8942882Svi117747 			alloc_thdr = B_TRUE;
8952882Svi117747 		} else {
8962882Svi117747 			(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
8972882Svi117747 			thdr = sip_search_for_header(sip_msg, SIP_TO, NULL);
8982882Svi117747 			if (dialog->sip_dlg_remote_target == NULL) {
8992882Svi117747 				chdr = sip_search_for_header(sip_msg,
9002882Svi117747 				    SIP_CONTACT, NULL);
9012882Svi117747 			}
9022882Svi117747 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
9032882Svi117747 		}
9042882Svi117747 		if (thdr == NULL) {
9052882Svi117747 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
9062882Svi117747 			return (NULL);
9072882Svi117747 		}
9082882Svi117747 		ttag = sip_get_to_tag((sip_msg_t)sip_msg, NULL);
9092882Svi117747 	}
9102882Svi117747 	if (ttag == NULL) {
9112882Svi117747 		if (alloc_thdr)
9122882Svi117747 			sip_free_header(thdr);
9132882Svi117747 		return (NULL);
9142882Svi117747 	}
9152882Svi117747 	prev_state = dialog->sip_dlg_state;
9162882Svi117747 
9172882Svi117747 	if (method == NOTIFY) {
9182882Svi117747 		int			error;
9192882Svi117747 		const sip_str_t		*dlg_id_val = NULL;
9202882Svi117747 		const sip_str_t		*event;
9212882Svi117747 		const sip_str_t		*id_val = NULL;
9222882Svi117747 		sip_header_value_t	ev_val;
9232882Svi117747 		sip_hdr_value_t		*dlg_ev_val = NULL;
9242882Svi117747 
9252882Svi117747 		event = sip_get_event((sip_msg_t)sip_msg, &error);
9262882Svi117747 		if (event == NULL || error != 0) {
9272882Svi117747 			sip_free_header(thdr);
9282882Svi117747 			return (NULL);
9292882Svi117747 		}
9302882Svi117747 		ev_val = (sip_header_value_t)sip_get_header_value(evhdr,
9312882Svi117747 		    &error);
9322882Svi117747 		if (ev_val != NULL)
9332882Svi117747 			id_val = sip_get_param_value(ev_val, "id", &error);
9342882Svi117747 		if (error == 0) {
9352882Svi117747 			dlg_ev_val = (sip_hdr_value_t *)sip_get_header_value(
9362882Svi117747 			    dialog->sip_dlg_event, &error);
9372882Svi117747 		}
9382882Svi117747 		if (dlg_ev_val == NULL || error != 0) {
9392882Svi117747 			sip_free_header(thdr);
9402882Svi117747 			return (NULL);
9412882Svi117747 		}
9422882Svi117747 		dlg_id_val = sip_get_param_value((sip_header_value_t)dlg_ev_val,
9432882Svi117747 		    "id", &error);
9442882Svi117747 		if (error != 0 ||
9452882Svi117747 		    dlg_ev_val->str_val_len != event->sip_str_len ||
9462882Svi117747 		    strncmp(dlg_ev_val->str_val_ptr, event->sip_str_ptr,
9472882Svi117747 		    event->sip_str_len != 0)) {
9482882Svi117747 			sip_free_header(thdr);
9492882Svi117747 			return (NULL);
9502882Svi117747 		}
9512882Svi117747 		if ((dlg_id_val == NULL && id_val != NULL) ||
9522882Svi117747 		    (dlg_id_val != NULL && id_val == NULL)) {
9532882Svi117747 			sip_free_header(thdr);
9542882Svi117747 			return (NULL);
9552882Svi117747 		} else if (dlg_id_val != NULL && id_val != NULL) {
9562882Svi117747 			if (dlg_id_val->sip_str_len != id_val->sip_str_len ||
9572882Svi117747 			    strncasecmp(dlg_id_val->sip_str_ptr,
9582882Svi117747 			    id_val->sip_str_ptr, dlg_id_val->sip_str_len) !=
9592882Svi117747 			    0) {
9602882Svi117747 				sip_free_header(thdr);
9612882Svi117747 				return (NULL);
9622882Svi117747 			}
9632882Svi117747 		}
9642882Svi117747 		if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
9652882Svi117747 			dialog->sip_dlg_remote_uri_tag = thdr;
9662882Svi117747 			if ((dialog->sip_dlg_remote_target =
9672882Svi117747 			    sip_dup_header(chdr)) == NULL) {
9682882Svi117747 				sip_free_header(thdr);
9692882Svi117747 				return (NULL);
9702882Svi117747 			}
9712882Svi117747 		} else {
9722882Svi117747 			dialog->sip_dlg_local_uri_tag = thdr;
9732882Svi117747 		}
9742882Svi117747 		dialog->sip_dlg_state = SIP_DLG_CONFIRMED;
9752882Svi117747 	} else {
9762882Svi117747 		resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
9772882Svi117747 		(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
9782882Svi117747 		assert(dialog->sip_dlg_state == SIP_DLG_NEW);
9792882Svi117747 		if (dialog->sip_dlg_remote_target == NULL && chdr != NULL) {
9802882Svi117747 			assert(dialog->sip_dlg_type == SIP_UAC_DIALOG);
9812882Svi117747 			if ((dialog->sip_dlg_remote_target =
9822882Svi117747 			    sip_dup_header(chdr)) == NULL) {
9832882Svi117747 				(void) pthread_mutex_unlock(
9842882Svi117747 				    &dialog->sip_dlg_mutex);
9852882Svi117747 				if (alloc_thdr)
9862882Svi117747 					sip_free_header(thdr);
9873439Svi117747 				goto terminate_new_dlg;
9882882Svi117747 			}
9892882Svi117747 			if (sip_dialog_get_route_set(dialog, sip_msg,
9902882Svi117747 			    dialog->sip_dlg_type) != 0) {
9912882Svi117747 				(void) pthread_mutex_unlock(
9922882Svi117747 				    &dialog->sip_dlg_mutex);
9932882Svi117747 				if (alloc_thdr)
9942882Svi117747 					sip_free_header(thdr);
9953439Svi117747 				goto terminate_new_dlg;
9962882Svi117747 			}
9972882Svi117747 		}
9982882Svi117747 		if (SIP_PROVISIONAL_RESP(resp_code)) {
9992882Svi117747 			dialog->sip_dlg_state = SIP_DLG_EARLY;
10002882Svi117747 		} else if (SIP_OK_RESP(resp_code)) {
10012882Svi117747 			/*
10022882Svi117747 			 * Per 12.1 the UAS must include the contact header
10032882Svi117747 			 * for a dialog establishing response, so if we
10042882Svi117747 			 * don't find one, we terminate it.
10052882Svi117747 			 */
10062882Svi117747 			if (dialog->sip_dlg_remote_target == NULL) {
10072882Svi117747 				(void) pthread_mutex_unlock(
10082882Svi117747 				    &dialog->sip_dlg_mutex);
10092882Svi117747 				if (sip_ulp_dlg_del_cb != NULL) {
10102882Svi117747 					sip_ulp_dlg_del_cb(dialog,
10112882Svi117747 					    (sip_msg_t)sip_msg, NULL);
10122882Svi117747 				}
10132882Svi117747 				if (alloc_thdr)
10142882Svi117747 					sip_free_header(thdr);
10153439Svi117747 				goto terminate_new_dlg;
10162882Svi117747 			}
10172882Svi117747 			dialog->sip_dlg_state = SIP_DLG_CONFIRMED;
10182882Svi117747 		} else {
10192882Svi117747 			(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
10202882Svi117747 			if (sip_ulp_dlg_del_cb != NULL) {
10212882Svi117747 				sip_ulp_dlg_del_cb(dialog, (sip_msg_t)sip_msg,
10222882Svi117747 				    NULL);
10232882Svi117747 			}
10242882Svi117747 			if (alloc_thdr)
10252882Svi117747 				sip_free_header(thdr);
10263439Svi117747 			goto terminate_new_dlg;
10272882Svi117747 		}
10282882Svi117747 		if (dialog->sip_dlg_type == SIP_UAS_DIALOG) {
10292882Svi117747 			dialog->sip_dlg_local_uri_tag = thdr;
10302882Svi117747 		} else {
10312882Svi117747 			if ((dialog->sip_dlg_remote_uri_tag =
10322882Svi117747 			    sip_dup_header(thdr)) == NULL) {
10332882Svi117747 				(void) pthread_mutex_unlock(
10342882Svi117747 				    &dialog->sip_dlg_mutex);
10353439Svi117747 				goto terminate_new_dlg;
10362882Svi117747 			}
10372882Svi117747 		}
10382882Svi117747 	}
10392882Svi117747 
10402882Svi117747 	/*
1041*4702Sgm209912 	 * We take the local contact for UAS Dialog from the response (either
1042*4702Sgm209912 	 * NOTIFY for SUBSCRIBE request or from final response 2xx to INVITE
1043*4702Sgm209912 	 * request)
1044*4702Sgm209912 	 */
1045*4702Sgm209912 	if ((dialog->sip_dlg_type == SIP_UAS_DIALOG) && (dialog->sip_dlg_state
1046*4702Sgm209912 	    == SIP_DLG_CONFIRMED)) {
1047*4702Sgm209912 		if (chdr == NULL) {
1048*4702Sgm209912 			(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
1049*4702Sgm209912 			chdr = sip_search_for_header(sip_msg, SIP_CONTACT,
1050*4702Sgm209912 			    NULL);
1051*4702Sgm209912 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
1052*4702Sgm209912 		}
1053*4702Sgm209912 		if ((chdr == NULL) || ((dialog->sip_dlg_local_contact =
1054*4702Sgm209912 		    sip_dup_header(chdr)) == NULL)) {
1055*4702Sgm209912 			(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1056*4702Sgm209912 			if (alloc_thdr)
1057*4702Sgm209912 				sip_free_header(thdr);
1058*4702Sgm209912 			goto terminate_new_dlg;
1059*4702Sgm209912 		}
1060*4702Sgm209912 	}
1061*4702Sgm209912 
1062*4702Sgm209912 	/*
10632882Svi117747 	 * Cancel the partial dialog timer
10642882Svi117747 	 */
10652882Svi117747 	if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
10662882Svi117747 		SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
10672882Svi117747 
10682882Svi117747 	if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
10692882Svi117747 		val =  sip_get_header_value(dialog->sip_dlg_local_uri_tag,
10702882Svi117747 		    &error);
10712882Svi117747 	} else {
10722882Svi117747 		val =  sip_get_header_value(dialog->sip_dlg_remote_uri_tag,
10732882Svi117747 		    &error);
10742882Svi117747 	}
10752882Svi117747 	assert(val != NULL && error == 0);
10762882Svi117747 	remtag = sip_get_param_value((sip_header_value_t)val, "tag", &error);
10772882Svi117747 
10782882Svi117747 	val = sip_get_header_value(dialog->sip_dlg_call_id, &error);
10792882Svi117747 	callid = &((sip_hdr_value_t *)val)->str_val;
10802882Svi117747 
10812882Svi117747 	/*
10822882Svi117747 	 * Get an ID for this dialog
10832882Svi117747 	 */
10842882Svi117747 	if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
10852882Svi117747 		sip_md5_hash(remtag->sip_str_ptr, remtag->sip_str_len,
10862882Svi117747 		    ttag->sip_str_ptr, ttag->sip_str_len,
10872882Svi117747 		    callid->sip_str_ptr, callid->sip_str_len,
10882882Svi117747 		    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id);
10892882Svi117747 	} else {
10902882Svi117747 		sip_md5_hash(ttag->sip_str_ptr, ttag->sip_str_len,
10912882Svi117747 		    remtag->sip_str_ptr, remtag->sip_str_len,
10922882Svi117747 		    callid->sip_str_ptr, callid->sip_str_len,
10932882Svi117747 		    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id);
10942882Svi117747 	}
10952882Svi117747 
10962882Svi117747 	SIP_DLG_REFCNT_INCR(dialog);
10972882Svi117747 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
10982882Svi117747 
10992882Svi117747 	/*
11002882Svi117747 	 * Add it to the hash table
11012882Svi117747 	 */
11022882Svi117747 	if (sip_hash_add(sip_dialog_hash, (void *)dialog,
11032882Svi117747 	    SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) {
11043439Svi117747 	terminate_new_dlg:
11052882Svi117747 		/*
11062882Svi117747 		 * So that sip_dialog_delete() does not try to remove
11072882Svi117747 		 * this from the hash table.
11082882Svi117747 		 */
11092882Svi117747 		(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
11102882Svi117747 		if (dialog->sip_dlg_type == SIP_UAS_DIALOG) {
11113439Svi117747 			if (dialog->sip_dlg_local_uri_tag != NULL) {
11123439Svi117747 				sip_free_header(dialog->sip_dlg_local_uri_tag);
11133439Svi117747 				dialog->sip_dlg_local_uri_tag = NULL;
11143439Svi117747 			}
11152882Svi117747 		} else {
11163439Svi117747 			if (dialog->sip_dlg_remote_uri_tag != NULL) {
11173439Svi117747 				sip_free_header(dialog->sip_dlg_remote_uri_tag);
11183439Svi117747 				dialog->sip_dlg_remote_uri_tag = NULL;
11193439Svi117747 			}
11202882Svi117747 		}
11212882Svi117747 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
11222882Svi117747 		sip_dialog_terminate(dialog, (sip_msg_t)sip_msg);
11232882Svi117747 		return (NULL);
11242882Svi117747 	}
11252882Svi117747 	if (sip_dlg_ulp_state_cb != NULL) {
11262882Svi117747 		sip_dlg_ulp_state_cb((sip_dialog_t)dialog,
11272882Svi117747 		    (sip_msg_t)sip_msg, prev_state, dialog->sip_dlg_state);
11282882Svi117747 	}
11292882Svi117747 	return ((sip_dialog_t)dialog);
11302882Svi117747 }
11312882Svi117747 
11322882Svi117747 /*
11332882Svi117747  * Check if this dialog is a match.
11342882Svi117747  */
11352882Svi117747 boolean_t
11362882Svi117747 sip_dialog_match(void *obj, void *hindex)
11372882Svi117747 {
11382882Svi117747 	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
11392882Svi117747 
11402882Svi117747 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
11412882Svi117747 	if (dialog->sip_dlg_state == SIP_DLG_DESTROYED) {
11422882Svi117747 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
11432882Svi117747 		return (B_FALSE);
11442882Svi117747 	}
11452882Svi117747 	if (bcmp(dialog->sip_dlg_id, hindex,
11462882Svi117747 	    sizeof (dialog->sip_dlg_id)) == 0) {
11472882Svi117747 		SIP_DLG_REFCNT_INCR(dialog);
11482882Svi117747 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
11492882Svi117747 		return (B_TRUE);
11502882Svi117747 	}
11512882Svi117747 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
11522882Svi117747 	return (B_FALSE);
11532882Svi117747 }
11542882Svi117747 
11552882Svi117747 /*
11562882Svi117747  * Don't delete, just take it out of the hash
11572882Svi117747  */
11582882Svi117747 boolean_t
11592882Svi117747 sip_dialog_dontfree(void *obj, void *hindex, int *found)
11602882Svi117747 {
11612882Svi117747 	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
11622882Svi117747 
11632882Svi117747 	*found = 0;
11642882Svi117747 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
11652882Svi117747 	if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id))
11662882Svi117747 	    == 0) {
11672882Svi117747 		*found = 1;
11682882Svi117747 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
11692882Svi117747 		return (B_TRUE);
11702882Svi117747 	}
11712882Svi117747 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
11722882Svi117747 	return (B_FALSE);
11732882Svi117747 }
11742882Svi117747 
11752882Svi117747 /*
11762882Svi117747  * Free resources associated with the dialog, the object will be removed
11772882Svi117747  * from the hash list by sip_hash_delete.
11782882Svi117747  */
11792882Svi117747 boolean_t
11802882Svi117747 sip_dialog_free(void *obj, void *hindex, int *found)
11812882Svi117747 {
11822882Svi117747 	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
11832882Svi117747 
11842882Svi117747 	*found = 0;
11852882Svi117747 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
11862882Svi117747 	if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id))
11872882Svi117747 	    == 0) {
11882882Svi117747 		*found = 1;
11892882Svi117747 		assert(dialog->sip_dlg_state == SIP_DLG_DESTROYED);
11902882Svi117747 		if (dialog->sip_dlg_ref_cnt != 0) {
11912882Svi117747 			(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
11922882Svi117747 			return (B_FALSE);
11932882Svi117747 		}
11942882Svi117747 		sip_release_dialog_res(dialog);
11952882Svi117747 		return (B_TRUE);
11962882Svi117747 	}
11972882Svi117747 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
11982882Svi117747 	return (B_FALSE);
11992882Svi117747 }
12002882Svi117747 
12012882Svi117747 /*
12022882Svi117747  * The UAS will receive the request from the transaction layer.  If the
12032882Svi117747  * request has a tag in the To header field, the UAS core computes the
12042882Svi117747  * dialog identifier corresponding to the request and compares it with
12052882Svi117747  * existing dialogs.  If there is a match, this is a mid-dialog request.
12062882Svi117747  */
12072882Svi117747 sip_dialog_t
12082882Svi117747 sip_dialog_find(_sip_msg_t *sip_msg)
12092882Svi117747 {
12102882Svi117747 	const sip_str_t	*localtag;
12112882Svi117747 	const sip_str_t	*remtag;
12122882Svi117747 	const sip_str_t	*callid;
12132882Svi117747 	uint16_t	digest[8];
12142882Svi117747 	_sip_dialog_t	*dialog;
12152882Svi117747 	boolean_t	is_request;
12162882Svi117747 	int		error;
12172882Svi117747 
12182882Svi117747 	is_request = sip_msg_is_request((sip_msg_t)sip_msg, &error);
12192882Svi117747 	if (error != 0)
12202882Svi117747 		return (NULL);
12212882Svi117747 	if (is_request) {
12222882Svi117747 		localtag = sip_get_to_tag((sip_msg_t)sip_msg, &error);
12232882Svi117747 		if (error == 0)
12242882Svi117747 			remtag = sip_get_from_tag((sip_msg_t)sip_msg, &error);
12252882Svi117747 	} else {
12262882Svi117747 		remtag = sip_get_to_tag((sip_msg_t)sip_msg, &error);
12272882Svi117747 		if (error == 0)
12282882Svi117747 			localtag = sip_get_from_tag((sip_msg_t)sip_msg, &error);
12292882Svi117747 	}
12302882Svi117747 	if (error != 0)
12312882Svi117747 		return (NULL);
12322882Svi117747 	callid = sip_get_callid((sip_msg_t)sip_msg, &error);
12332882Svi117747 	if (error != 0 || remtag == NULL || localtag == NULL ||
12342882Svi117747 	    callid == NULL) {
12352882Svi117747 		return (NULL);
12362882Svi117747 	}
12372882Svi117747 	sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len,
12382882Svi117747 	    remtag->sip_str_ptr, remtag->sip_str_len,
12392882Svi117747 	    callid->sip_str_ptr, callid->sip_str_len,
12402882Svi117747 	    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest);
12412882Svi117747 
12422882Svi117747 	dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_hash,
12432882Svi117747 	    (void *)digest, SIP_DIGEST_TO_HASH(digest), sip_dialog_match);
12442882Svi117747 	if (dialog == NULL) {
12452882Svi117747 		sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len,
12462882Svi117747 		    NULL, 0, callid->sip_str_ptr, callid->sip_str_len,
12472882Svi117747 		    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest);
12482882Svi117747 		dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_phash,
12492882Svi117747 		    (void *)digest, SIP_DIGEST_TO_HASH(digest),
12502882Svi117747 		    sip_dialog_match);
12512882Svi117747 	}
12522882Svi117747 	return ((sip_dialog_t)dialog);
12532882Svi117747 }
12542882Svi117747 
12552882Svi117747 /*
12562882Svi117747  * We keep this partial dialog for the duration of the INVITE
12572882Svi117747  * transaction timeout duration, i.e. Timer B.
12582882Svi117747  */
12592882Svi117747 void
12602882Svi117747 sip_dlg_self_destruct(void *args)
12612882Svi117747 {
12622882Svi117747 	sip_dialog_timer_obj_t	*tim_obj = (sip_dialog_timer_obj_t *)args;
12632882Svi117747 	_sip_dialog_t		*dialog = (_sip_dialog_t *)tim_obj->dialog;
12642882Svi117747 	int			index;
12652882Svi117747 
12662882Svi117747 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
12672882Svi117747 	assert(dialog->sip_dlg_state == SIP_DLG_NEW);
12682882Svi117747 	dialog->sip_dlg_state = SIP_DLG_DESTROYED;
12692882Svi117747 	if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
12702882Svi117747 		index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id);
12712882Svi117747 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
12722882Svi117747 		sip_hash_delete(sip_dialog_phash, (void *)dialog->sip_dlg_id,
12732882Svi117747 		    index, sip_dialog_dontfree);
12742882Svi117747 	} else {
12752882Svi117747 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
12762882Svi117747 	}
12772882Svi117747 	if (tim_obj->func != NULL)
12782882Svi117747 		tim_obj->func(dialog, NULL, NULL);
12792882Svi117747 	free(tim_obj);
12802882Svi117747 	SIP_DLG_REFCNT_DECR(dialog);
12812882Svi117747 }
12822882Svi117747 
12832882Svi117747 /*
12842882Svi117747  * Terminate a dialog
12852882Svi117747  */
12862882Svi117747 void
12872882Svi117747 sip_dialog_terminate(_sip_dialog_t *dialog, sip_msg_t sip_msg)
12882882Svi117747 {
12892882Svi117747 	int	prev_state;
12902882Svi117747 
12912882Svi117747 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
12922882Svi117747 	prev_state = dialog->sip_dlg_state;
12932882Svi117747 	dialog->sip_dlg_state = SIP_DLG_DESTROYED;
12942882Svi117747 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
12952882Svi117747 	if (sip_dlg_ulp_state_cb != NULL) {
12962882Svi117747 		sip_dlg_ulp_state_cb((sip_dialog_t)dialog, sip_msg, prev_state,
12972882Svi117747 		    dialog->sip_dlg_state);
12982882Svi117747 	}
12992882Svi117747 	SIP_DLG_REFCNT_DECR(dialog);
13002882Svi117747 }
13012882Svi117747 
13022882Svi117747 /*
13032882Svi117747  * Delete a dialog
13042882Svi117747  */
13052882Svi117747 void
13062882Svi117747 sip_dialog_delete(_sip_dialog_t *dialog)
13072882Svi117747 {
13082882Svi117747 	int	index;
13092882Svi117747 
13102882Svi117747 	/*
13112882Svi117747 	 * partial dialog, not in the hash table
13122882Svi117747 	 */
13132882Svi117747 	if (dialog->sip_dlg_local_uri_tag == NULL ||
13142882Svi117747 	    dialog->sip_dlg_remote_uri_tag == NULL) {
13152882Svi117747 		/*
13162882Svi117747 		 * Cancel the partial dialog timer
13172882Svi117747 		 */
13182882Svi117747 		if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
13192882Svi117747 			SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
13202882Svi117747 		sip_release_dialog_res(dialog);
13212882Svi117747 		return;
13222882Svi117747 	}
13232882Svi117747 	index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id);
13242882Svi117747 	sip_hash_delete(sip_dialog_hash, (void *)dialog->sip_dlg_id, index,
13252882Svi117747 	    sip_dialog_free);
13262882Svi117747 }
13272882Svi117747 
13282882Svi117747 /*
13292882Svi117747  * Get the remote target from the CONTACT header from the 200 OK response
13302882Svi117747  */
13312882Svi117747 static boolean_t
13322882Svi117747 sip_get_rtarg(_sip_dialog_t *dialog, _sip_msg_t *sip_msg)
13332882Svi117747 {
13342882Svi117747 	sip_header_t	chdr;
13352882Svi117747 
13362882Svi117747 	if (dialog->sip_dlg_remote_target != NULL)
13372882Svi117747 		return (B_TRUE);
13382882Svi117747 
13392882Svi117747 	(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
13402882Svi117747 	chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
13412882Svi117747 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
13422882Svi117747 	if (chdr == NULL)
13432882Svi117747 		return (B_FALSE);
13442882Svi117747 	if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) == NULL)
13452882Svi117747 		return (B_FALSE);
13462882Svi117747 
13472882Svi117747 	return (B_TRUE);
13482882Svi117747 }
13492882Svi117747 
13502882Svi117747 /*
13512882Svi117747  * Process an incoming request/response
13522882Svi117747  */
13532882Svi117747 /* ARGSUSED */
13542882Svi117747 int
13552882Svi117747 sip_dialog_process(_sip_msg_t *sip_msg, sip_dialog_t *sip_dialog)
13562882Svi117747 {
13572882Svi117747 	boolean_t	request;
13582882Svi117747 	_sip_dialog_t	*_dialog;
13592882Svi117747 	int		error;
13602882Svi117747 
13612882Svi117747 	request = sip_msg_is_request((sip_msg_t)sip_msg, &error);
13622882Svi117747 	if (error != 0)
13632882Svi117747 		return (EINVAL);
13642882Svi117747 	_dialog = (_sip_dialog_t *)*sip_dialog;
13652882Svi117747 	if (request) {
13662882Svi117747 		uint32_t	cseq;
13672882Svi117747 		sip_method_t	method;
13682882Svi117747 
13692882Svi117747 		cseq = sip_get_callseq_num((sip_msg_t)sip_msg, &error);
13702882Svi117747 		if (error != 0)
13712882Svi117747 			return (EINVAL);
13722882Svi117747 		method = sip_get_callseq_method((sip_msg_t)sip_msg, &error);
13732882Svi117747 		if (error != 0)
13742882Svi117747 			return (EINVAL);
13752882Svi117747 		if (sip_get_request_method((sip_msg_t)sip_msg, &error) !=
13762882Svi117747 		    method) {
13772882Svi117747 			return (EINVAL);
13782882Svi117747 		}
13792882Svi117747 		(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
13802882Svi117747 		/*
13812882Svi117747 		 * Requests that do not change in any way the state
13822882Svi117747 		 * of a dialog may be received within a dialog.
13832882Svi117747 		 * They are processed as if they had been received
13842882Svi117747 		 * outside the dialog.
13852882Svi117747 		 * For dialogs that have been established with an
13862882Svi117747 		 * INVITE, the only target refresh request defined is
13872882Svi117747 		 * re-INVITE.
13882882Svi117747 		 */
13892882Svi117747 		if (_dialog->sip_dlg_method == INVITE &&
13902882Svi117747 		    method == INVITE && _dialog->sip_dlg_remote_cseq != 0 &&
13912882Svi117747 		    SIP_CSEQ_LT(cseq, _dialog->sip_dlg_remote_cseq)) {
13922882Svi117747 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
13932882Svi117747 			return (EPROTO);
13942882Svi117747 		}
13952882Svi117747 		/*
13962882Svi117747 		 * Target-Refresh request
13972882Svi117747 		 */
13982882Svi117747 		if (_dialog->sip_dlg_method == INVITE && method == INVITE) {
13992882Svi117747 			sip_header_t	chdr;
14002882Svi117747 			sip_header_t	nchdr;
14012882Svi117747 
14022882Svi117747 			(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
14032882Svi117747 			chdr = sip_search_for_header(sip_msg, SIP_CONTACT,
14042882Svi117747 			    NULL);
14052882Svi117747 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
14062882Svi117747 			if (chdr != NULL &&
14072882Svi117747 			    (nchdr = sip_dup_header(chdr)) != NULL) {
14082882Svi117747 				if (_dialog->sip_dlg_remote_target != NULL) {
14092882Svi117747 					sip_free_header(
14102882Svi117747 					    _dialog->sip_dlg_remote_target);
14112882Svi117747 				}
14122882Svi117747 				_dialog->sip_dlg_remote_target = nchdr;
14132882Svi117747 			}
14142882Svi117747 		}
14152882Svi117747 		_dialog->sip_dlg_remote_cseq = cseq;
14162882Svi117747 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
14172882Svi117747 	} else {
14182882Svi117747 		int		resp_code;
14192882Svi117747 		sip_method_t	method;
14202882Svi117747 		int		error;
14212882Svi117747 
14222882Svi117747 		resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
14232882Svi117747 		if (error == 0) {
14242882Svi117747 			method = sip_get_callseq_method((sip_msg_t)sip_msg,
14252882Svi117747 			    &error);
14262882Svi117747 		}
14272882Svi117747 		if (error != 0)
14282882Svi117747 			return (error);
14292882Svi117747 
14302882Svi117747 		(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
14314641Sgm209912 		if (_dialog->sip_dlg_state == SIP_DLG_DESTROYED) {
14324641Sgm209912 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
14334641Sgm209912 			return (0);
14344641Sgm209912 		}
14352882Svi117747 		assert(_dialog->sip_dlg_state == SIP_DLG_EARLY ||
14362882Svi117747 		    _dialog->sip_dlg_state == SIP_DLG_CONFIRMED);
14372882Svi117747 		/*
14382882Svi117747 		 * Let the user delete the dialog if it is not a 1XX/2XX resp
14392882Svi117747 		 * for an early INVITE dialog.
14402882Svi117747 		 */
14412882Svi117747 		if (SIP_OK_RESP(resp_code)) {
14422882Svi117747 			if (method == INVITE) {
14432882Svi117747 				if (!sip_get_rtarg(_dialog, sip_msg)) {
14442882Svi117747 					(void) pthread_mutex_unlock(
14452882Svi117747 					    &_dialog->sip_dlg_mutex);
14462882Svi117747 					if (sip_ulp_dlg_del_cb != NULL) {
14472882Svi117747 						sip_ulp_dlg_del_cb(
14482882Svi117747 						    (sip_dialog_t)_dialog,
14492882Svi117747 						    (sip_msg_t)sip_msg, NULL);
14502882Svi117747 					}
14512882Svi117747 					sip_dialog_terminate(_dialog,
14522882Svi117747 					    (sip_msg_t)sip_msg);
14532882Svi117747 					return (0);
14542882Svi117747 				}
14552882Svi117747 				if (_dialog->sip_dlg_state == SIP_DLG_EARLY) {
14562882Svi117747 					_dialog->sip_dlg_state =
14572882Svi117747 					    SIP_DLG_CONFIRMED;
14582882Svi117747 					(void) pthread_mutex_unlock(
14592882Svi117747 					    &_dialog->sip_dlg_mutex);
14602882Svi117747 					(void) sip_dlg_recompute_rset(_dialog,
14612882Svi117747 					    sip_msg, SIP_UAC_DIALOG);
14622882Svi117747 					if (sip_dlg_ulp_state_cb != NULL) {
14632882Svi117747 						sip_dlg_ulp_state_cb(
14642882Svi117747 						    (sip_dialog_t)_dialog,
14652882Svi117747 						    sip_msg, SIP_DLG_EARLY,
14662882Svi117747 						    _dialog->sip_dlg_state);
14672882Svi117747 					}
14682882Svi117747 					return (0);
1469*4702Sgm209912 				} else if (_dialog->sip_dlg_new_local_contact
1470*4702Sgm209912 				    != NULL) {
1471*4702Sgm209912 					assert(_dialog->sip_dlg_local_contact
1472*4702Sgm209912 					    != NULL);
1473*4702Sgm209912 					sip_free_header(_dialog->
1474*4702Sgm209912 						    sip_dlg_local_contact);
1475*4702Sgm209912 					_dialog->sip_dlg_local_contact =
1476*4702Sgm209912 					    _dialog->sip_dlg_new_local_contact;
1477*4702Sgm209912 					_dialog->sip_dlg_new_local_contact =
1478*4702Sgm209912 					    NULL;
14792882Svi117747 				}
14802882Svi117747 			}
14812882Svi117747 		}
14822882Svi117747 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
14832882Svi117747 	}
14842882Svi117747 	return (0);
14852882Svi117747 }
14862882Svi117747 
14872882Svi117747 /*
14882882Svi117747  * Copy partial dialog to create a complete dialog
14892882Svi117747  */
14902882Svi117747 _sip_dialog_t *
14912882Svi117747 sip_copy_partial_dialog(_sip_dialog_t *dialog)
14922882Svi117747 {
14932882Svi117747 	_sip_dialog_t	*new_dlg;
14942882Svi117747 
14952882Svi117747 	new_dlg =  calloc(1, sizeof (_sip_dialog_t));
14962882Svi117747 	if (new_dlg == NULL)
14972882Svi117747 		return (NULL);
14982882Svi117747 	if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) {
14992882Svi117747 		new_dlg->sip_dlg_req_uri.sip_str_ptr =
15002882Svi117747 		    malloc(dialog->sip_dlg_req_uri.sip_str_len + 1);
15012882Svi117747 		if (new_dlg->sip_dlg_req_uri.sip_str_ptr == NULL) {
15022882Svi117747 			free(new_dlg);
15032882Svi117747 			return (NULL);
15042882Svi117747 		}
15052882Svi117747 		(void) strncpy(new_dlg->sip_dlg_req_uri.sip_str_ptr,
15062882Svi117747 		    dialog->sip_dlg_req_uri.sip_str_ptr,
15072882Svi117747 		    dialog->sip_dlg_req_uri.sip_str_len);
15082882Svi117747 		new_dlg->sip_dlg_req_uri.sip_str_ptr[
15092882Svi117747 		    dialog->sip_dlg_req_uri.sip_str_len] = '\0';
15102882Svi117747 		new_dlg->sip_dlg_req_uri.sip_str_len =
15112882Svi117747 		    dialog->sip_dlg_req_uri.sip_str_len;
15122882Svi117747 	}
15132882Svi117747 	if (dialog->sip_dlg_route_set != NULL) {
15142882Svi117747 		assert(dialog->sip_dlg_rset.sip_str_ptr != NULL);
15152882Svi117747 		new_dlg->sip_dlg_rset.sip_str_ptr =
15162882Svi117747 		    malloc(dialog->sip_dlg_rset.sip_str_len + 1);
15172882Svi117747 		if (new_dlg->sip_dlg_rset.sip_str_ptr == NULL) {
15182882Svi117747 			if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL)
15192882Svi117747 				free(new_dlg->sip_dlg_req_uri.sip_str_ptr);
15202882Svi117747 			free(new_dlg);
15212882Svi117747 			return (NULL);
15222882Svi117747 		}
15232882Svi117747 		(void) strncpy(new_dlg->sip_dlg_rset.sip_str_ptr,
15242882Svi117747 		    dialog->sip_dlg_rset.sip_str_ptr,
15252882Svi117747 		    dialog->sip_dlg_rset.sip_str_len);
15262882Svi117747 		new_dlg->sip_dlg_rset.sip_str_ptr[
15272882Svi117747 		    dialog->sip_dlg_rset.sip_str_len] = '\0';
15282882Svi117747 		new_dlg->sip_dlg_rset.sip_str_len =
15292882Svi117747 		    dialog->sip_dlg_rset.sip_str_len;
15302882Svi117747 
15312882Svi117747 		new_dlg->sip_dlg_route_set =
15322882Svi117747 		    sip_dup_header(dialog->sip_dlg_route_set);
15332882Svi117747 		if (new_dlg->sip_dlg_route_set == NULL) {
15342882Svi117747 			free(new_dlg->sip_dlg_rset.sip_str_ptr);
15352882Svi117747 			if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL)
15362882Svi117747 				free(new_dlg->sip_dlg_req_uri.sip_str_ptr);
15372882Svi117747 			free(new_dlg);
15382882Svi117747 			return (NULL);
15392882Svi117747 		}
15402882Svi117747 	}
15412882Svi117747 	if ((new_dlg->sip_dlg_local_uri_tag =
15422882Svi117747 	    sip_dup_header(dialog->sip_dlg_local_uri_tag)) == NULL ||
15432882Svi117747 	    (new_dlg->sip_dlg_remote_target =
15442882Svi117747 	    sip_dup_header(dialog->sip_dlg_remote_target)) == NULL ||
1545*4702Sgm209912 	    (new_dlg->sip_dlg_local_contact =
1546*4702Sgm209912 	    sip_dup_header(dialog->sip_dlg_local_contact)) == NULL ||
15472882Svi117747 	    (new_dlg->sip_dlg_call_id =
15482882Svi117747 	    sip_dup_header(dialog->sip_dlg_call_id)) == NULL) {
15492882Svi117747 		sip_release_dialog_res(new_dlg);
15502882Svi117747 		return (NULL);
15512882Svi117747 	}
15522882Svi117747 	if (dialog->sip_dlg_event != NULL) {
15532882Svi117747 		new_dlg->sip_dlg_event = sip_dup_header(dialog->sip_dlg_event);
15542882Svi117747 		if (new_dlg->sip_dlg_event == NULL) {
15552882Svi117747 			sip_release_dialog_res(new_dlg);
15562882Svi117747 			return (NULL);
15572882Svi117747 		}
15582882Svi117747 	}
15592882Svi117747 	new_dlg->sip_dlg_local_cseq = dialog->sip_dlg_local_cseq;
15602882Svi117747 	new_dlg->sip_dlg_type = dialog->sip_dlg_type;
15612882Svi117747 	new_dlg->sip_dlg_on_fork = B_FALSE;
15622882Svi117747 	(void) pthread_mutex_init(&new_dlg->sip_dlg_mutex, NULL);
15632882Svi117747 
15642882Svi117747 	return (new_dlg);
15652882Svi117747 }
15662882Svi117747 
15672882Svi117747 /*
15682882Svi117747  * Update the dialog using the response
15692882Svi117747  */
15702882Svi117747 sip_dialog_t
15712882Svi117747 sip_update_dialog(sip_dialog_t dialog, _sip_msg_t *sip_msg)
15722882Svi117747 {
15732882Svi117747 	_sip_dialog_t	*_dialog;
15742882Svi117747 	boolean_t	isreq;
15752882Svi117747 	sip_method_t	method;
15762882Svi117747 	int		resp_code = 0;
15772882Svi117747 	int		prev_state;
15782882Svi117747 	boolean_t	decr_ref = B_FALSE;
15792882Svi117747 	int		error;
15802882Svi117747 
15812882Svi117747 	isreq = sip_msg_is_request((sip_msg_t)sip_msg, &error);
15822882Svi117747 	if (error != 0)
15832882Svi117747 		return (dialog);
15842882Svi117747 	_dialog = (_sip_dialog_t *)dialog;
15852882Svi117747 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
15862882Svi117747 	if (isreq) {
15872882Svi117747 		method = sip_get_request_method((sip_msg_t)sip_msg, &error);
15882882Svi117747 		if (error != 0 || _dialog->sip_dlg_method != SUBSCRIBE ||
15892882Svi117747 		    method != NOTIFY) {
15902882Svi117747 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
15912882Svi117747 			return (dialog);
15922882Svi117747 		}
15932882Svi117747 	} else {
15942882Svi117747 		resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
15952882Svi117747 		if (error != 0) {
15962882Svi117747 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
15972882Svi117747 			return (dialog);
15982882Svi117747 		}
1599*4702Sgm209912 		method = sip_get_callseq_method((sip_msg_t)sip_msg, &error);
1600*4702Sgm209912 		if (error != 0) {
1601*4702Sgm209912 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
1602*4702Sgm209912 			return (dialog);
1603*4702Sgm209912 		}
16042882Svi117747 	}
16052882Svi117747 	prev_state = _dialog->sip_dlg_state;
16062882Svi117747 	if (_dialog->sip_dlg_state == SIP_DLG_CONFIRMED) {
16072882Svi117747 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
16082882Svi117747 	} else if (_dialog->sip_dlg_state == SIP_DLG_EARLY) {
16092882Svi117747 		/*
16102882Svi117747 		 * Let the user delete the dialog if it is not a 1XX/2XX resp
16112882Svi117747 		 * for an early dialog.
16122882Svi117747 		 */
16132882Svi117747 		assert(!isreq);
16142882Svi117747 		if (SIP_OK_RESP(resp_code)) {
16152882Svi117747 			_dialog->sip_dlg_state = SIP_DLG_CONFIRMED;
1616*4702Sgm209912 			/*
1617*4702Sgm209912 			 * If we recieved provisional response before we would
1618*4702Sgm209912 			 * not have captured local contact. So store it now.
1619*4702Sgm209912 			 */
1620*4702Sgm209912 			if (_dialog->sip_dlg_type == SIP_UAS_DIALOG && _dialog->
1621*4702Sgm209912 			    sip_dlg_method == INVITE && method == INVITE) {
1622*4702Sgm209912 				sip_header_t chdr;
1623*4702Sgm209912 				(void) pthread_mutex_lock(&sip_msg->
1624*4702Sgm209912 				    sip_msg_mutex);
1625*4702Sgm209912 				chdr = sip_search_for_header(sip_msg,
1626*4702Sgm209912 				    SIP_CONTACT, NULL);
1627*4702Sgm209912 				(void) pthread_mutex_unlock(&sip_msg->
1628*4702Sgm209912 				    sip_msg_mutex);
1629*4702Sgm209912 				if (chdr != NULL) {
1630*4702Sgm209912 					_dialog->sip_dlg_local_contact
1631*4702Sgm209912 					    = sip_dup_header(chdr);
1632*4702Sgm209912 					_dialog->sip_dlg_new_local_contact =
1633*4702Sgm209912 					    NULL;
1634*4702Sgm209912 				}
1635*4702Sgm209912 			}
16362882Svi117747 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
16372882Svi117747 			(void) sip_dlg_recompute_rset(_dialog, sip_msg,
16382882Svi117747 			    SIP_UAS_DIALOG);
16392882Svi117747 			if (sip_dlg_ulp_state_cb != NULL) {
16402882Svi117747 				sip_dlg_ulp_state_cb(dialog, (sip_msg_t)sip_msg,
16412882Svi117747 				    prev_state, dialog->sip_dlg_state);
16422882Svi117747 			}
16432882Svi117747 		} else {
16442882Svi117747 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
16452882Svi117747 		}
16462882Svi117747 	} else if (_dialog->sip_dlg_state == SIP_DLG_NEW) {
16472882Svi117747 		if (!isreq && _dialog->sip_dlg_method == SUBSCRIBE &&
16482882Svi117747 		    SIP_PROVISIONAL_RESP(resp_code)) {
16492882Svi117747 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
16502882Svi117747 			return (dialog);
16512882Svi117747 		}
16522882Svi117747 		if (_dialog->sip_dlg_type == SIP_UAC_DIALOG) {
16532882Svi117747 			_sip_dialog_t	*new_dlg;
16542882Svi117747 
16552882Svi117747 			if (_dialog->sip_dlg_on_fork) {
16562882Svi117747 				new_dlg = sip_copy_partial_dialog(_dialog);
16572882Svi117747 				if (new_dlg == NULL) {
16582882Svi117747 					(void) pthread_mutex_unlock(
16592882Svi117747 					    &_dialog->sip_dlg_mutex);
16602882Svi117747 					return (dialog);
16612882Svi117747 				}
16622882Svi117747 				/*
16632882Svi117747 				 * This decr/incr dance is because the caller
16642882Svi117747 				 * has incremented the ref on the partial
16652882Svi117747 				 * dialog, we release it here and incr the
16662882Svi117747 				 * ref on the new dialog which will be
16672882Svi117747 				 * released by the caller.
16682882Svi117747 				 */
16692882Svi117747 				(void) pthread_mutex_unlock(
16702882Svi117747 				    &_dialog->sip_dlg_mutex);
16712882Svi117747 				SIP_DLG_REFCNT_DECR(_dialog);
16722882Svi117747 				_dialog = new_dlg;
16732882Svi117747 				(void) pthread_mutex_lock(
16742882Svi117747 				    &_dialog->sip_dlg_mutex);
16752882Svi117747 				SIP_DLG_REFCNT_INCR(_dialog);
16762882Svi117747 			} else {
16772882Svi117747 				int	index;
16782882Svi117747 
16792882Svi117747 				/*
16802882Svi117747 				 * take it out of the list so that further
16812882Svi117747 				 * responses will not result in a dialog.
16822882Svi117747 				 * We will have an extra refcount when we
16832882Svi117747 				 * come back from sip_complete_dialog(), i.e.
16842882Svi117747 				 * one when the partial dialog was created -
16852882Svi117747 				 * in sip_seed_dialog(), one held by the caller
16862882Svi117747 				 * and one that will be added by
16872882Svi117747 				 * sip_complete_dialog(). We need to release
16882882Svi117747 				 * the one added by the sip_seed_dialog(),
16892882Svi117747 				 * since the one in sip_complete_dialog()
16902882Svi117747 				 * is for the same purpose.
16912882Svi117747 				 */
16922882Svi117747 				if (SIP_IS_TIMER_RUNNING(
16932882Svi117747 				    _dialog->sip_dlg_timer)) {
16942882Svi117747 					SIP_CANCEL_TIMER(
16952882Svi117747 					    _dialog->sip_dlg_timer);
16962882Svi117747 				}
16972882Svi117747 				index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id);
16982882Svi117747 				(void) pthread_mutex_unlock(
16992882Svi117747 				    &_dialog->sip_dlg_mutex);
17002882Svi117747 				sip_hash_delete(sip_dialog_phash,
17012882Svi117747 				    (void *)_dialog->sip_dlg_id,
17022882Svi117747 				    index, sip_dialog_dontfree);
17032882Svi117747 				(void) pthread_mutex_lock(
17042882Svi117747 				    &_dialog->sip_dlg_mutex);
17052882Svi117747 				decr_ref = B_TRUE;
17062882Svi117747 			}
17072882Svi117747 		} else {
17082882Svi117747 			decr_ref = B_TRUE;
17092882Svi117747 		}
17102882Svi117747 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
17112882Svi117747 		if ((dialog = sip_complete_dialog(sip_msg, _dialog)) ==
17122882Svi117747 		    NULL) {
17133439Svi117747 			if (_dialog->sip_dlg_type == SIP_UAC_DIALOG && decr_ref)
17143439Svi117747 				SIP_DLG_REFCNT_DECR(_dialog);
17152882Svi117747 			return (NULL);
17162882Svi117747 		}
17172882Svi117747 		if (decr_ref)
17182882Svi117747 			SIP_DLG_REFCNT_DECR(_dialog);
17192882Svi117747 	} else {
17202882Svi117747 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
17212882Svi117747 	}
17222882Svi117747 	return (dialog);
17232882Svi117747 }
17242882Svi117747 
17252882Svi117747 /*
17262882Svi117747  * Initialize the hash table
17272882Svi117747  */
17282882Svi117747 void
17292882Svi117747 sip_dialog_init(void (*ulp_dlg_del) (sip_dialog_t, sip_msg_t, void *),
17302882Svi117747     void (*ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int))
17312882Svi117747 {
17322882Svi117747 	int	cnt;
17332882Svi117747 
17342882Svi117747 	for (cnt = 0; cnt < SIP_HASH_SZ; cnt++) {
17352882Svi117747 		sip_dialog_hash[cnt].hash_count = 0;
17362882Svi117747 		sip_dialog_hash[cnt].hash_head = NULL;
17372882Svi117747 		sip_dialog_hash[cnt].hash_tail = NULL;
17382882Svi117747 		(void) pthread_mutex_init(
17392882Svi117747 		    &sip_dialog_hash[cnt].sip_hash_mutex, NULL);
17402882Svi117747 		sip_dialog_phash[cnt].hash_count = 0;
17412882Svi117747 		sip_dialog_phash[cnt].hash_head = NULL;
17422882Svi117747 		sip_dialog_phash[cnt].hash_tail = NULL;
17432882Svi117747 		(void) pthread_mutex_init(
17442882Svi117747 		    &sip_dialog_phash[cnt].sip_hash_mutex, NULL);
17452882Svi117747 	}
17462882Svi117747 	if (ulp_dlg_del != NULL)
17472882Svi117747 		sip_ulp_dlg_del_cb = ulp_dlg_del;
17482882Svi117747 
17492882Svi117747 	if (ulp_state_cb != NULL)
17502882Svi117747 		sip_dlg_ulp_state_cb = ulp_state_cb;
17512882Svi117747 }
1752*4702Sgm209912 
1753*4702Sgm209912 /*
1754*4702Sgm209912  * Copy the new contact header of re-INVITE
1755*4702Sgm209912  */
1756*4702Sgm209912 void
1757*4702Sgm209912 sip_dialog_add_new_contact(sip_dialog_t dialog, _sip_msg_t *sip_msg)
1758*4702Sgm209912 {
1759*4702Sgm209912 	sip_header_t chdr = NULL;
1760*4702Sgm209912 	sip_header_t nhdr = NULL;
1761*4702Sgm209912 
1762*4702Sgm209912 	(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
1763*4702Sgm209912 	chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
1764*4702Sgm209912 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
1765*4702Sgm209912 
1766*4702Sgm209912 	if (chdr == NULL)
1767*4702Sgm209912 		return;
1768*4702Sgm209912 
1769*4702Sgm209912 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
1770*4702Sgm209912 	if (dialog->sip_dlg_method != INVITE || dialog->sip_dlg_state
1771*4702Sgm209912 	    != SIP_DLG_CONFIRMED) {
1772*4702Sgm209912 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1773*4702Sgm209912 		return;
1774*4702Sgm209912 	}
1775*4702Sgm209912 
1776*4702Sgm209912 	if (((nhdr = sip_dup_header(chdr)) != NULL)) {
1777*4702Sgm209912 		if (dialog->sip_dlg_new_local_contact != NULL)
1778*4702Sgm209912 			sip_free_header(dialog->sip_dlg_new_local_contact);
1779*4702Sgm209912 		dialog->sip_dlg_new_local_contact = nhdr;
1780*4702Sgm209912 	}
1781*4702Sgm209912 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1782*4702Sgm209912 }
1783