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);
1232882Svi117747 	if (dialog->sip_dlg_route_set != NULL)
1242882Svi117747 		sip_free_header(dialog->sip_dlg_route_set);
1252882Svi117747 	if (dialog->sip_dlg_event != NULL)
1262882Svi117747 		sip_free_header(dialog->sip_dlg_event);
1272882Svi117747 	if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) {
1282882Svi117747 		free(dialog->sip_dlg_req_uri.sip_str_ptr);
1292882Svi117747 		dialog->sip_dlg_req_uri.sip_str_ptr = NULL;
1302882Svi117747 		dialog->sip_dlg_req_uri.sip_str_len = 0;
1312882Svi117747 	}
1322882Svi117747 	if (dialog->sip_dlg_rset.sip_str_ptr != NULL) {
1332882Svi117747 		free(dialog->sip_dlg_rset.sip_str_ptr);
1342882Svi117747 		dialog->sip_dlg_rset.sip_str_len = 0;
1352882Svi117747 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
1362882Svi117747 	}
1372882Svi117747 	(void) pthread_mutex_destroy(&dialog->sip_dlg_mutex);
1382882Svi117747 	free(dialog);
1392882Svi117747 }
1402882Svi117747 
1412882Svi117747 /*
1422882Svi117747  * Get the route information from the 'value' and add it to the route
1432882Svi117747  * set.
1442882Svi117747  */
1452882Svi117747 static sip_dlg_route_set_t *
1462882Svi117747 sip_add_route_to_set(sip_hdr_value_t *value)
1472882Svi117747 {
1482882Svi117747 	int			vlen = 0;
1492882Svi117747 	sip_dlg_route_set_t	*rset;
1502882Svi117747 	char			*crlf;
1512882Svi117747 	const sip_param_t	*uri_param;
1522882Svi117747 	int			error;
1532882Svi117747 
1542882Svi117747 	rset = calloc(1, sizeof (*rset));
1552882Svi117747 	if (rset == NULL)
1562882Svi117747 		return (NULL);
1572882Svi117747 	rset->sip_dlg_route_next = NULL;
1582882Svi117747 	vlen = value->sip_value_end - value->sip_value_start;
1592882Svi117747 
1602882Svi117747 	/*
1612882Svi117747 	 * check for CRLF
1622882Svi117747 	 */
1632882Svi117747 	crlf = value->sip_value_end - strlen(SIP_CRLF);
1642882Svi117747 	while (crlf != NULL && strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) {
1652882Svi117747 		vlen -= strlen(SIP_CRLF);
1662882Svi117747 		crlf -= strlen(SIP_CRLF);
1672882Svi117747 	}
1682882Svi117747 	rset->sip_dlg_route = calloc(1, vlen + 1);
1692882Svi117747 	if (rset->sip_dlg_route == NULL) {
1702882Svi117747 		free(rset);
1712882Svi117747 		return (NULL);
1722882Svi117747 	}
1732882Svi117747 	/*
1742882Svi117747 	 * loose routing
1752882Svi117747 	 */
1762882Svi117747 	rset->sip_dlg_route_lr = B_FALSE;
1772882Svi117747 	(void) strncpy(rset->sip_dlg_route, value->sip_value_start, vlen);
1782882Svi117747 	rset->sip_dlg_ruri.sip_str_ptr = rset->sip_dlg_route +
1792882Svi117747 	    (value->cftr_uri.sip_str_ptr - value->sip_value_start);
1802882Svi117747 	rset->sip_dlg_ruri.sip_str_len = value->cftr_uri.sip_str_len;
1812882Svi117747 	rset->sip_dlg_route[vlen] = '\0';
1822882Svi117747 
1832882Svi117747 	assert(value->sip_value_parsed_uri != NULL);
1842882Svi117747 	/*
1852882Svi117747 	 * Check if the 'lr' param is present for this route.
1862882Svi117747 	 */
1872882Svi117747 	uri_param = sip_get_uri_params(value->sip_value_parsed_uri, &error);
1882882Svi117747 	if (error != 0) {
1892882Svi117747 		free(rset->sip_dlg_route);
1902882Svi117747 		free(rset);
1912882Svi117747 		return (NULL);
1922882Svi117747 	}
1932882Svi117747 	if (uri_param != NULL) {
1942882Svi117747 		rset->sip_dlg_route_lr = sip_is_param_present(uri_param, "lr",
1952882Svi117747 		    strlen("lr"));
1962882Svi117747 	}
1972882Svi117747 	return (rset);
1982882Svi117747 }
1992882Svi117747 
2002882Svi117747 /*
2012882Svi117747  * Depending on the route-set, determine the request URI.
2022882Svi117747  */
2032882Svi117747 char *
2042882Svi117747 sip_dialog_req_uri(sip_dialog_t dialog)
2052882Svi117747 {
2062882Svi117747 	const sip_str_t		*req_uri;
2072882Svi117747 	char			*uri;
2082882Svi117747 	_sip_dialog_t		*_dialog;
2092882Svi117747 
2102882Svi117747 	_dialog = (_sip_dialog_t *)dialog;
2112882Svi117747 	if (_dialog->sip_dlg_route_set == NULL ||
2122882Svi117747 	    _dialog->sip_dlg_req_uri.sip_str_ptr == NULL) {
2132882Svi117747 		const struct sip_value	*val;
2142882Svi117747 
2152882Svi117747 		val = sip_get_header_value(_dialog->sip_dlg_remote_target,
2162882Svi117747 		    NULL);
2172882Svi117747 		if (val == NULL)
2182882Svi117747 			return (NULL);
2192882Svi117747 		req_uri = &((sip_hdr_value_t *)val)->cftr_uri;
2202882Svi117747 	} else {
2212882Svi117747 		req_uri = &_dialog->sip_dlg_req_uri;
2222882Svi117747 	}
2232882Svi117747 	uri = (char *)malloc(req_uri->sip_str_len + 1);
2242882Svi117747 	if (uri == NULL)
2252882Svi117747 		return (NULL);
2262882Svi117747 	(void) strncpy(uri, req_uri->sip_str_ptr, req_uri->sip_str_len);
2272882Svi117747 	uri[req_uri->sip_str_len] = '\0';
2282882Svi117747 
2292882Svi117747 	return (uri);
2302882Svi117747 }
2312882Svi117747 
2322882Svi117747 /*
2332882Svi117747  * Free the route set.
2342882Svi117747  */
2352882Svi117747 void
2362882Svi117747 sip_dialog_free_rset(sip_dlg_route_set_t *rset)
2372882Svi117747 {
2382882Svi117747 	sip_dlg_route_set_t	*next;
2392882Svi117747 
2402882Svi117747 	while (rset != NULL) {
2412882Svi117747 		next = rset->sip_dlg_route_next;
2422882Svi117747 		rset->sip_dlg_route_next = NULL;
2432882Svi117747 		free(rset->sip_dlg_route);
2442882Svi117747 		free(rset);
2452882Svi117747 		rset = next;
2462882Svi117747 	}
2472882Svi117747 }
2482882Svi117747 
2492882Svi117747 /*
2502882Svi117747  * Recompute route-set
2512882Svi117747  */
2522882Svi117747 static int
2532882Svi117747 sip_dlg_recompute_rset(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what)
2542882Svi117747 {
2552882Svi117747 	int ret;
2562882Svi117747 
2572882Svi117747 	if (dialog->sip_dlg_route_set != NULL) {
2582882Svi117747 		sip_free_header(dialog->sip_dlg_route_set);
2592882Svi117747 		dialog->sip_dlg_route_set = NULL;
2602882Svi117747 	}
2612882Svi117747 	if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) {
2622882Svi117747 		free(dialog->sip_dlg_req_uri.sip_str_ptr);
2632882Svi117747 		dialog->sip_dlg_req_uri.sip_str_ptr = NULL;
2642882Svi117747 		dialog->sip_dlg_req_uri.sip_str_len = 0;
2652882Svi117747 	}
2662882Svi117747 	if (dialog->sip_dlg_rset.sip_str_ptr != NULL) {
2672882Svi117747 		free(dialog->sip_dlg_rset.sip_str_ptr);
2682882Svi117747 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
2692882Svi117747 		dialog->sip_dlg_rset.sip_str_len = 0;
2702882Svi117747 	}
2712882Svi117747 	ret = sip_dialog_get_route_set(dialog, sip_msg, what);
2722882Svi117747 	return (ret);
2732882Svi117747 }
2742882Svi117747 
2752882Svi117747 /*
2762882Svi117747  * If the route set is empty, the UAC MUST place the remote target URI
2772882Svi117747  * into the Request-URI.  The UAC MUST NOT add a Route header field to
2782882Svi117747  * the request.
2792882Svi117747  *
2802882Svi117747  * If the route set is not empty, and the first URI in the route set
2812882Svi117747  * contains the lr parameter (see Section 19.1.1), the UAC MUST place
2822882Svi117747  * the remote target URI into the Request-URI and MUST include a Route
2832882Svi117747  * header field containing the route set values in order, including all
2842882Svi117747  * parameters.
2852882Svi117747  *
2862882Svi117747  * If the route set is not empty, and its first URI does not contain the
2872882Svi117747  * lr parameter, the UAC MUST place the first URI from the route set
2882882Svi117747  * into the Request-URI, stripping any parameters that are not allowed
2892882Svi117747  * in a Request-URI.  The UAC MUST add a Route header field containing
2902882Svi117747  * the remainder of the route set values in order, including all
2912882Svi117747  * parameters.  The UAC MUST then place the remote target URI into the
2922882Svi117747  * Route header field as the last value.
2932882Svi117747  */
2942882Svi117747 int
2952882Svi117747 sip_dialog_set_route_hdr(_sip_dialog_t *dialog, sip_dlg_route_set_t *rset_head,
2962882Svi117747     int rcnt, int rlen)
2972882Svi117747 {
2982882Svi117747 	size_t			rset_len;
2992882Svi117747 	_sip_header_t		*rhdr;
3002882Svi117747 	char			*rset;
3012882Svi117747 	char			*rp;
3022882Svi117747 	char			*rsp;
3032882Svi117747 	int			count;
3042882Svi117747 	sip_dlg_route_set_t	*route;
3052882Svi117747 	boolean_t		first = B_TRUE;
3062882Svi117747 	const sip_str_t		*to_uri;
3072882Svi117747 	char			*uri = NULL;
3082882Svi117747 	int			rspl;
3092882Svi117747 	int			rpl;
3102882Svi117747 
3112882Svi117747 	assert(rcnt > 0);
3122882Svi117747 
3132882Svi117747 	dialog->sip_dlg_rset.sip_str_len = rlen + rcnt - 1;
3142882Svi117747 	dialog->sip_dlg_rset.sip_str_ptr = malloc(rlen + rcnt);
3152882Svi117747 	if (dialog->sip_dlg_rset.sip_str_ptr == NULL)
3162882Svi117747 		return (ENOMEM);
3172882Svi117747 	rsp = dialog->sip_dlg_rset.sip_str_ptr;
3182882Svi117747 	rspl = rlen + rcnt;
3192882Svi117747 	route = rset_head;
3202882Svi117747 	rset_len = rlen;
3212882Svi117747 	if (!route->sip_dlg_route_lr) {
3222882Svi117747 		const struct sip_value	*val;
3232882Svi117747 
3242882Svi117747 		val = sip_get_header_value(dialog->sip_dlg_remote_target, NULL);
3252882Svi117747 		to_uri = &((sip_hdr_value_t *)val)->cftr_uri;
3262882Svi117747 		uri = (char *)malloc(to_uri->sip_str_len + 1);
3272882Svi117747 		if (uri == NULL) {
3282882Svi117747 			free(dialog->sip_dlg_rset.sip_str_ptr);
3292882Svi117747 			dialog->sip_dlg_rset.sip_str_len = 0;
3302882Svi117747 			dialog->sip_dlg_rset.sip_str_ptr = NULL;
3312882Svi117747 			return (ENOMEM);
3322882Svi117747 		}
3332882Svi117747 		(void) strncpy(uri, to_uri->sip_str_ptr, to_uri->sip_str_len);
3342882Svi117747 		uri[to_uri->sip_str_len] = '\0';
3352882Svi117747 		rset_len = rlen - strlen(route->sip_dlg_route) + strlen(uri) +
3362882Svi117747 		    SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN +
3372882Svi117747 		    sizeof (char);
3382882Svi117747 		count = snprintf(rsp, rspl, "%s", route->sip_dlg_route);
3392882Svi117747 		dialog->sip_dlg_req_uri.sip_str_ptr = malloc(
3402882Svi117747 		    route->sip_dlg_ruri.sip_str_len + 1);
3412882Svi117747 		if (dialog->sip_dlg_req_uri.sip_str_ptr == NULL) {
3422882Svi117747 			free(uri);
3432882Svi117747 			free(dialog->sip_dlg_rset.sip_str_ptr);
3442882Svi117747 			dialog->sip_dlg_rset.sip_str_len = 0;
3452882Svi117747 			dialog->sip_dlg_rset.sip_str_ptr = NULL;
3462882Svi117747 			return (ENOMEM);
3472882Svi117747 		}
3482882Svi117747 		(void) strncpy(dialog->sip_dlg_req_uri.sip_str_ptr, rsp +
3492882Svi117747 		    (route->sip_dlg_ruri.sip_str_ptr - route->sip_dlg_route),
3502882Svi117747 		    route->sip_dlg_ruri.sip_str_len);
3512882Svi117747 		dialog->sip_dlg_req_uri.sip_str_ptr[
3522882Svi117747 		    route->sip_dlg_ruri.sip_str_len] = '\0';
3532882Svi117747 		dialog->sip_dlg_req_uri.sip_str_len =
3542882Svi117747 		    route->sip_dlg_ruri.sip_str_len;
3552882Svi117747 
3562882Svi117747 		rsp += count;
3572882Svi117747 		rspl -= count;
3582882Svi117747 		route = route->sip_dlg_route_next;
3592882Svi117747 	}
3602882Svi117747 
3612882Svi117747 	/*
3622882Svi117747 	 * rcnt - 1 is for the number of COMMAs
3632882Svi117747 	 */
3642882Svi117747 	rset_len += strlen(SIP_ROUTE) + SIP_SPACE_LEN + sizeof (char) +
3652882Svi117747 	    SIP_SPACE_LEN + rcnt - 1;
3662882Svi117747 	rset = malloc(rset_len + 1);
3672882Svi117747 	if (rset == NULL) {
3682882Svi117747 		free(dialog->sip_dlg_rset.sip_str_ptr);
3692882Svi117747 		dialog->sip_dlg_rset.sip_str_len = 0;
3702882Svi117747 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
3712882Svi117747 		return (ENOMEM);
3722882Svi117747 	}
3732882Svi117747 	rhdr = sip_new_header(rset_len + strlen(SIP_CRLF));
3742882Svi117747 	if (rhdr == NULL) {
3752882Svi117747 		free(rset);
3762882Svi117747 		free(dialog->sip_dlg_rset.sip_str_ptr);
3772882Svi117747 		dialog->sip_dlg_rset.sip_str_len = 0;
3782882Svi117747 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
3792882Svi117747 		return (ENOMEM);
3802882Svi117747 	}
3812882Svi117747 
3822882Svi117747 	rp = rset;
3832882Svi117747 	rpl = rset_len + 1;
3842882Svi117747 	count = snprintf(rp, rpl, "%s %c ", SIP_ROUTE, SIP_HCOLON);
3852882Svi117747 	rp += count;
3862882Svi117747 	rpl -= count;
3872882Svi117747 
3882882Svi117747 	while (route != NULL) {
3892882Svi117747 		if (first) {
3902882Svi117747 			count = snprintf(rp, rpl, "%s", route->sip_dlg_route);
3912882Svi117747 			rp += count;
3922882Svi117747 			rpl -= count;
3932882Svi117747 			first = B_FALSE;
3942882Svi117747 			if (uri != NULL) {
3952882Svi117747 				count = snprintf(rsp, rspl, "%c%s",
3962882Svi117747 				    SIP_COMMA, route->sip_dlg_route);
3972882Svi117747 			} else {
3982882Svi117747 				count = snprintf(rsp, rspl, "%s",
3992882Svi117747 				    route->sip_dlg_route);
4002882Svi117747 			}
4012882Svi117747 			rsp += count;
4022882Svi117747 			rspl -= count;
4032882Svi117747 		} else {
4042882Svi117747 			count = snprintf(rp, rpl, "%c%s", SIP_COMMA,
4052882Svi117747 			    route->sip_dlg_route);
4062882Svi117747 			rp += count;
4072882Svi117747 			rpl -= count;
4082882Svi117747 			count = snprintf(rsp, rspl, "%c%s", SIP_COMMA,
4092882Svi117747 			    route->sip_dlg_route);
4102882Svi117747 			rsp += count;
4112882Svi117747 			rspl -= count;
4122882Svi117747 		}
4132882Svi117747 		route = route->sip_dlg_route_next;
4142882Svi117747 	}
4152882Svi117747 	assert(rsp <= dialog->sip_dlg_rset.sip_str_ptr +
4162882Svi117747 	    dialog->sip_dlg_rset.sip_str_len);
4172882Svi117747 	dialog->sip_dlg_rset.sip_str_ptr[dialog->sip_dlg_rset.sip_str_len] =
4182882Svi117747 	    '\0';
4192882Svi117747 	if (uri != NULL) {
4202882Svi117747 		if (first) {
4212882Svi117747 			count = snprintf(rp, rpl, "%c %s %c", SIP_LAQUOT,
4222882Svi117747 			    uri, SIP_RAQUOT);
4232882Svi117747 		} else {
4242882Svi117747 			count = snprintf(rp, rpl, "%c%c %s %c", SIP_COMMA,
4252882Svi117747 			    SIP_LAQUOT, uri, SIP_RAQUOT);
4262882Svi117747 		}
4272882Svi117747 		rp += count;
4282882Svi117747 		rpl -= count;
4292882Svi117747 		free(uri);
4302882Svi117747 	}
4312882Svi117747 	assert(rp <= rset + rset_len);
4322882Svi117747 	(void) snprintf(rhdr->sip_hdr_start, rset_len + strlen(SIP_CRLF) + 1,
4332882Svi117747 	    "%s%s", rset, SIP_CRLF);
4342882Svi117747 	free(rset);
4352882Svi117747 	dialog->sip_dlg_route_set = (sip_header_t)rhdr;
4362882Svi117747 	sip_dialog_free_rset(rset_head);
4372882Svi117747 	return (0);
4382882Svi117747 }
4392882Svi117747 
4402882Svi117747 /*
4412882Svi117747  * UAC Behavior
4422882Svi117747  * The route set MUST be set to the list of URIs in the Record-Route
4432882Svi117747  * header field from the response, taken in reverse order and preserving
4442882Svi117747  * all URI parameters.
4452882Svi117747  *
4462882Svi117747  * UAS behavior
4472882Svi117747  * The route set MUST be set to the list of URIs in the Record-Route
4482882Svi117747  * header field from the request, taken in order and preserving all URI
4492882Svi117747  * parameters.
4502882Svi117747  */
4512882Svi117747 static int
4522882Svi117747 sip_dialog_get_route_set(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what)
4532882Svi117747 {
4542882Svi117747 	sip_header_t		rrhdr;
4552882Svi117747 	sip_hdr_value_t		*value;
4562882Svi117747 	int			error;
4572882Svi117747 	sip_dlg_route_set_t	*rset_head = NULL;
4582882Svi117747 	sip_dlg_route_set_t	*rset_tail = NULL;
4592882Svi117747 	sip_dlg_route_set_t	*rset;
4602882Svi117747 	int			rset_cnt = 0;
4612882Svi117747 	int			rset_len = 0;
4622882Svi117747 
4632882Svi117747 	(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
4642882Svi117747 	rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, NULL);
4652882Svi117747 	while (rrhdr != NULL) {
4662882Svi117747 		(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
4672882Svi117747 		value = (sip_hdr_value_t *)sip_get_header_value(rrhdr, &error);
4682882Svi117747 		while (value != NULL && error == 0) {
4692882Svi117747 			char	*crlf;
4702882Svi117747 
4712882Svi117747 			if (value->sip_value_state == SIP_VALUE_BAD) {
4722882Svi117747 				value = (sip_hdr_value_t *)sip_get_next_value(
4732882Svi117747 				    (sip_header_value_t)value, &error);
4742882Svi117747 				continue;
4752882Svi117747 			}
4762882Svi117747 			rset = sip_add_route_to_set(value);
4772882Svi117747 			if (rset == NULL)
4782882Svi117747 				goto r_error;
4792882Svi117747 			/*
4802882Svi117747 			 * Add one for COMMA
4812882Svi117747 			 */
4822882Svi117747 			rset_cnt++;
4832882Svi117747 			rset_len += (value->sip_value_end -
4842882Svi117747 			    value->sip_value_start);
4852882Svi117747 			/*
4862882Svi117747 			 * Check for CRLF
4872882Svi117747 			 */
4882882Svi117747 			crlf = value->sip_value_end - strlen(SIP_CRLF);
4892882Svi117747 			while (crlf != NULL &&
4902882Svi117747 			    strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) {
4912882Svi117747 				rset_len -= strlen(SIP_CRLF);
4922882Svi117747 				crlf -= strlen(SIP_CRLF);
4932882Svi117747 			}
4942882Svi117747 			if (rset_head == NULL) {
4952882Svi117747 				assert(rset_tail == NULL);
4962882Svi117747 				rset_head = rset_tail = rset;
4972882Svi117747 			} else if (what == SIP_UAS_DIALOG) {
4982882Svi117747 				rset_tail->sip_dlg_route_next = rset;
4992882Svi117747 				rset_tail = rset;
5002882Svi117747 			} else if (what == SIP_UAC_DIALOG) {
5012882Svi117747 				rset->sip_dlg_route_next = rset_head;
5022882Svi117747 				rset_head = rset;
5032882Svi117747 			} else {
5042882Svi117747 				assert(0);
5052882Svi117747 			}
5062882Svi117747 			value = (sip_hdr_value_t *)sip_get_next_value(
5072882Svi117747 			    (sip_header_value_t)value, &error);
5082882Svi117747 		}
5092882Svi117747 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
5102882Svi117747 		rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, rrhdr);
5112882Svi117747 	}
5122882Svi117747 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
5132882Svi117747 	if (rset_cnt == 0)
5142882Svi117747 		return (0);
5152882Svi117747 	if (sip_dialog_set_route_hdr(dialog, rset_head, rset_cnt,
5162882Svi117747 	    rset_len) != 0) {
5172882Svi117747 		goto r_error;
5182882Svi117747 	}
5192882Svi117747 	return (0);
5202882Svi117747 r_error:
5212882Svi117747 	sip_dialog_free_rset(rset_head);
5222882Svi117747 	return (ENOMEM);
5232882Svi117747 }
5242882Svi117747 
5252882Svi117747 /*
5262882Svi117747  * UAS behavior:
5272882Svi117747  * The remote sequence number MUST be set to the value of the sequence
5282882Svi117747  * number in the CSeq header field of the request.  The local sequence
5292882Svi117747  * number MUST be empty.  The call identifier component of the dialog ID
5302882Svi117747  * MUST be set to the value of the Call-ID in the request.  The local
5312882Svi117747  * tag component of the dialog ID MUST be set to the tag in the To field
5322882Svi117747  * in the response to the request (which always includes a tag), and the
5332882Svi117747  * remote tag component of the dialog ID MUST be set to the tag from the
5342882Svi117747  * From field in the request.  A UAS MUST be prepared to receive a
5352882Svi117747  * request without a tag in the From field, in which case the tag is
5362882Svi117747  * considered to have a value of null.
5372882Svi117747  * The remote URI MUST be set to the URI in the From field, and the
5382882Svi117747  * local URI MUST be set to the URI in the To field.
5392882Svi117747  * The remote target MUST be set to the URI from the Contact header field
5402882Svi117747  * of the request.
5412882Svi117747  *
5422882Svi117747  * UAC behavior:
5432882Svi117747  * The local sequence number MUST be set to the value of the sequence
5442882Svi117747  * number in the CSeq header field of the request.  The remote sequence
5452882Svi117747  * number MUST be empty (it is established when the remote UA sends a
5462882Svi117747  * request within the dialog).  The call identifier component of the
5472882Svi117747  * dialog ID MUST be set to the value of the Call-ID in the request.
5482882Svi117747  * The local tag component of the dialog ID MUST be set to the tag in
5492882Svi117747  * the From field in the request, and the remote tag component of the
5502882Svi117747  * dialog ID MUST be set to the tag in the To field of the response.  A
5512882Svi117747  * UAC MUST be prepared to receive a response without a tag in the To
5522882Svi117747  * field, in which case the tag is considered to have a value of null.
5532882Svi117747  * The remote URI MUST be set to the URI in the To field, and the local
5542882Svi117747  * URI MUST be set to the URI in the From field.
5552882Svi117747  * The remote target MUST be set to the URI from the Contact header field
5562882Svi117747  * of the response.
5572882Svi117747  */
5582882Svi117747 
5592882Svi117747 
5602882Svi117747 /*
5612882Svi117747  * This is the routine that seeds a dialog.
5622882Svi117747  */
5632882Svi117747 sip_dialog_t
5642882Svi117747 sip_seed_dialog(sip_conn_object_t obj, _sip_msg_t *sip_msg,
5652882Svi117747     boolean_t dlg_on_fork, int dlg_type)
5662882Svi117747 {
5672882Svi117747 	_sip_dialog_t		*dialog;
5682882Svi117747 	int			cseq;
5692882Svi117747 	sip_header_t		fhdr = NULL;
5702882Svi117747 	sip_header_t		thdr = NULL;
5712882Svi117747 	sip_header_t		chdr;
5722882Svi117747 	sip_header_t		cihdr;
5732882Svi117747 	sip_header_t		evhdr = NULL;
5742882Svi117747 	const struct sip_value	*value;
5752882Svi117747 	sip_dialog_timer_obj_t	*tim_obj = NULL;
5762882Svi117747 	const sip_str_t		*callid;
5772882Svi117747 	sip_method_t		method;
5782882Svi117747 	int			timer1 = sip_timer_T1;
5792882Svi117747 	int			error;
5802882Svi117747 
5812882Svi117747 	if (!sip_msg_is_request((sip_msg_t)sip_msg, &error))
5822882Svi117747 		return (NULL);
5832882Svi117747 
5842882Svi117747 	method = sip_get_request_method((sip_msg_t)sip_msg, &error);
5852882Svi117747 	/*
5862882Svi117747 	 * Only INVITE and SUBSCRIBE supported
5872882Svi117747 	 */
5882882Svi117747 	if (error != 0 || (method != INVITE && method != SUBSCRIBE))
5892882Svi117747 		return (NULL);
5902882Svi117747 
5912882Svi117747 	/*
5922882Svi117747 	 * A request outside of a dialog MUST NOT contain a To tag
5932882Svi117747 	 */
5942882Svi117747 	if (sip_get_to_tag((sip_msg_t)sip_msg, NULL) != NULL)
5952882Svi117747 		return (NULL);
5962882Svi117747 
5972882Svi117747 	if (dlg_type == SIP_UAS_DIALOG) {
5982882Svi117747 		thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg,
5992882Svi117747 		    SIP_DLG_XCHG_FROM);
6002882Svi117747 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
6012882Svi117747 	} else {
6022882Svi117747 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
6032882Svi117747 		fhdr = sip_search_for_header(sip_msg, SIP_FROM, NULL);
6042882Svi117747 	}
6052882Svi117747 	cihdr = sip_search_for_header(sip_msg, SIP_CALL_ID, NULL);
6062882Svi117747 	chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
6072882Svi117747 	if (method == SUBSCRIBE)
6082882Svi117747 		evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL);
6092882Svi117747 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
6102882Svi117747 	if ((fhdr == NULL && thdr == NULL) || cihdr == NULL || chdr == NULL ||
6112882Svi117747 	    (method == SUBSCRIBE && evhdr == NULL)) {
6122882Svi117747 		if (thdr != NULL)
6132882Svi117747 			sip_free_header(thdr);
6142882Svi117747 		return (NULL);
6152882Svi117747 	}
6162882Svi117747 
6172882Svi117747 	/*
6182882Svi117747 	 * Sanity check since we just store the headers in the dialog
6192882Svi117747 	 */
6202882Svi117747 	if (sip_get_from_tag((sip_msg_t)sip_msg, NULL) == NULL ||
6212882Svi117747 	    sip_get_from_uri_str((sip_msg_t)sip_msg, NULL) == NULL ||
6222882Svi117747 	    ((cseq = sip_get_callseq_num((sip_msg_t)sip_msg, NULL)) == -1) ||
6232882Svi117747 	    (callid = sip_get_callid((sip_msg_t)sip_msg, NULL)) == NULL ||
6242882Svi117747 	    sip_get_to_uri_str((sip_msg_t)sip_msg, NULL) == NULL ||
6252882Svi117747 	    ((value = sip_get_header_value(chdr, NULL)) == NULL) ||
6262882Svi117747 	    sip_get_contact_uri_str((sip_header_value_t)value, NULL) == NULL) {
6272882Svi117747 		if (thdr != NULL)
6282882Svi117747 			sip_free_header(thdr);
6292882Svi117747 		return (NULL);
6302882Svi117747 	}
6312882Svi117747 
6322882Svi117747 	tim_obj = calloc(1, sizeof (sip_dialog_timer_obj_t));
6332882Svi117747 	if (tim_obj == NULL) {
6342882Svi117747 		if (thdr != NULL)
6352882Svi117747 			sip_free_header(thdr);
6362882Svi117747 		return (NULL);
6372882Svi117747 	}
6382882Svi117747 	dialog = calloc(1, sizeof (_sip_dialog_t));
6392882Svi117747 	if (dialog == NULL) {
6402882Svi117747 		if (thdr != NULL)
6412882Svi117747 			sip_free_header(thdr);
6422882Svi117747 		return (NULL);
6432882Svi117747 	}
6442882Svi117747 	/*
6452882Svi117747 	 * We will take the TO header with the tag when we complete this
6462882Svi117747 	 * dialog
6472882Svi117747 	 */
6482882Svi117747 	if (dlg_type == SIP_UAS_DIALOG) {
6492882Svi117747 		dialog->sip_dlg_remote_uri_tag = thdr;
6502882Svi117747 		/*
6512882Svi117747 		 * We take the remote target from the incoming request on the
6522882Svi117747 		 * UAS. For the UAC, we will take it from the response.
6532882Svi117747 		 */
6542882Svi117747 		if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) ==
6552882Svi117747 		    NULL) {
6562882Svi117747 			goto dia_err;
6572882Svi117747 		}
6582882Svi117747 	} else {
6592882Svi117747 		if ((dialog->sip_dlg_local_uri_tag = sip_dup_header(fhdr)) ==
6602882Svi117747 		    NULL) {
6612882Svi117747 			goto dia_err;
6622882Svi117747 		}
6632882Svi117747 	}
6642882Svi117747 	if ((dialog->sip_dlg_call_id = sip_dup_header(cihdr)) == NULL)
6652882Svi117747 		goto dia_err;
6662882Svi117747 	if (method == SUBSCRIBE) {
6672882Svi117747 		dialog->sip_dlg_event = sip_dup_header(evhdr);
6682882Svi117747 		if (dialog->sip_dlg_event == NULL) {
6692882Svi117747 			goto dia_err;
6702882Svi117747 		}
6712882Svi117747 	}
6722882Svi117747 	dialog->sip_dlg_rset.sip_str_ptr = NULL;
6732882Svi117747 	dialog->sip_dlg_rset.sip_str_len = 0;
6742882Svi117747 	dialog->sip_dlg_req_uri.sip_str_ptr = NULL;
6752882Svi117747 	dialog->sip_dlg_req_uri.sip_str_len = 0;
6762882Svi117747 	/*
6772882Svi117747 	 * Get the route set from the request, if present
6782882Svi117747 	 */
6792882Svi117747 	if (dlg_type == SIP_UAS_DIALOG &&
6802882Svi117747 	    sip_dialog_get_route_set(dialog, sip_msg, dlg_type) != 0) {
6812882Svi117747 		goto dia_err;
6822882Svi117747 	}
6832882Svi117747 	if (dlg_type == SIP_UAC_DIALOG)
6842882Svi117747 		dialog->sip_dlg_local_cseq = cseq;
6852882Svi117747 	else
6862882Svi117747 		dialog->sip_dlg_remote_cseq = cseq;
6872882Svi117747 	dialog->sip_dlg_type = dlg_type;
6882882Svi117747 	dialog->sip_dlg_on_fork = dlg_on_fork;
6892882Svi117747 	dialog->sip_dlg_method = method;
6902882Svi117747 	/*
6912882Svi117747 	 * Set the partial dialog timer with the INVITE timeout val
6922882Svi117747 	 */
6932882Svi117747 	if (sip_conn_timer1 != NULL)
6942882Svi117747 		timer1 = sip_conn_timer1(obj);
6952882Svi117747 	SIP_INIT_TIMER(dialog->sip_dlg_timer, 64 * timer1);
6962882Svi117747 	tim_obj->dialog = dialog;
6972882Svi117747 	/*
6982882Svi117747 	 * Since at the client we never pass the partial dialog, we need not
6992882Svi117747 	 * invoke the callback when the partial dialog self-destructs.
7002882Svi117747 	 */
7012882Svi117747 	if (dlg_type == SIP_UAS_DIALOG)
7022882Svi117747 		tim_obj->func = sip_ulp_dlg_del_cb;
7032882Svi117747 	SIP_SCHED_TIMER(dialog->sip_dlg_timer, (void *)tim_obj,
7042882Svi117747 	    sip_dlg_self_destruct);
7052882Svi117747 	if (!SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
7062882Svi117747 		goto dia_err;
7072882Svi117747 	(void) pthread_mutex_init(&dialog->sip_dlg_mutex, NULL);
7082882Svi117747 
7092882Svi117747 	if (dlg_type == SIP_UAC_DIALOG) {
7102882Svi117747 		const sip_str_t	*local_tag;
7112882Svi117747 
7122882Svi117747 		local_tag = sip_get_from_tag((sip_msg_t)sip_msg, NULL);
7132882Svi117747 		assert(local_tag != NULL);
7142882Svi117747 		sip_md5_hash(local_tag->sip_str_ptr, local_tag->sip_str_len,
7152882Svi117747 		    callid->sip_str_ptr, callid->sip_str_len,
7162882Svi117747 		    NULL, 0, NULL, 0, NULL, 0, NULL, 0,
7172882Svi117747 		    (uchar_t *)dialog->sip_dlg_id);
7182882Svi117747 
7192882Svi117747 
7202882Svi117747 		/*
7212882Svi117747 		 * Add it to the partial hash table
7222882Svi117747 		 */
7232882Svi117747 		if (sip_hash_add(sip_dialog_phash, (void *)dialog,
7242882Svi117747 		    SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) {
7252882Svi117747 			goto dia_err;
7262882Svi117747 		}
7272882Svi117747 	}
7282882Svi117747 	SIP_DLG_REFCNT_INCR(dialog);
7292882Svi117747 	return ((sip_dialog_t)dialog);
7302882Svi117747 dia_err:
7312882Svi117747 	sip_release_dialog_res(dialog);
7322882Svi117747 	if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
7332882Svi117747 		SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
7342882Svi117747 	if (tim_obj != NULL)
7352882Svi117747 		free(tim_obj);
7362882Svi117747 	return (NULL);
7372882Svi117747 }
7382882Svi117747 
7392882Svi117747 /*
7402882Svi117747  * When creating a dialog from a NOTIFY request, we need to get the FROM
7412882Svi117747  * header for the dialog from the TO header of the NOTIFY.
7422882Svi117747  */
7432882Svi117747 _sip_header_t *
7442882Svi117747 sip_dlg_xchg_from_to(sip_msg_t sip_msg, int what)
7452882Svi117747 {
7462882Svi117747 	int			len;
7472882Svi117747 	_sip_header_t		*newhdr;
7482882Svi117747 	int			cnt;
7492882Svi117747 	const struct sip_header	*hdr;
7502882Svi117747 	int			hdrsize;
7512882Svi117747 	int			error;
7522882Svi117747 
7532882Svi117747 	hdr = sip_get_header(sip_msg, what == SIP_DLG_XCHG_FROM ? SIP_FROM :
7542882Svi117747 	    SIP_TO, NULL, &error);
7552882Svi117747 	if (error != 0 || hdr == NULL)
7562882Svi117747 		return (NULL);
7572882Svi117747 	if (sip_parse_goto_values((_sip_header_t *)hdr) != 0)
7582882Svi117747 		return (NULL);
7592882Svi117747 	len = hdr->sip_hdr_end - hdr->sip_hdr_current;
7602882Svi117747 	if (what == SIP_DLG_XCHG_FROM) {
7612882Svi117747 		hdrsize = len + strlen(SIP_TO) + SIP_SPACE_LEN + sizeof (char) +
7622882Svi117747 		    SIP_SPACE_LEN;
7632882Svi117747 	} else {
7642882Svi117747 		hdrsize = len + strlen(SIP_FROM) + SIP_SPACE_LEN +
7652882Svi117747 		    sizeof (char) + SIP_SPACE_LEN;
7662882Svi117747 	}
7672882Svi117747 	newhdr = sip_new_header(hdrsize);
7682882Svi117747 	if (newhdr == NULL)
7692882Svi117747 		return (NULL);
7702882Svi117747 	if (what == SIP_DLG_XCHG_FROM) {
7712882Svi117747 		cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1,
7722882Svi117747 		    "%s %c ", SIP_TO, SIP_HCOLON);
7732882Svi117747 	} else {
7742882Svi117747 		cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1,
7752882Svi117747 		    "%s %c ", SIP_FROM, SIP_HCOLON);
7762882Svi117747 	}
7772882Svi117747 	newhdr->sip_hdr_current += cnt;
7782882Svi117747 	(void) strncpy(newhdr->sip_hdr_current, hdr->sip_hdr_current, len);
7792882Svi117747 	newhdr->sip_hdr_current += len;
7802882Svi117747 	assert(newhdr->sip_hdr_current == newhdr->sip_hdr_end);
7812882Svi117747 	assert(hdr->sip_header_functions != NULL);
7822882Svi117747 
7832882Svi117747 	/*
7842882Svi117747 	 * FROM and TO have common parsing functions
7852882Svi117747 	 */
7862882Svi117747 	newhdr->sip_header_functions = hdr->sip_header_functions;
7872882Svi117747 	newhdr->sip_hdr_current = newhdr->sip_hdr_start;
7882882Svi117747 
7892882Svi117747 	return (newhdr);
7902882Svi117747 }
7912882Svi117747 
7922882Svi117747 /*
7932882Svi117747  * This is the response that completes the dialog that was created
7942882Svi117747  * in sip_seed_dialog().
7952882Svi117747  */
7962882Svi117747 sip_dialog_t
7972882Svi117747 sip_complete_dialog(_sip_msg_t *sip_msg, _sip_dialog_t *dialog)
7982882Svi117747 {
7992882Svi117747 	_sip_header_t		*thdr;
8002882Svi117747 	_sip_header_t		*evhdr = NULL;
8012882Svi117747 	_sip_header_t		*substate = NULL;
8022882Svi117747 	sip_header_t		chdr = NULL;
8032882Svi117747 	int			resp_code;
8042882Svi117747 	const sip_str_t		*ttag;
8052882Svi117747 	const sip_str_t		*remtag;
8062882Svi117747 	const sip_str_t		*callid;
8072882Svi117747 	const struct sip_value 	*val;
8082882Svi117747 	sip_method_t		method;
8092882Svi117747 	int			error = 0;
8102882Svi117747 	int			prev_state;
8112882Svi117747 	boolean_t		alloc_thdr = B_FALSE;
8122882Svi117747 
8132882Svi117747 	if (sip_msg_is_request((sip_msg_t)sip_msg, &error) && error == 0)
8142882Svi117747 		method = sip_get_request_method((sip_msg_t)sip_msg, &error);
8152882Svi117747 	else
8162882Svi117747 		method = sip_get_callseq_method((sip_msg_t)sip_msg, &error);
8172882Svi117747 	if (error != 0 || dialog == NULL ||
8182882Svi117747 	    (sip_msg_is_request((sip_msg_t)sip_msg, &error) &&
8192882Svi117747 	    (dialog->sip_dlg_method == INVITE || method != NOTIFY))) {
8202882Svi117747 		return (NULL);
8212882Svi117747 	}
8222882Svi117747 	if ((dialog->sip_dlg_type == SIP_UAC_DIALOG && method != NOTIFY &&
8232882Svi117747 	    sip_get_callseq_num((sip_msg_t)sip_msg, NULL) !=
8242882Svi117747 	    dialog->sip_dlg_local_cseq) ||
8252882Svi117747 	    (dialog->sip_dlg_type == SIP_UAS_DIALOG && method != NOTIFY &&
8262882Svi117747 	    sip_get_callseq_num((sip_msg_t)sip_msg, NULL) !=
8272882Svi117747 	    dialog->sip_dlg_remote_cseq)) {
8282882Svi117747 		return (NULL);
8292882Svi117747 	}
8302882Svi117747 	if (method == NOTIFY) {
8312882Svi117747 		const sip_str_t	*sstate;
8322882Svi117747 
8332882Svi117747 		thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg,
8342882Svi117747 		    SIP_DLG_XCHG_FROM);
8352882Svi117747 		if (thdr == NULL)
8362882Svi117747 			return (NULL);
8372882Svi117747 		alloc_thdr = B_TRUE;
8382882Svi117747 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
8392882Svi117747 		chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
8402882Svi117747 		if (chdr == NULL) {
8412882Svi117747 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
8422882Svi117747 			sip_free_header(thdr);
8432882Svi117747 			return (NULL);
8442882Svi117747 		}
8452882Svi117747 		evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL);
8462882Svi117747 		if (evhdr == NULL) {
8472882Svi117747 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
8482882Svi117747 			sip_free_header(thdr);
8492882Svi117747 			return (NULL);
8502882Svi117747 		}
8512882Svi117747 		substate = sip_search_for_header(sip_msg,
8522882Svi117747 		    SIP_SUBSCRIPTION_STATE, NULL);
8532882Svi117747 		if (substate == NULL) {
8542882Svi117747 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
8552882Svi117747 			sip_free_header(thdr);
8562882Svi117747 			return (NULL);
8572882Svi117747 		}
8582882Svi117747 		(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
8592882Svi117747 		sstate = sip_get_substate((sip_msg_t)sip_msg, &error);
8602882Svi117747 		if (sstate == NULL || error != 0) {
8612882Svi117747 			sip_free_header(thdr);
8622882Svi117747 			return (NULL);
8632882Svi117747 		}
8642882Svi117747 		if ((sstate->sip_str_len != strlen("pending") &&
8652882Svi117747 		    sstate->sip_str_len != strlen("active")) ||
8662882Svi117747 		    ((sstate->sip_str_len == strlen("pending") &&
8672882Svi117747 		    strncasecmp(sstate->sip_str_ptr, "pending",
8682882Svi117747 		    strlen("pending")) != 0) ||
8692882Svi117747 		    (sstate->sip_str_len == strlen("active") &&
8702882Svi117747 		    strncasecmp(sstate->sip_str_ptr, "active",
8712882Svi117747 		    strlen("active")) != 0))) {
8722882Svi117747 			sip_free_header(thdr);
8732882Svi117747 			return (NULL);
8742882Svi117747 		}
8752882Svi117747 		ttag = sip_get_from_tag((sip_msg_t)sip_msg, NULL);
8762882Svi117747 	} else {
8772882Svi117747 		if (dialog->sip_dlg_type == SIP_UAS_DIALOG) {
8782882Svi117747 			thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg,
8792882Svi117747 			    SIP_DLG_XCHG_TO);
8802882Svi117747 			alloc_thdr = B_TRUE;
8812882Svi117747 		} else {
8822882Svi117747 			(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
8832882Svi117747 			thdr = sip_search_for_header(sip_msg, SIP_TO, NULL);
8842882Svi117747 			if (dialog->sip_dlg_remote_target == NULL) {
8852882Svi117747 				chdr = sip_search_for_header(sip_msg,
8862882Svi117747 				    SIP_CONTACT, NULL);
8872882Svi117747 			}
8882882Svi117747 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
8892882Svi117747 		}
8902882Svi117747 		if (thdr == NULL) {
8912882Svi117747 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
8922882Svi117747 			return (NULL);
8932882Svi117747 		}
8942882Svi117747 		ttag = sip_get_to_tag((sip_msg_t)sip_msg, NULL);
8952882Svi117747 	}
8962882Svi117747 	if (ttag == NULL) {
8972882Svi117747 		if (alloc_thdr)
8982882Svi117747 			sip_free_header(thdr);
8992882Svi117747 		return (NULL);
9002882Svi117747 	}
9012882Svi117747 	prev_state = dialog->sip_dlg_state;
9022882Svi117747 
9032882Svi117747 	if (method == NOTIFY) {
9042882Svi117747 		int			error;
9052882Svi117747 		const sip_str_t		*dlg_id_val = NULL;
9062882Svi117747 		const sip_str_t		*event;
9072882Svi117747 		const sip_str_t		*id_val = NULL;
9082882Svi117747 		sip_header_value_t	ev_val;
9092882Svi117747 		sip_hdr_value_t		*dlg_ev_val = NULL;
9102882Svi117747 
9112882Svi117747 		event = sip_get_event((sip_msg_t)sip_msg, &error);
9122882Svi117747 		if (event == NULL || error != 0) {
9132882Svi117747 			sip_free_header(thdr);
9142882Svi117747 			return (NULL);
9152882Svi117747 		}
9162882Svi117747 		ev_val = (sip_header_value_t)sip_get_header_value(evhdr,
9172882Svi117747 		    &error);
9182882Svi117747 		if (ev_val != NULL)
9192882Svi117747 			id_val = sip_get_param_value(ev_val, "id", &error);
9202882Svi117747 		if (error == 0) {
9212882Svi117747 			dlg_ev_val = (sip_hdr_value_t *)sip_get_header_value(
9222882Svi117747 			    dialog->sip_dlg_event, &error);
9232882Svi117747 		}
9242882Svi117747 		if (dlg_ev_val == NULL || error != 0) {
9252882Svi117747 			sip_free_header(thdr);
9262882Svi117747 			return (NULL);
9272882Svi117747 		}
9282882Svi117747 		dlg_id_val = sip_get_param_value((sip_header_value_t)dlg_ev_val,
9292882Svi117747 		    "id", &error);
9302882Svi117747 		if (error != 0 ||
9312882Svi117747 		    dlg_ev_val->str_val_len != event->sip_str_len ||
9322882Svi117747 		    strncmp(dlg_ev_val->str_val_ptr, event->sip_str_ptr,
9332882Svi117747 		    event->sip_str_len != 0)) {
9342882Svi117747 			sip_free_header(thdr);
9352882Svi117747 			return (NULL);
9362882Svi117747 		}
9372882Svi117747 		if ((dlg_id_val == NULL && id_val != NULL) ||
9382882Svi117747 		    (dlg_id_val != NULL && id_val == NULL)) {
9392882Svi117747 			sip_free_header(thdr);
9402882Svi117747 			return (NULL);
9412882Svi117747 		} else if (dlg_id_val != NULL && id_val != NULL) {
9422882Svi117747 			if (dlg_id_val->sip_str_len != id_val->sip_str_len ||
9432882Svi117747 			    strncasecmp(dlg_id_val->sip_str_ptr,
9442882Svi117747 			    id_val->sip_str_ptr, dlg_id_val->sip_str_len) !=
9452882Svi117747 			    0) {
9462882Svi117747 				sip_free_header(thdr);
9472882Svi117747 				return (NULL);
9482882Svi117747 			}
9492882Svi117747 		}
9502882Svi117747 		if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
9512882Svi117747 			dialog->sip_dlg_remote_uri_tag = thdr;
9522882Svi117747 			if ((dialog->sip_dlg_remote_target =
9532882Svi117747 			    sip_dup_header(chdr)) == NULL) {
9542882Svi117747 				sip_free_header(thdr);
9552882Svi117747 				return (NULL);
9562882Svi117747 			}
9572882Svi117747 		} else {
9582882Svi117747 			dialog->sip_dlg_local_uri_tag = thdr;
9592882Svi117747 		}
9602882Svi117747 		dialog->sip_dlg_state = SIP_DLG_CONFIRMED;
9612882Svi117747 	} else {
9622882Svi117747 		resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
9632882Svi117747 		(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
9642882Svi117747 		assert(dialog->sip_dlg_state == SIP_DLG_NEW);
9652882Svi117747 		if (dialog->sip_dlg_remote_target == NULL && chdr != NULL) {
9662882Svi117747 			assert(dialog->sip_dlg_type == SIP_UAC_DIALOG);
9672882Svi117747 			if ((dialog->sip_dlg_remote_target =
9682882Svi117747 			    sip_dup_header(chdr)) == NULL) {
9692882Svi117747 				(void) pthread_mutex_unlock(
9702882Svi117747 				    &dialog->sip_dlg_mutex);
9712882Svi117747 				if (alloc_thdr)
9722882Svi117747 					sip_free_header(thdr);
9733439Svi117747 				goto terminate_new_dlg;
9742882Svi117747 			}
9752882Svi117747 			if (sip_dialog_get_route_set(dialog, sip_msg,
9762882Svi117747 			    dialog->sip_dlg_type) != 0) {
9772882Svi117747 				(void) pthread_mutex_unlock(
9782882Svi117747 				    &dialog->sip_dlg_mutex);
9792882Svi117747 				if (alloc_thdr)
9802882Svi117747 					sip_free_header(thdr);
9813439Svi117747 				goto terminate_new_dlg;
9822882Svi117747 			}
9832882Svi117747 		}
9842882Svi117747 		if (SIP_PROVISIONAL_RESP(resp_code)) {
9852882Svi117747 			dialog->sip_dlg_state = SIP_DLG_EARLY;
9862882Svi117747 		} else if (SIP_OK_RESP(resp_code)) {
9872882Svi117747 			/*
9882882Svi117747 			 * Per 12.1 the UAS must include the contact header
9892882Svi117747 			 * for a dialog establishing response, so if we
9902882Svi117747 			 * don't find one, we terminate it.
9912882Svi117747 			 */
9922882Svi117747 			if (dialog->sip_dlg_remote_target == NULL) {
9932882Svi117747 				(void) pthread_mutex_unlock(
9942882Svi117747 				    &dialog->sip_dlg_mutex);
9952882Svi117747 				if (sip_ulp_dlg_del_cb != NULL) {
9962882Svi117747 					sip_ulp_dlg_del_cb(dialog,
9972882Svi117747 					    (sip_msg_t)sip_msg, NULL);
9982882Svi117747 				}
9992882Svi117747 				if (alloc_thdr)
10002882Svi117747 					sip_free_header(thdr);
10013439Svi117747 				goto terminate_new_dlg;
10022882Svi117747 			}
10032882Svi117747 			dialog->sip_dlg_state = SIP_DLG_CONFIRMED;
10042882Svi117747 		} else {
10052882Svi117747 			(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
10062882Svi117747 			if (sip_ulp_dlg_del_cb != NULL) {
10072882Svi117747 				sip_ulp_dlg_del_cb(dialog, (sip_msg_t)sip_msg,
10082882Svi117747 				    NULL);
10092882Svi117747 			}
10102882Svi117747 			if (alloc_thdr)
10112882Svi117747 				sip_free_header(thdr);
10123439Svi117747 			goto terminate_new_dlg;
10132882Svi117747 		}
10142882Svi117747 		if (dialog->sip_dlg_type == SIP_UAS_DIALOG) {
10152882Svi117747 			dialog->sip_dlg_local_uri_tag = thdr;
10162882Svi117747 		} else {
10172882Svi117747 			if ((dialog->sip_dlg_remote_uri_tag =
10182882Svi117747 			    sip_dup_header(thdr)) == NULL) {
10192882Svi117747 				(void) pthread_mutex_unlock(
10202882Svi117747 				    &dialog->sip_dlg_mutex);
10213439Svi117747 				goto terminate_new_dlg;
10222882Svi117747 			}
10232882Svi117747 		}
10242882Svi117747 	}
10252882Svi117747 
10262882Svi117747 	/*
10272882Svi117747 	 * Cancel the partial dialog timer
10282882Svi117747 	 */
10292882Svi117747 	if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
10302882Svi117747 		SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
10312882Svi117747 
10322882Svi117747 	if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
10332882Svi117747 		val =  sip_get_header_value(dialog->sip_dlg_local_uri_tag,
10342882Svi117747 		    &error);
10352882Svi117747 	} else {
10362882Svi117747 		val =  sip_get_header_value(dialog->sip_dlg_remote_uri_tag,
10372882Svi117747 		    &error);
10382882Svi117747 	}
10392882Svi117747 	assert(val != NULL && error == 0);
10402882Svi117747 	remtag = sip_get_param_value((sip_header_value_t)val, "tag", &error);
10412882Svi117747 
10422882Svi117747 	val = sip_get_header_value(dialog->sip_dlg_call_id, &error);
10432882Svi117747 	callid = &((sip_hdr_value_t *)val)->str_val;
10442882Svi117747 
10452882Svi117747 	/*
10462882Svi117747 	 * Get an ID for this dialog
10472882Svi117747 	 */
10482882Svi117747 	if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
10492882Svi117747 		sip_md5_hash(remtag->sip_str_ptr, remtag->sip_str_len,
10502882Svi117747 		    ttag->sip_str_ptr, ttag->sip_str_len,
10512882Svi117747 		    callid->sip_str_ptr, callid->sip_str_len,
10522882Svi117747 		    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id);
10532882Svi117747 	} else {
10542882Svi117747 		sip_md5_hash(ttag->sip_str_ptr, ttag->sip_str_len,
10552882Svi117747 		    remtag->sip_str_ptr, remtag->sip_str_len,
10562882Svi117747 		    callid->sip_str_ptr, callid->sip_str_len,
10572882Svi117747 		    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id);
10582882Svi117747 	}
10592882Svi117747 
10602882Svi117747 	SIP_DLG_REFCNT_INCR(dialog);
10612882Svi117747 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
10622882Svi117747 
10632882Svi117747 	/*
10642882Svi117747 	 * Add it to the hash table
10652882Svi117747 	 */
10662882Svi117747 	if (sip_hash_add(sip_dialog_hash, (void *)dialog,
10672882Svi117747 	    SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) {
10683439Svi117747 	terminate_new_dlg:
10692882Svi117747 		/*
10702882Svi117747 		 * So that sip_dialog_delete() does not try to remove
10712882Svi117747 		 * this from the hash table.
10722882Svi117747 		 */
10732882Svi117747 		(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
10742882Svi117747 		if (dialog->sip_dlg_type == SIP_UAS_DIALOG) {
10753439Svi117747 			if (dialog->sip_dlg_local_uri_tag != NULL) {
10763439Svi117747 				sip_free_header(dialog->sip_dlg_local_uri_tag);
10773439Svi117747 				dialog->sip_dlg_local_uri_tag = NULL;
10783439Svi117747 			}
10792882Svi117747 		} else {
10803439Svi117747 			if (dialog->sip_dlg_remote_uri_tag != NULL) {
10813439Svi117747 				sip_free_header(dialog->sip_dlg_remote_uri_tag);
10823439Svi117747 				dialog->sip_dlg_remote_uri_tag = NULL;
10833439Svi117747 			}
10842882Svi117747 		}
10852882Svi117747 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
10862882Svi117747 		sip_dialog_terminate(dialog, (sip_msg_t)sip_msg);
10872882Svi117747 		return (NULL);
10882882Svi117747 	}
10892882Svi117747 	if (sip_dlg_ulp_state_cb != NULL) {
10902882Svi117747 		sip_dlg_ulp_state_cb((sip_dialog_t)dialog,
10912882Svi117747 		    (sip_msg_t)sip_msg, prev_state, dialog->sip_dlg_state);
10922882Svi117747 	}
10932882Svi117747 	return ((sip_dialog_t)dialog);
10942882Svi117747 }
10952882Svi117747 
10962882Svi117747 /*
10972882Svi117747  * Check if this dialog is a match.
10982882Svi117747  */
10992882Svi117747 boolean_t
11002882Svi117747 sip_dialog_match(void *obj, void *hindex)
11012882Svi117747 {
11022882Svi117747 	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
11032882Svi117747 
11042882Svi117747 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
11052882Svi117747 	if (dialog->sip_dlg_state == SIP_DLG_DESTROYED) {
11062882Svi117747 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
11072882Svi117747 		return (B_FALSE);
11082882Svi117747 	}
11092882Svi117747 	if (bcmp(dialog->sip_dlg_id, hindex,
11102882Svi117747 	    sizeof (dialog->sip_dlg_id)) == 0) {
11112882Svi117747 		SIP_DLG_REFCNT_INCR(dialog);
11122882Svi117747 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
11132882Svi117747 		return (B_TRUE);
11142882Svi117747 	}
11152882Svi117747 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
11162882Svi117747 	return (B_FALSE);
11172882Svi117747 }
11182882Svi117747 
11192882Svi117747 /*
11202882Svi117747  * Don't delete, just take it out of the hash
11212882Svi117747  */
11222882Svi117747 boolean_t
11232882Svi117747 sip_dialog_dontfree(void *obj, void *hindex, int *found)
11242882Svi117747 {
11252882Svi117747 	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
11262882Svi117747 
11272882Svi117747 	*found = 0;
11282882Svi117747 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
11292882Svi117747 	if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id))
11302882Svi117747 	    == 0) {
11312882Svi117747 		*found = 1;
11322882Svi117747 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
11332882Svi117747 		return (B_TRUE);
11342882Svi117747 	}
11352882Svi117747 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
11362882Svi117747 	return (B_FALSE);
11372882Svi117747 }
11382882Svi117747 
11392882Svi117747 /*
11402882Svi117747  * Free resources associated with the dialog, the object will be removed
11412882Svi117747  * from the hash list by sip_hash_delete.
11422882Svi117747  */
11432882Svi117747 boolean_t
11442882Svi117747 sip_dialog_free(void *obj, void *hindex, int *found)
11452882Svi117747 {
11462882Svi117747 	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
11472882Svi117747 
11482882Svi117747 	*found = 0;
11492882Svi117747 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
11502882Svi117747 	if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id))
11512882Svi117747 	    == 0) {
11522882Svi117747 		*found = 1;
11532882Svi117747 		assert(dialog->sip_dlg_state == SIP_DLG_DESTROYED);
11542882Svi117747 		if (dialog->sip_dlg_ref_cnt != 0) {
11552882Svi117747 			(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
11562882Svi117747 			return (B_FALSE);
11572882Svi117747 		}
11582882Svi117747 		sip_release_dialog_res(dialog);
11592882Svi117747 		return (B_TRUE);
11602882Svi117747 	}
11612882Svi117747 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
11622882Svi117747 	return (B_FALSE);
11632882Svi117747 }
11642882Svi117747 
11652882Svi117747 /*
11662882Svi117747  * The UAS will receive the request from the transaction layer.  If the
11672882Svi117747  * request has a tag in the To header field, the UAS core computes the
11682882Svi117747  * dialog identifier corresponding to the request and compares it with
11692882Svi117747  * existing dialogs.  If there is a match, this is a mid-dialog request.
11702882Svi117747  */
11712882Svi117747 sip_dialog_t
11722882Svi117747 sip_dialog_find(_sip_msg_t *sip_msg)
11732882Svi117747 {
11742882Svi117747 	const sip_str_t	*localtag;
11752882Svi117747 	const sip_str_t	*remtag;
11762882Svi117747 	const sip_str_t	*callid;
11772882Svi117747 	uint16_t	digest[8];
11782882Svi117747 	_sip_dialog_t	*dialog;
11792882Svi117747 	boolean_t	is_request;
11802882Svi117747 	int		error;
11812882Svi117747 
11822882Svi117747 	is_request = sip_msg_is_request((sip_msg_t)sip_msg, &error);
11832882Svi117747 	if (error != 0)
11842882Svi117747 		return (NULL);
11852882Svi117747 	if (is_request) {
11862882Svi117747 		localtag = sip_get_to_tag((sip_msg_t)sip_msg, &error);
11872882Svi117747 		if (error == 0)
11882882Svi117747 			remtag = sip_get_from_tag((sip_msg_t)sip_msg, &error);
11892882Svi117747 	} else {
11902882Svi117747 		remtag = sip_get_to_tag((sip_msg_t)sip_msg, &error);
11912882Svi117747 		if (error == 0)
11922882Svi117747 			localtag = sip_get_from_tag((sip_msg_t)sip_msg, &error);
11932882Svi117747 	}
11942882Svi117747 	if (error != 0)
11952882Svi117747 		return (NULL);
11962882Svi117747 	callid = sip_get_callid((sip_msg_t)sip_msg, &error);
11972882Svi117747 	if (error != 0 || remtag == NULL || localtag == NULL ||
11982882Svi117747 	    callid == NULL) {
11992882Svi117747 		return (NULL);
12002882Svi117747 	}
12012882Svi117747 	sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len,
12022882Svi117747 	    remtag->sip_str_ptr, remtag->sip_str_len,
12032882Svi117747 	    callid->sip_str_ptr, callid->sip_str_len,
12042882Svi117747 	    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest);
12052882Svi117747 
12062882Svi117747 	dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_hash,
12072882Svi117747 	    (void *)digest, SIP_DIGEST_TO_HASH(digest), sip_dialog_match);
12082882Svi117747 	if (dialog == NULL) {
12092882Svi117747 		sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len,
12102882Svi117747 		    NULL, 0, callid->sip_str_ptr, callid->sip_str_len,
12112882Svi117747 		    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest);
12122882Svi117747 		dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_phash,
12132882Svi117747 		    (void *)digest, SIP_DIGEST_TO_HASH(digest),
12142882Svi117747 		    sip_dialog_match);
12152882Svi117747 	}
12162882Svi117747 	return ((sip_dialog_t)dialog);
12172882Svi117747 }
12182882Svi117747 
12192882Svi117747 /*
12202882Svi117747  * We keep this partial dialog for the duration of the INVITE
12212882Svi117747  * transaction timeout duration, i.e. Timer B.
12222882Svi117747  */
12232882Svi117747 void
12242882Svi117747 sip_dlg_self_destruct(void *args)
12252882Svi117747 {
12262882Svi117747 	sip_dialog_timer_obj_t	*tim_obj = (sip_dialog_timer_obj_t *)args;
12272882Svi117747 	_sip_dialog_t		*dialog = (_sip_dialog_t *)tim_obj->dialog;
12282882Svi117747 	int			index;
12292882Svi117747 
12302882Svi117747 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
12312882Svi117747 	assert(dialog->sip_dlg_state == SIP_DLG_NEW);
12322882Svi117747 	dialog->sip_dlg_state = SIP_DLG_DESTROYED;
12332882Svi117747 	if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
12342882Svi117747 		index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id);
12352882Svi117747 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
12362882Svi117747 		sip_hash_delete(sip_dialog_phash, (void *)dialog->sip_dlg_id,
12372882Svi117747 		    index, sip_dialog_dontfree);
12382882Svi117747 	} else {
12392882Svi117747 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
12402882Svi117747 	}
12412882Svi117747 	if (tim_obj->func != NULL)
12422882Svi117747 		tim_obj->func(dialog, NULL, NULL);
12432882Svi117747 	free(tim_obj);
12442882Svi117747 	SIP_DLG_REFCNT_DECR(dialog);
12452882Svi117747 }
12462882Svi117747 
12472882Svi117747 /*
12482882Svi117747  * Terminate a dialog
12492882Svi117747  */
12502882Svi117747 void
12512882Svi117747 sip_dialog_terminate(_sip_dialog_t *dialog, sip_msg_t sip_msg)
12522882Svi117747 {
12532882Svi117747 	int	prev_state;
12542882Svi117747 
12552882Svi117747 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
12562882Svi117747 	prev_state = dialog->sip_dlg_state;
12572882Svi117747 	dialog->sip_dlg_state = SIP_DLG_DESTROYED;
12582882Svi117747 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
12592882Svi117747 	if (sip_dlg_ulp_state_cb != NULL) {
12602882Svi117747 		sip_dlg_ulp_state_cb((sip_dialog_t)dialog, sip_msg, prev_state,
12612882Svi117747 		    dialog->sip_dlg_state);
12622882Svi117747 	}
12632882Svi117747 	SIP_DLG_REFCNT_DECR(dialog);
12642882Svi117747 }
12652882Svi117747 
12662882Svi117747 /*
12672882Svi117747  * Delete a dialog
12682882Svi117747  */
12692882Svi117747 void
12702882Svi117747 sip_dialog_delete(_sip_dialog_t *dialog)
12712882Svi117747 {
12722882Svi117747 	int	index;
12732882Svi117747 
12742882Svi117747 	/*
12752882Svi117747 	 * partial dialog, not in the hash table
12762882Svi117747 	 */
12772882Svi117747 	if (dialog->sip_dlg_local_uri_tag == NULL ||
12782882Svi117747 	    dialog->sip_dlg_remote_uri_tag == NULL) {
12792882Svi117747 		/*
12802882Svi117747 		 * Cancel the partial dialog timer
12812882Svi117747 		 */
12822882Svi117747 		if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
12832882Svi117747 			SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
12842882Svi117747 		sip_release_dialog_res(dialog);
12852882Svi117747 		return;
12862882Svi117747 	}
12872882Svi117747 	index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id);
12882882Svi117747 	sip_hash_delete(sip_dialog_hash, (void *)dialog->sip_dlg_id, index,
12892882Svi117747 	    sip_dialog_free);
12902882Svi117747 }
12912882Svi117747 
12922882Svi117747 /*
12932882Svi117747  * Get the remote target from the CONTACT header from the 200 OK response
12942882Svi117747  */
12952882Svi117747 static boolean_t
12962882Svi117747 sip_get_rtarg(_sip_dialog_t *dialog, _sip_msg_t *sip_msg)
12972882Svi117747 {
12982882Svi117747 	sip_header_t	chdr;
12992882Svi117747 
13002882Svi117747 	if (dialog->sip_dlg_remote_target != NULL)
13012882Svi117747 		return (B_TRUE);
13022882Svi117747 
13032882Svi117747 	(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
13042882Svi117747 	chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
13052882Svi117747 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
13062882Svi117747 	if (chdr == NULL)
13072882Svi117747 		return (B_FALSE);
13082882Svi117747 	if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) == NULL)
13092882Svi117747 		return (B_FALSE);
13102882Svi117747 
13112882Svi117747 	return (B_TRUE);
13122882Svi117747 }
13132882Svi117747 
13142882Svi117747 /*
13152882Svi117747  * Process an incoming request/response
13162882Svi117747  */
13172882Svi117747 /* ARGSUSED */
13182882Svi117747 int
13192882Svi117747 sip_dialog_process(_sip_msg_t *sip_msg, sip_dialog_t *sip_dialog)
13202882Svi117747 {
13212882Svi117747 	boolean_t	request;
13222882Svi117747 	_sip_dialog_t	*_dialog;
13232882Svi117747 	int		error;
13242882Svi117747 
13252882Svi117747 	request = sip_msg_is_request((sip_msg_t)sip_msg, &error);
13262882Svi117747 	if (error != 0)
13272882Svi117747 		return (EINVAL);
13282882Svi117747 	_dialog = (_sip_dialog_t *)*sip_dialog;
13292882Svi117747 	if (request) {
13302882Svi117747 		uint32_t	cseq;
13312882Svi117747 		sip_method_t	method;
13322882Svi117747 
13332882Svi117747 		cseq = sip_get_callseq_num((sip_msg_t)sip_msg, &error);
13342882Svi117747 		if (error != 0)
13352882Svi117747 			return (EINVAL);
13362882Svi117747 		method = sip_get_callseq_method((sip_msg_t)sip_msg, &error);
13372882Svi117747 		if (error != 0)
13382882Svi117747 			return (EINVAL);
13392882Svi117747 		if (sip_get_request_method((sip_msg_t)sip_msg, &error) !=
13402882Svi117747 		    method) {
13412882Svi117747 			return (EINVAL);
13422882Svi117747 		}
13432882Svi117747 		(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
13442882Svi117747 		/*
13452882Svi117747 		 * Requests that do not change in any way the state
13462882Svi117747 		 * of a dialog may be received within a dialog.
13472882Svi117747 		 * They are processed as if they had been received
13482882Svi117747 		 * outside the dialog.
13492882Svi117747 		 * For dialogs that have been established with an
13502882Svi117747 		 * INVITE, the only target refresh request defined is
13512882Svi117747 		 * re-INVITE.
13522882Svi117747 		 */
13532882Svi117747 		if (_dialog->sip_dlg_method == INVITE &&
13542882Svi117747 		    method == INVITE && _dialog->sip_dlg_remote_cseq != 0 &&
13552882Svi117747 		    SIP_CSEQ_LT(cseq, _dialog->sip_dlg_remote_cseq)) {
13562882Svi117747 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
13572882Svi117747 			return (EPROTO);
13582882Svi117747 		}
13592882Svi117747 		/*
13602882Svi117747 		 * Target-Refresh request
13612882Svi117747 		 */
13622882Svi117747 		if (_dialog->sip_dlg_method == INVITE && method == INVITE) {
13632882Svi117747 			sip_header_t	chdr;
13642882Svi117747 			sip_header_t	nchdr;
13652882Svi117747 
13662882Svi117747 			(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
13672882Svi117747 			chdr = sip_search_for_header(sip_msg, SIP_CONTACT,
13682882Svi117747 			    NULL);
13692882Svi117747 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
13702882Svi117747 			if (chdr != NULL &&
13712882Svi117747 			    (nchdr = sip_dup_header(chdr)) != NULL) {
13722882Svi117747 				if (_dialog->sip_dlg_remote_target != NULL) {
13732882Svi117747 					sip_free_header(
13742882Svi117747 					    _dialog->sip_dlg_remote_target);
13752882Svi117747 				}
13762882Svi117747 				_dialog->sip_dlg_remote_target = nchdr;
13772882Svi117747 			}
13782882Svi117747 		}
13792882Svi117747 		_dialog->sip_dlg_remote_cseq = cseq;
13802882Svi117747 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
13812882Svi117747 	} else {
13822882Svi117747 		int		resp_code;
13832882Svi117747 		sip_method_t	method;
13842882Svi117747 		int		error;
13852882Svi117747 
13862882Svi117747 		resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
13872882Svi117747 		if (error == 0) {
13882882Svi117747 			method = sip_get_callseq_method((sip_msg_t)sip_msg,
13892882Svi117747 			    &error);
13902882Svi117747 		}
13912882Svi117747 		if (error != 0)
13922882Svi117747 			return (error);
13932882Svi117747 
13942882Svi117747 		(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
1395*4641Sgm209912 		if (_dialog->sip_dlg_state == SIP_DLG_DESTROYED) {
1396*4641Sgm209912 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
1397*4641Sgm209912 			return (0);
1398*4641Sgm209912 		}
13992882Svi117747 		assert(_dialog->sip_dlg_state == SIP_DLG_EARLY ||
14002882Svi117747 		    _dialog->sip_dlg_state == SIP_DLG_CONFIRMED);
14012882Svi117747 		/*
14022882Svi117747 		 * Let the user delete the dialog if it is not a 1XX/2XX resp
14032882Svi117747 		 * for an early INVITE dialog.
14042882Svi117747 		 */
14052882Svi117747 		if (SIP_OK_RESP(resp_code)) {
14062882Svi117747 			if (method == INVITE) {
14072882Svi117747 				if (!sip_get_rtarg(_dialog, sip_msg)) {
14082882Svi117747 					(void) pthread_mutex_unlock(
14092882Svi117747 					    &_dialog->sip_dlg_mutex);
14102882Svi117747 					if (sip_ulp_dlg_del_cb != NULL) {
14112882Svi117747 						sip_ulp_dlg_del_cb(
14122882Svi117747 						    (sip_dialog_t)_dialog,
14132882Svi117747 						    (sip_msg_t)sip_msg, NULL);
14142882Svi117747 					}
14152882Svi117747 					sip_dialog_terminate(_dialog,
14162882Svi117747 					    (sip_msg_t)sip_msg);
14172882Svi117747 					return (0);
14182882Svi117747 				}
14192882Svi117747 				if (_dialog->sip_dlg_state == SIP_DLG_EARLY) {
14202882Svi117747 					_dialog->sip_dlg_state =
14212882Svi117747 					    SIP_DLG_CONFIRMED;
14222882Svi117747 					(void) pthread_mutex_unlock(
14232882Svi117747 					    &_dialog->sip_dlg_mutex);
14242882Svi117747 					(void) sip_dlg_recompute_rset(_dialog,
14252882Svi117747 					    sip_msg, SIP_UAC_DIALOG);
14262882Svi117747 					if (sip_dlg_ulp_state_cb != NULL) {
14272882Svi117747 						sip_dlg_ulp_state_cb(
14282882Svi117747 						    (sip_dialog_t)_dialog,
14292882Svi117747 						    sip_msg, SIP_DLG_EARLY,
14302882Svi117747 						    _dialog->sip_dlg_state);
14312882Svi117747 					}
14322882Svi117747 					return (0);
14332882Svi117747 				}
14342882Svi117747 			}
14352882Svi117747 		}
14362882Svi117747 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
14372882Svi117747 	}
14382882Svi117747 	return (0);
14392882Svi117747 }
14402882Svi117747 
14412882Svi117747 /*
14422882Svi117747  * Copy partial dialog to create a complete dialog
14432882Svi117747  */
14442882Svi117747 _sip_dialog_t *
14452882Svi117747 sip_copy_partial_dialog(_sip_dialog_t *dialog)
14462882Svi117747 {
14472882Svi117747 	_sip_dialog_t	*new_dlg;
14482882Svi117747 
14492882Svi117747 	new_dlg =  calloc(1, sizeof (_sip_dialog_t));
14502882Svi117747 	if (new_dlg == NULL)
14512882Svi117747 		return (NULL);
14522882Svi117747 	if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) {
14532882Svi117747 		new_dlg->sip_dlg_req_uri.sip_str_ptr =
14542882Svi117747 		    malloc(dialog->sip_dlg_req_uri.sip_str_len + 1);
14552882Svi117747 		if (new_dlg->sip_dlg_req_uri.sip_str_ptr == NULL) {
14562882Svi117747 			free(new_dlg);
14572882Svi117747 			return (NULL);
14582882Svi117747 		}
14592882Svi117747 		(void) strncpy(new_dlg->sip_dlg_req_uri.sip_str_ptr,
14602882Svi117747 		    dialog->sip_dlg_req_uri.sip_str_ptr,
14612882Svi117747 		    dialog->sip_dlg_req_uri.sip_str_len);
14622882Svi117747 		new_dlg->sip_dlg_req_uri.sip_str_ptr[
14632882Svi117747 		    dialog->sip_dlg_req_uri.sip_str_len] = '\0';
14642882Svi117747 		new_dlg->sip_dlg_req_uri.sip_str_len =
14652882Svi117747 		    dialog->sip_dlg_req_uri.sip_str_len;
14662882Svi117747 	}
14672882Svi117747 	if (dialog->sip_dlg_route_set != NULL) {
14682882Svi117747 		assert(dialog->sip_dlg_rset.sip_str_ptr != NULL);
14692882Svi117747 		new_dlg->sip_dlg_rset.sip_str_ptr =
14702882Svi117747 		    malloc(dialog->sip_dlg_rset.sip_str_len + 1);
14712882Svi117747 		if (new_dlg->sip_dlg_rset.sip_str_ptr == NULL) {
14722882Svi117747 			if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL)
14732882Svi117747 				free(new_dlg->sip_dlg_req_uri.sip_str_ptr);
14742882Svi117747 			free(new_dlg);
14752882Svi117747 			return (NULL);
14762882Svi117747 		}
14772882Svi117747 		(void) strncpy(new_dlg->sip_dlg_rset.sip_str_ptr,
14782882Svi117747 		    dialog->sip_dlg_rset.sip_str_ptr,
14792882Svi117747 		    dialog->sip_dlg_rset.sip_str_len);
14802882Svi117747 		new_dlg->sip_dlg_rset.sip_str_ptr[
14812882Svi117747 		    dialog->sip_dlg_rset.sip_str_len] = '\0';
14822882Svi117747 		new_dlg->sip_dlg_rset.sip_str_len =
14832882Svi117747 		    dialog->sip_dlg_rset.sip_str_len;
14842882Svi117747 
14852882Svi117747 		new_dlg->sip_dlg_route_set =
14862882Svi117747 		    sip_dup_header(dialog->sip_dlg_route_set);
14872882Svi117747 		if (new_dlg->sip_dlg_route_set == NULL) {
14882882Svi117747 			free(new_dlg->sip_dlg_rset.sip_str_ptr);
14892882Svi117747 			if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL)
14902882Svi117747 				free(new_dlg->sip_dlg_req_uri.sip_str_ptr);
14912882Svi117747 			free(new_dlg);
14922882Svi117747 			return (NULL);
14932882Svi117747 		}
14942882Svi117747 	}
14952882Svi117747 	if ((new_dlg->sip_dlg_local_uri_tag =
14962882Svi117747 	    sip_dup_header(dialog->sip_dlg_local_uri_tag)) == NULL ||
14972882Svi117747 	    (new_dlg->sip_dlg_remote_target =
14982882Svi117747 	    sip_dup_header(dialog->sip_dlg_remote_target)) == NULL ||
14992882Svi117747 	    (new_dlg->sip_dlg_call_id =
15002882Svi117747 	    sip_dup_header(dialog->sip_dlg_call_id)) == NULL) {
15012882Svi117747 		sip_release_dialog_res(new_dlg);
15022882Svi117747 		return (NULL);
15032882Svi117747 	}
15042882Svi117747 	if (dialog->sip_dlg_event != NULL) {
15052882Svi117747 		new_dlg->sip_dlg_event = sip_dup_header(dialog->sip_dlg_event);
15062882Svi117747 		if (new_dlg->sip_dlg_event == NULL) {
15072882Svi117747 			sip_release_dialog_res(new_dlg);
15082882Svi117747 			return (NULL);
15092882Svi117747 		}
15102882Svi117747 	}
15112882Svi117747 	new_dlg->sip_dlg_local_cseq = dialog->sip_dlg_local_cseq;
15122882Svi117747 	new_dlg->sip_dlg_type = dialog->sip_dlg_type;
15132882Svi117747 	new_dlg->sip_dlg_on_fork = B_FALSE;
15142882Svi117747 	(void) pthread_mutex_init(&new_dlg->sip_dlg_mutex, NULL);
15152882Svi117747 
15162882Svi117747 	return (new_dlg);
15172882Svi117747 }
15182882Svi117747 
15192882Svi117747 /*
15202882Svi117747  * Update the dialog using the response
15212882Svi117747  */
15222882Svi117747 sip_dialog_t
15232882Svi117747 sip_update_dialog(sip_dialog_t dialog, _sip_msg_t *sip_msg)
15242882Svi117747 {
15252882Svi117747 	_sip_dialog_t	*_dialog;
15262882Svi117747 	boolean_t	isreq;
15272882Svi117747 	sip_method_t	method;
15282882Svi117747 	int		resp_code = 0;
15292882Svi117747 	int		prev_state;
15302882Svi117747 	boolean_t	decr_ref = B_FALSE;
15312882Svi117747 	int		error;
15322882Svi117747 
15332882Svi117747 	isreq = sip_msg_is_request((sip_msg_t)sip_msg, &error);
15342882Svi117747 	if (error != 0)
15352882Svi117747 		return (dialog);
15362882Svi117747 	_dialog = (_sip_dialog_t *)dialog;
15372882Svi117747 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
15382882Svi117747 	if (isreq) {
15392882Svi117747 		method = sip_get_request_method((sip_msg_t)sip_msg, &error);
15402882Svi117747 		if (error != 0 || _dialog->sip_dlg_method != SUBSCRIBE ||
15412882Svi117747 		    method != NOTIFY) {
15422882Svi117747 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
15432882Svi117747 			return (dialog);
15442882Svi117747 		}
15452882Svi117747 	} else {
15462882Svi117747 		resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
15472882Svi117747 		if (error != 0) {
15482882Svi117747 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
15492882Svi117747 			return (dialog);
15502882Svi117747 		}
15512882Svi117747 	}
15522882Svi117747 	prev_state = _dialog->sip_dlg_state;
15532882Svi117747 	if (_dialog->sip_dlg_state == SIP_DLG_CONFIRMED) {
15542882Svi117747 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
15552882Svi117747 	} else if (_dialog->sip_dlg_state == SIP_DLG_EARLY) {
15562882Svi117747 		/*
15572882Svi117747 		 * Let the user delete the dialog if it is not a 1XX/2XX resp
15582882Svi117747 		 * for an early dialog.
15592882Svi117747 		 */
15602882Svi117747 		assert(!isreq);
15612882Svi117747 		if (SIP_OK_RESP(resp_code)) {
15622882Svi117747 			_dialog->sip_dlg_state = SIP_DLG_CONFIRMED;
15632882Svi117747 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
15642882Svi117747 			(void) sip_dlg_recompute_rset(_dialog, sip_msg,
15652882Svi117747 			    SIP_UAS_DIALOG);
15662882Svi117747 			if (sip_dlg_ulp_state_cb != NULL) {
15672882Svi117747 				sip_dlg_ulp_state_cb(dialog, (sip_msg_t)sip_msg,
15682882Svi117747 				    prev_state, dialog->sip_dlg_state);
15692882Svi117747 			}
15702882Svi117747 		} else {
15712882Svi117747 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
15722882Svi117747 		}
15732882Svi117747 	} else if (_dialog->sip_dlg_state == SIP_DLG_NEW) {
15742882Svi117747 		if (!isreq && _dialog->sip_dlg_method == SUBSCRIBE &&
15752882Svi117747 		    SIP_PROVISIONAL_RESP(resp_code)) {
15762882Svi117747 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
15772882Svi117747 			return (dialog);
15782882Svi117747 		}
15792882Svi117747 		if (_dialog->sip_dlg_type == SIP_UAC_DIALOG) {
15802882Svi117747 			_sip_dialog_t	*new_dlg;
15812882Svi117747 
15822882Svi117747 			if (_dialog->sip_dlg_on_fork) {
15832882Svi117747 				new_dlg = sip_copy_partial_dialog(_dialog);
15842882Svi117747 				if (new_dlg == NULL) {
15852882Svi117747 					(void) pthread_mutex_unlock(
15862882Svi117747 					    &_dialog->sip_dlg_mutex);
15872882Svi117747 					return (dialog);
15882882Svi117747 				}
15892882Svi117747 				/*
15902882Svi117747 				 * This decr/incr dance is because the caller
15912882Svi117747 				 * has incremented the ref on the partial
15922882Svi117747 				 * dialog, we release it here and incr the
15932882Svi117747 				 * ref on the new dialog which will be
15942882Svi117747 				 * released by the caller.
15952882Svi117747 				 */
15962882Svi117747 				(void) pthread_mutex_unlock(
15972882Svi117747 				    &_dialog->sip_dlg_mutex);
15982882Svi117747 				SIP_DLG_REFCNT_DECR(_dialog);
15992882Svi117747 				_dialog = new_dlg;
16002882Svi117747 				(void) pthread_mutex_lock(
16012882Svi117747 				    &_dialog->sip_dlg_mutex);
16022882Svi117747 				SIP_DLG_REFCNT_INCR(_dialog);
16032882Svi117747 			} else {
16042882Svi117747 				int	index;
16052882Svi117747 
16062882Svi117747 				/*
16072882Svi117747 				 * take it out of the list so that further
16082882Svi117747 				 * responses will not result in a dialog.
16092882Svi117747 				 * We will have an extra refcount when we
16102882Svi117747 				 * come back from sip_complete_dialog(), i.e.
16112882Svi117747 				 * one when the partial dialog was created -
16122882Svi117747 				 * in sip_seed_dialog(), one held by the caller
16132882Svi117747 				 * and one that will be added by
16142882Svi117747 				 * sip_complete_dialog(). We need to release
16152882Svi117747 				 * the one added by the sip_seed_dialog(),
16162882Svi117747 				 * since the one in sip_complete_dialog()
16172882Svi117747 				 * is for the same purpose.
16182882Svi117747 				 */
16192882Svi117747 				if (SIP_IS_TIMER_RUNNING(
16202882Svi117747 				    _dialog->sip_dlg_timer)) {
16212882Svi117747 					SIP_CANCEL_TIMER(
16222882Svi117747 					    _dialog->sip_dlg_timer);
16232882Svi117747 				}
16242882Svi117747 				index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id);
16252882Svi117747 				(void) pthread_mutex_unlock(
16262882Svi117747 				    &_dialog->sip_dlg_mutex);
16272882Svi117747 				sip_hash_delete(sip_dialog_phash,
16282882Svi117747 				    (void *)_dialog->sip_dlg_id,
16292882Svi117747 				    index, sip_dialog_dontfree);
16302882Svi117747 				(void) pthread_mutex_lock(
16312882Svi117747 				    &_dialog->sip_dlg_mutex);
16322882Svi117747 				decr_ref = B_TRUE;
16332882Svi117747 			}
16342882Svi117747 		} else {
16352882Svi117747 			decr_ref = B_TRUE;
16362882Svi117747 		}
16372882Svi117747 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
16382882Svi117747 		if ((dialog = sip_complete_dialog(sip_msg, _dialog)) ==
16392882Svi117747 		    NULL) {
16403439Svi117747 			if (_dialog->sip_dlg_type == SIP_UAC_DIALOG && decr_ref)
16413439Svi117747 				SIP_DLG_REFCNT_DECR(_dialog);
16422882Svi117747 			return (NULL);
16432882Svi117747 		}
16442882Svi117747 		if (decr_ref)
16452882Svi117747 			SIP_DLG_REFCNT_DECR(_dialog);
16462882Svi117747 	} else {
16472882Svi117747 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
16482882Svi117747 	}
16492882Svi117747 	return (dialog);
16502882Svi117747 }
16512882Svi117747 
16522882Svi117747 /*
16532882Svi117747  * Initialize the hash table
16542882Svi117747  */
16552882Svi117747 void
16562882Svi117747 sip_dialog_init(void (*ulp_dlg_del) (sip_dialog_t, sip_msg_t, void *),
16572882Svi117747     void (*ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int))
16582882Svi117747 {
16592882Svi117747 	int	cnt;
16602882Svi117747 
16612882Svi117747 	for (cnt = 0; cnt < SIP_HASH_SZ; cnt++) {
16622882Svi117747 		sip_dialog_hash[cnt].hash_count = 0;
16632882Svi117747 		sip_dialog_hash[cnt].hash_head = NULL;
16642882Svi117747 		sip_dialog_hash[cnt].hash_tail = NULL;
16652882Svi117747 		(void) pthread_mutex_init(
16662882Svi117747 		    &sip_dialog_hash[cnt].sip_hash_mutex, NULL);
16672882Svi117747 		sip_dialog_phash[cnt].hash_count = 0;
16682882Svi117747 		sip_dialog_phash[cnt].hash_head = NULL;
16692882Svi117747 		sip_dialog_phash[cnt].hash_tail = NULL;
16702882Svi117747 		(void) pthread_mutex_init(
16712882Svi117747 		    &sip_dialog_phash[cnt].sip_hash_mutex, NULL);
16722882Svi117747 	}
16732882Svi117747 	if (ulp_dlg_del != NULL)
16742882Svi117747 		sip_ulp_dlg_del_cb = ulp_dlg_del;
16752882Svi117747 
16762882Svi117747 	if (ulp_state_cb != NULL)
16772882Svi117747 		sip_dlg_ulp_state_cb = ulp_state_cb;
16782882Svi117747 }
1679