xref: /illumos-gate/usr/src/lib/libsip/common/sip_dialog.c (revision 943efbc33954e332318b6365bf27037c05bff72c)
140cb5e5dSvi /*
240cb5e5dSvi  * CDDL HEADER START
340cb5e5dSvi  *
440cb5e5dSvi  * The contents of this file are subject to the terms of the
540cb5e5dSvi  * Common Development and Distribution License (the "License").
640cb5e5dSvi  * You may not use this file except in compliance with the License.
740cb5e5dSvi  *
840cb5e5dSvi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
940cb5e5dSvi  * or http://www.opensolaris.org/os/licensing.
1040cb5e5dSvi  * See the License for the specific language governing permissions
1140cb5e5dSvi  * and limitations under the License.
1240cb5e5dSvi  *
1340cb5e5dSvi  * When distributing Covered Code, include this CDDL HEADER in each
1440cb5e5dSvi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1540cb5e5dSvi  * If applicable, add the following below this CDDL HEADER, with the
1640cb5e5dSvi  * fields enclosed by brackets "[]" replaced with your own identifying
1740cb5e5dSvi  * information: Portions Copyright [yyyy] [name of copyright owner]
1840cb5e5dSvi  *
1940cb5e5dSvi  * CDDL HEADER END
2040cb5e5dSvi  */
2140cb5e5dSvi 
2240cb5e5dSvi /*
23*943efbc3Sgm  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2440cb5e5dSvi  * Use is subject to license terms.
2540cb5e5dSvi  */
2640cb5e5dSvi 
2740cb5e5dSvi #pragma ident	"%Z%%M%	%I%	%E% SMI"
2840cb5e5dSvi 
292c2c4183Svi #include <stdio.h>
302c2c4183Svi #include <stdlib.h>
312c2c4183Svi #include <assert.h>
322c2c4183Svi #include <errno.h>
332c2c4183Svi #include <pthread.h>
342c2c4183Svi #include <strings.h>
352c2c4183Svi #include <sip.h>
362c2c4183Svi 
3740cb5e5dSvi #include "sip_msg.h"
3840cb5e5dSvi #include "sip_miscdefs.h"
392c2c4183Svi #include "sip_hash.h"
4040cb5e5dSvi #include "sip_dialog.h"
4140cb5e5dSvi #include "sip_parse_generic.h"
4240cb5e5dSvi 
4340cb5e5dSvi #define	SIP_DLG_XCHG_FROM	0
4440cb5e5dSvi #define	SIP_DLG_XCHG_TO		1
4540cb5e5dSvi 
4640cb5e5dSvi /*
4740cb5e5dSvi  * Dialog state change callback function
4840cb5e5dSvi  */
4940cb5e5dSvi void (*sip_dlg_ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int) = NULL;
5040cb5e5dSvi void (*sip_ulp_dlg_del_cb)(sip_dialog_t, sip_msg_t, void *) = NULL;
5140cb5e5dSvi 
5240cb5e5dSvi boolean_t	sip_incomplete_dialog(sip_dialog_t);
5340cb5e5dSvi 
5440cb5e5dSvi /*
5540cb5e5dSvi  * Exchange From/To header
5640cb5e5dSvi  */
5740cb5e5dSvi _sip_header_t *sip_dlg_xchg_from_to(sip_msg_t, int);
5840cb5e5dSvi 
5940cb5e5dSvi /*
6040cb5e5dSvi  * Complete dialog hash table
6140cb5e5dSvi  */
6240cb5e5dSvi sip_hash_t sip_dialog_hash[SIP_HASH_SZ];
6340cb5e5dSvi 
6440cb5e5dSvi /*
6540cb5e5dSvi  * Partial dialog hash table
6640cb5e5dSvi  */
6740cb5e5dSvi sip_hash_t sip_dialog_phash[SIP_HASH_SZ];
6840cb5e5dSvi 
6940cb5e5dSvi /*
7040cb5e5dSvi  * Route set structure
7140cb5e5dSvi  */
7240cb5e5dSvi typedef struct sip_dlg_route_set_s  {
7340cb5e5dSvi 	char		*sip_dlg_route;
7440cb5e5dSvi 	sip_str_t	sip_dlg_ruri;
7540cb5e5dSvi 	boolean_t	sip_dlg_route_lr;
7640cb5e5dSvi 	struct sip_dlg_route_set_s *sip_dlg_route_next;
7740cb5e5dSvi }sip_dlg_route_set_t;
7840cb5e5dSvi 
7940cb5e5dSvi sip_dialog_t		sip_seed_dialog(sip_conn_object_t, _sip_msg_t *,
8040cb5e5dSvi 			    boolean_t, int);
8140cb5e5dSvi sip_dialog_t		sip_complete_dialog(_sip_msg_t *, _sip_dialog_t *);
8240cb5e5dSvi int			sip_dialog_process(_sip_msg_t *, sip_dialog_t *);
8340cb5e5dSvi void			sip_dialog_delete(_sip_dialog_t *);
8440cb5e5dSvi void			sip_dialog_init();
8540cb5e5dSvi sip_dialog_t		sip_dialog_find(_sip_msg_t *);
8640cb5e5dSvi boolean_t		sip_dialog_match(void *, void *);
8740cb5e5dSvi boolean_t		sip_dialog_free(void *, void *, int *);
8840cb5e5dSvi sip_dialog_t		sip_update_dialog(sip_dialog_t, _sip_msg_t *);
8940cb5e5dSvi char			*sip_dialog_req_uri(sip_dialog_t);
9040cb5e5dSvi 
9140cb5e5dSvi static void		sip_release_dialog_res(_sip_dialog_t *);
9240cb5e5dSvi void			sip_dlg_self_destruct(void *);
9340cb5e5dSvi static int		sip_dialog_get_route_set(_sip_dialog_t *, _sip_msg_t *,
9440cb5e5dSvi 			    int);
9540cb5e5dSvi static void		sip_dialog_free_rset(sip_dlg_route_set_t *);
9640cb5e5dSvi 
9740cb5e5dSvi /*
9840cb5e5dSvi  * Timer object for partial dialogs
9940cb5e5dSvi  */
10040cb5e5dSvi typedef struct sip_dialog_timer_obj_s {
10140cb5e5dSvi 	_sip_dialog_t	*dialog;
10240cb5e5dSvi 	void		(*func)(sip_dialog_t, sip_msg_t, void *);
10340cb5e5dSvi } sip_dialog_timer_obj_t;
10440cb5e5dSvi 
10540cb5e5dSvi /*
10640cb5e5dSvi  * To avoid duplication all over the place
10740cb5e5dSvi  */
10840cb5e5dSvi static void
10940cb5e5dSvi sip_release_dialog_res(_sip_dialog_t *dialog)
11040cb5e5dSvi {
111*943efbc3Sgm 	int			count = 0;
112*943efbc3Sgm 	sip_msg_chain_t		*msg_chain;
113*943efbc3Sgm 	sip_msg_chain_t		*nmsg_chain;
11440cb5e5dSvi 
115*943efbc3Sgm 	if (dialog->sip_dlg_ref_cnt != 0) {
116*943efbc3Sgm 		sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
117*943efbc3Sgm 		    SIP_ASSERT_ERROR, __FILE__,  __LINE__);
118*943efbc3Sgm 	}
11940cb5e5dSvi 	assert(dialog->sip_dlg_ref_cnt == 0);
12040cb5e5dSvi 	if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
12140cb5e5dSvi 		SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
12240cb5e5dSvi 	if (dialog->sip_dlg_call_id != NULL)
12340cb5e5dSvi 		sip_free_header(dialog->sip_dlg_call_id);
12440cb5e5dSvi 	if (dialog->sip_dlg_local_uri_tag != NULL)
12540cb5e5dSvi 		sip_free_header(dialog->sip_dlg_local_uri_tag);
12640cb5e5dSvi 	if (dialog->sip_dlg_remote_uri_tag != NULL)
12740cb5e5dSvi 		sip_free_header(dialog->sip_dlg_remote_uri_tag);
12840cb5e5dSvi 	if (dialog->sip_dlg_remote_target != NULL)
12940cb5e5dSvi 		sip_free_header(dialog->sip_dlg_remote_target);
130d8a40387Sgm 	if (dialog->sip_dlg_local_contact != NULL)
131d8a40387Sgm 		sip_free_header(dialog->sip_dlg_local_contact);
132d8a40387Sgm 	if (dialog->sip_dlg_new_local_contact != NULL)
133d8a40387Sgm 		sip_free_header(dialog->sip_dlg_new_local_contact);
13440cb5e5dSvi 	if (dialog->sip_dlg_route_set != NULL)
13540cb5e5dSvi 		sip_free_header(dialog->sip_dlg_route_set);
13640cb5e5dSvi 	if (dialog->sip_dlg_event != NULL)
13740cb5e5dSvi 		sip_free_header(dialog->sip_dlg_event);
13840cb5e5dSvi 	if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) {
13940cb5e5dSvi 		free(dialog->sip_dlg_req_uri.sip_str_ptr);
14040cb5e5dSvi 		dialog->sip_dlg_req_uri.sip_str_ptr = NULL;
14140cb5e5dSvi 		dialog->sip_dlg_req_uri.sip_str_len = 0;
14240cb5e5dSvi 	}
14340cb5e5dSvi 	if (dialog->sip_dlg_rset.sip_str_ptr != NULL) {
14440cb5e5dSvi 		free(dialog->sip_dlg_rset.sip_str_ptr);
14540cb5e5dSvi 		dialog->sip_dlg_rset.sip_str_len = 0;
14640cb5e5dSvi 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
14740cb5e5dSvi 	}
148*943efbc3Sgm 	for (count = 0; count <= SIP_DLG_DESTROYED; count++) {
149*943efbc3Sgm 		msg_chain = dialog->sip_dlg_log[count].sip_msgs;
150*943efbc3Sgm 		while (msg_chain != NULL) {
151*943efbc3Sgm 			nmsg_chain = msg_chain->next;
152*943efbc3Sgm 			if (msg_chain->sip_msg != NULL)
153*943efbc3Sgm 				free(msg_chain->sip_msg);
154*943efbc3Sgm 			free(msg_chain);
155*943efbc3Sgm 			msg_chain = nmsg_chain;
156*943efbc3Sgm 		}
157*943efbc3Sgm 	}
15840cb5e5dSvi 	(void) pthread_mutex_destroy(&dialog->sip_dlg_mutex);
15940cb5e5dSvi 	free(dialog);
16040cb5e5dSvi }
16140cb5e5dSvi 
16240cb5e5dSvi /*
16340cb5e5dSvi  * Get the route information from the 'value' and add it to the route
16440cb5e5dSvi  * set.
16540cb5e5dSvi  */
16640cb5e5dSvi static sip_dlg_route_set_t *
16740cb5e5dSvi sip_add_route_to_set(sip_hdr_value_t *value)
16840cb5e5dSvi {
16940cb5e5dSvi 	int			vlen = 0;
17040cb5e5dSvi 	sip_dlg_route_set_t	*rset;
17140cb5e5dSvi 	char			*crlf;
17240cb5e5dSvi 	const sip_param_t	*uri_param;
17340cb5e5dSvi 	int			error;
17440cb5e5dSvi 
17540cb5e5dSvi 	rset = calloc(1, sizeof (*rset));
17640cb5e5dSvi 	if (rset == NULL)
17740cb5e5dSvi 		return (NULL);
17840cb5e5dSvi 	rset->sip_dlg_route_next = NULL;
17940cb5e5dSvi 	vlen = value->sip_value_end - value->sip_value_start;
18040cb5e5dSvi 
18140cb5e5dSvi 	/*
18240cb5e5dSvi 	 * check for CRLF
18340cb5e5dSvi 	 */
18440cb5e5dSvi 	crlf = value->sip_value_end - strlen(SIP_CRLF);
18540cb5e5dSvi 	while (crlf != NULL && strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) {
18640cb5e5dSvi 		vlen -= strlen(SIP_CRLF);
18740cb5e5dSvi 		crlf -= strlen(SIP_CRLF);
18840cb5e5dSvi 	}
18940cb5e5dSvi 	rset->sip_dlg_route = calloc(1, vlen + 1);
19040cb5e5dSvi 	if (rset->sip_dlg_route == NULL) {
19140cb5e5dSvi 		free(rset);
19240cb5e5dSvi 		return (NULL);
19340cb5e5dSvi 	}
19440cb5e5dSvi 	/*
19540cb5e5dSvi 	 * loose routing
19640cb5e5dSvi 	 */
19740cb5e5dSvi 	rset->sip_dlg_route_lr = B_FALSE;
19840cb5e5dSvi 	(void) strncpy(rset->sip_dlg_route, value->sip_value_start, vlen);
19940cb5e5dSvi 	rset->sip_dlg_ruri.sip_str_ptr = rset->sip_dlg_route +
20040cb5e5dSvi 	    (value->cftr_uri.sip_str_ptr - value->sip_value_start);
20140cb5e5dSvi 	rset->sip_dlg_ruri.sip_str_len = value->cftr_uri.sip_str_len;
20240cb5e5dSvi 	rset->sip_dlg_route[vlen] = '\0';
20340cb5e5dSvi 
20440cb5e5dSvi 	assert(value->sip_value_parsed_uri != NULL);
20540cb5e5dSvi 	/*
20640cb5e5dSvi 	 * Check if the 'lr' param is present for this route.
20740cb5e5dSvi 	 */
20840cb5e5dSvi 	uri_param = sip_get_uri_params(value->sip_value_parsed_uri, &error);
20940cb5e5dSvi 	if (error != 0) {
21040cb5e5dSvi 		free(rset->sip_dlg_route);
21140cb5e5dSvi 		free(rset);
21240cb5e5dSvi 		return (NULL);
21340cb5e5dSvi 	}
21440cb5e5dSvi 	if (uri_param != NULL) {
21540cb5e5dSvi 		rset->sip_dlg_route_lr = sip_is_param_present(uri_param, "lr",
21640cb5e5dSvi 		    strlen("lr"));
21740cb5e5dSvi 	}
21840cb5e5dSvi 	return (rset);
21940cb5e5dSvi }
22040cb5e5dSvi 
22140cb5e5dSvi /*
22240cb5e5dSvi  * Depending on the route-set, determine the request URI.
22340cb5e5dSvi  */
22440cb5e5dSvi char *
22540cb5e5dSvi sip_dialog_req_uri(sip_dialog_t dialog)
22640cb5e5dSvi {
22740cb5e5dSvi 	const sip_str_t		*req_uri;
22840cb5e5dSvi 	char			*uri;
22940cb5e5dSvi 	_sip_dialog_t		*_dialog;
23040cb5e5dSvi 
23140cb5e5dSvi 	_dialog = (_sip_dialog_t *)dialog;
23240cb5e5dSvi 	if (_dialog->sip_dlg_route_set == NULL ||
23340cb5e5dSvi 	    _dialog->sip_dlg_req_uri.sip_str_ptr == NULL) {
23440cb5e5dSvi 		const struct sip_value	*val;
23540cb5e5dSvi 
23640cb5e5dSvi 		val = sip_get_header_value(_dialog->sip_dlg_remote_target,
23740cb5e5dSvi 		    NULL);
23840cb5e5dSvi 		if (val == NULL)
23940cb5e5dSvi 			return (NULL);
24040cb5e5dSvi 		req_uri = &((sip_hdr_value_t *)val)->cftr_uri;
24140cb5e5dSvi 	} else {
24240cb5e5dSvi 		req_uri = &_dialog->sip_dlg_req_uri;
24340cb5e5dSvi 	}
24440cb5e5dSvi 	uri = (char *)malloc(req_uri->sip_str_len + 1);
24540cb5e5dSvi 	if (uri == NULL)
24640cb5e5dSvi 		return (NULL);
24740cb5e5dSvi 	(void) strncpy(uri, req_uri->sip_str_ptr, req_uri->sip_str_len);
24840cb5e5dSvi 	uri[req_uri->sip_str_len] = '\0';
24940cb5e5dSvi 
25040cb5e5dSvi 	return (uri);
25140cb5e5dSvi }
25240cb5e5dSvi 
25340cb5e5dSvi /*
25440cb5e5dSvi  * Free the route set.
25540cb5e5dSvi  */
25640cb5e5dSvi void
25740cb5e5dSvi sip_dialog_free_rset(sip_dlg_route_set_t *rset)
25840cb5e5dSvi {
25940cb5e5dSvi 	sip_dlg_route_set_t	*next;
26040cb5e5dSvi 
26140cb5e5dSvi 	while (rset != NULL) {
26240cb5e5dSvi 		next = rset->sip_dlg_route_next;
26340cb5e5dSvi 		rset->sip_dlg_route_next = NULL;
26440cb5e5dSvi 		free(rset->sip_dlg_route);
26540cb5e5dSvi 		free(rset);
26640cb5e5dSvi 		rset = next;
26740cb5e5dSvi 	}
26840cb5e5dSvi }
26940cb5e5dSvi 
27040cb5e5dSvi /*
27140cb5e5dSvi  * Recompute route-set
27240cb5e5dSvi  */
27340cb5e5dSvi static int
27440cb5e5dSvi sip_dlg_recompute_rset(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what)
27540cb5e5dSvi {
27640cb5e5dSvi 	int ret;
27740cb5e5dSvi 
27840cb5e5dSvi 	if (dialog->sip_dlg_route_set != NULL) {
27940cb5e5dSvi 		sip_free_header(dialog->sip_dlg_route_set);
28040cb5e5dSvi 		dialog->sip_dlg_route_set = NULL;
28140cb5e5dSvi 	}
28240cb5e5dSvi 	if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) {
28340cb5e5dSvi 		free(dialog->sip_dlg_req_uri.sip_str_ptr);
28440cb5e5dSvi 		dialog->sip_dlg_req_uri.sip_str_ptr = NULL;
28540cb5e5dSvi 		dialog->sip_dlg_req_uri.sip_str_len = 0;
28640cb5e5dSvi 	}
28740cb5e5dSvi 	if (dialog->sip_dlg_rset.sip_str_ptr != NULL) {
28840cb5e5dSvi 		free(dialog->sip_dlg_rset.sip_str_ptr);
28940cb5e5dSvi 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
29040cb5e5dSvi 		dialog->sip_dlg_rset.sip_str_len = 0;
29140cb5e5dSvi 	}
29240cb5e5dSvi 	ret = sip_dialog_get_route_set(dialog, sip_msg, what);
29340cb5e5dSvi 	return (ret);
29440cb5e5dSvi }
29540cb5e5dSvi 
29640cb5e5dSvi /*
29740cb5e5dSvi  * If the route set is empty, the UAC MUST place the remote target URI
29840cb5e5dSvi  * into the Request-URI.  The UAC MUST NOT add a Route header field to
29940cb5e5dSvi  * the request.
30040cb5e5dSvi  *
30140cb5e5dSvi  * If the route set is not empty, and the first URI in the route set
30240cb5e5dSvi  * contains the lr parameter (see Section 19.1.1), the UAC MUST place
30340cb5e5dSvi  * the remote target URI into the Request-URI and MUST include a Route
30440cb5e5dSvi  * header field containing the route set values in order, including all
30540cb5e5dSvi  * parameters.
30640cb5e5dSvi  *
30740cb5e5dSvi  * If the route set is not empty, and its first URI does not contain the
30840cb5e5dSvi  * lr parameter, the UAC MUST place the first URI from the route set
30940cb5e5dSvi  * into the Request-URI, stripping any parameters that are not allowed
31040cb5e5dSvi  * in a Request-URI.  The UAC MUST add a Route header field containing
31140cb5e5dSvi  * the remainder of the route set values in order, including all
31240cb5e5dSvi  * parameters.  The UAC MUST then place the remote target URI into the
31340cb5e5dSvi  * Route header field as the last value.
31440cb5e5dSvi  */
31540cb5e5dSvi int
31640cb5e5dSvi sip_dialog_set_route_hdr(_sip_dialog_t *dialog, sip_dlg_route_set_t *rset_head,
31740cb5e5dSvi     int rcnt, int rlen)
31840cb5e5dSvi {
31940cb5e5dSvi 	size_t			rset_len;
32040cb5e5dSvi 	_sip_header_t		*rhdr;
32140cb5e5dSvi 	char			*rset;
32240cb5e5dSvi 	char			*rp;
32340cb5e5dSvi 	char			*rsp;
32440cb5e5dSvi 	int			count;
32540cb5e5dSvi 	sip_dlg_route_set_t	*route;
32640cb5e5dSvi 	boolean_t		first = B_TRUE;
32740cb5e5dSvi 	const sip_str_t		*to_uri;
32840cb5e5dSvi 	char			*uri = NULL;
32940cb5e5dSvi 	int			rspl;
33040cb5e5dSvi 	int			rpl;
33140cb5e5dSvi 
332*943efbc3Sgm 	if (rcnt <= 0) {
333*943efbc3Sgm 		sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
334*943efbc3Sgm 		    SIP_ASSERT_ERROR, __FILE__, __LINE__);
335*943efbc3Sgm 	}
33640cb5e5dSvi 	assert(rcnt > 0);
33740cb5e5dSvi 
33840cb5e5dSvi 	dialog->sip_dlg_rset.sip_str_len = rlen + rcnt - 1;
33940cb5e5dSvi 	dialog->sip_dlg_rset.sip_str_ptr = malloc(rlen + rcnt);
34040cb5e5dSvi 	if (dialog->sip_dlg_rset.sip_str_ptr == NULL)
34140cb5e5dSvi 		return (ENOMEM);
34240cb5e5dSvi 	rsp = dialog->sip_dlg_rset.sip_str_ptr;
34340cb5e5dSvi 	rspl = rlen + rcnt;
34440cb5e5dSvi 	route = rset_head;
34540cb5e5dSvi 	rset_len = rlen;
34640cb5e5dSvi 	if (!route->sip_dlg_route_lr) {
34740cb5e5dSvi 		const struct sip_value	*val;
34840cb5e5dSvi 
34940cb5e5dSvi 		val = sip_get_header_value(dialog->sip_dlg_remote_target, NULL);
35040cb5e5dSvi 		to_uri = &((sip_hdr_value_t *)val)->cftr_uri;
35140cb5e5dSvi 		uri = (char *)malloc(to_uri->sip_str_len + 1);
35240cb5e5dSvi 		if (uri == NULL) {
35340cb5e5dSvi 			free(dialog->sip_dlg_rset.sip_str_ptr);
35440cb5e5dSvi 			dialog->sip_dlg_rset.sip_str_len = 0;
35540cb5e5dSvi 			dialog->sip_dlg_rset.sip_str_ptr = NULL;
35640cb5e5dSvi 			return (ENOMEM);
35740cb5e5dSvi 		}
35840cb5e5dSvi 		(void) strncpy(uri, to_uri->sip_str_ptr, to_uri->sip_str_len);
35940cb5e5dSvi 		uri[to_uri->sip_str_len] = '\0';
36040cb5e5dSvi 		rset_len = rlen - strlen(route->sip_dlg_route) + strlen(uri) +
36140cb5e5dSvi 		    SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN +
36240cb5e5dSvi 		    sizeof (char);
36340cb5e5dSvi 		count = snprintf(rsp, rspl, "%s", route->sip_dlg_route);
36440cb5e5dSvi 		dialog->sip_dlg_req_uri.sip_str_ptr = malloc(
36540cb5e5dSvi 		    route->sip_dlg_ruri.sip_str_len + 1);
36640cb5e5dSvi 		if (dialog->sip_dlg_req_uri.sip_str_ptr == NULL) {
36740cb5e5dSvi 			free(uri);
36840cb5e5dSvi 			free(dialog->sip_dlg_rset.sip_str_ptr);
36940cb5e5dSvi 			dialog->sip_dlg_rset.sip_str_len = 0;
37040cb5e5dSvi 			dialog->sip_dlg_rset.sip_str_ptr = NULL;
37140cb5e5dSvi 			return (ENOMEM);
37240cb5e5dSvi 		}
37340cb5e5dSvi 		(void) strncpy(dialog->sip_dlg_req_uri.sip_str_ptr, rsp +
37440cb5e5dSvi 		    (route->sip_dlg_ruri.sip_str_ptr - route->sip_dlg_route),
37540cb5e5dSvi 		    route->sip_dlg_ruri.sip_str_len);
37640cb5e5dSvi 		dialog->sip_dlg_req_uri.sip_str_ptr[
37740cb5e5dSvi 		    route->sip_dlg_ruri.sip_str_len] = '\0';
37840cb5e5dSvi 		dialog->sip_dlg_req_uri.sip_str_len =
37940cb5e5dSvi 		    route->sip_dlg_ruri.sip_str_len;
38040cb5e5dSvi 
38140cb5e5dSvi 		rsp += count;
38240cb5e5dSvi 		rspl -= count;
38340cb5e5dSvi 		route = route->sip_dlg_route_next;
38440cb5e5dSvi 	}
38540cb5e5dSvi 
38640cb5e5dSvi 	/*
38740cb5e5dSvi 	 * rcnt - 1 is for the number of COMMAs
38840cb5e5dSvi 	 */
38940cb5e5dSvi 	rset_len += strlen(SIP_ROUTE) + SIP_SPACE_LEN + sizeof (char) +
39040cb5e5dSvi 	    SIP_SPACE_LEN + rcnt - 1;
39140cb5e5dSvi 	rset = malloc(rset_len + 1);
39240cb5e5dSvi 	if (rset == NULL) {
39340cb5e5dSvi 		free(dialog->sip_dlg_rset.sip_str_ptr);
39440cb5e5dSvi 		dialog->sip_dlg_rset.sip_str_len = 0;
39540cb5e5dSvi 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
39640cb5e5dSvi 		return (ENOMEM);
39740cb5e5dSvi 	}
39840cb5e5dSvi 	rhdr = sip_new_header(rset_len + strlen(SIP_CRLF));
39940cb5e5dSvi 	if (rhdr == NULL) {
40040cb5e5dSvi 		free(rset);
40140cb5e5dSvi 		free(dialog->sip_dlg_rset.sip_str_ptr);
40240cb5e5dSvi 		dialog->sip_dlg_rset.sip_str_len = 0;
40340cb5e5dSvi 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
40440cb5e5dSvi 		return (ENOMEM);
40540cb5e5dSvi 	}
40640cb5e5dSvi 
40740cb5e5dSvi 	rp = rset;
40840cb5e5dSvi 	rpl = rset_len + 1;
40940cb5e5dSvi 	count = snprintf(rp, rpl, "%s %c ", SIP_ROUTE, SIP_HCOLON);
41040cb5e5dSvi 	rp += count;
41140cb5e5dSvi 	rpl -= count;
41240cb5e5dSvi 
41340cb5e5dSvi 	while (route != NULL) {
41440cb5e5dSvi 		if (first) {
41540cb5e5dSvi 			count = snprintf(rp, rpl, "%s", route->sip_dlg_route);
41640cb5e5dSvi 			rp += count;
41740cb5e5dSvi 			rpl -= count;
41840cb5e5dSvi 			first = B_FALSE;
41940cb5e5dSvi 			if (uri != NULL) {
42040cb5e5dSvi 				count = snprintf(rsp, rspl, "%c%s",
42140cb5e5dSvi 				    SIP_COMMA, route->sip_dlg_route);
42240cb5e5dSvi 			} else {
42340cb5e5dSvi 				count = snprintf(rsp, rspl, "%s",
42440cb5e5dSvi 				    route->sip_dlg_route);
42540cb5e5dSvi 			}
42640cb5e5dSvi 			rsp += count;
42740cb5e5dSvi 			rspl -= count;
42840cb5e5dSvi 		} else {
42940cb5e5dSvi 			count = snprintf(rp, rpl, "%c%s", SIP_COMMA,
43040cb5e5dSvi 			    route->sip_dlg_route);
43140cb5e5dSvi 			rp += count;
43240cb5e5dSvi 			rpl -= count;
43340cb5e5dSvi 			count = snprintf(rsp, rspl, "%c%s", SIP_COMMA,
43440cb5e5dSvi 			    route->sip_dlg_route);
43540cb5e5dSvi 			rsp += count;
43640cb5e5dSvi 			rspl -= count;
43740cb5e5dSvi 		}
43840cb5e5dSvi 		route = route->sip_dlg_route_next;
43940cb5e5dSvi 	}
440*943efbc3Sgm 	if (rsp > dialog->sip_dlg_rset.sip_str_ptr +
441*943efbc3Sgm 	    dialog->sip_dlg_rset.sip_str_len) {
442*943efbc3Sgm 		sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
443*943efbc3Sgm 		    SIP_ASSERT_ERROR, __FILE__, __LINE__);
444*943efbc3Sgm 	}
44540cb5e5dSvi 	assert(rsp <= dialog->sip_dlg_rset.sip_str_ptr +
44640cb5e5dSvi 	    dialog->sip_dlg_rset.sip_str_len);
44740cb5e5dSvi 	dialog->sip_dlg_rset.sip_str_ptr[dialog->sip_dlg_rset.sip_str_len] =
44840cb5e5dSvi 	    '\0';
44940cb5e5dSvi 	if (uri != NULL) {
45040cb5e5dSvi 		if (first) {
45140cb5e5dSvi 			count = snprintf(rp, rpl, "%c %s %c", SIP_LAQUOT,
45240cb5e5dSvi 			    uri, SIP_RAQUOT);
45340cb5e5dSvi 		} else {
45440cb5e5dSvi 			count = snprintf(rp, rpl, "%c%c %s %c", SIP_COMMA,
45540cb5e5dSvi 			    SIP_LAQUOT, uri, SIP_RAQUOT);
45640cb5e5dSvi 		}
45740cb5e5dSvi 		rp += count;
45840cb5e5dSvi 		rpl -= count;
45940cb5e5dSvi 		free(uri);
46040cb5e5dSvi 	}
461*943efbc3Sgm 	if (rp > rset + rset_len) {
462*943efbc3Sgm 		sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
463*943efbc3Sgm 		    SIP_ASSERT_ERROR, __FILE__, __LINE__);
464*943efbc3Sgm 	}
46540cb5e5dSvi 	assert(rp <= rset + rset_len);
46640cb5e5dSvi 	(void) snprintf(rhdr->sip_hdr_start, rset_len + strlen(SIP_CRLF) + 1,
46740cb5e5dSvi 	    "%s%s", rset, SIP_CRLF);
46840cb5e5dSvi 	free(rset);
46940cb5e5dSvi 	dialog->sip_dlg_route_set = (sip_header_t)rhdr;
47040cb5e5dSvi 	sip_dialog_free_rset(rset_head);
47140cb5e5dSvi 	return (0);
47240cb5e5dSvi }
47340cb5e5dSvi 
47440cb5e5dSvi /*
47540cb5e5dSvi  * UAC Behavior
47640cb5e5dSvi  * The route set MUST be set to the list of URIs in the Record-Route
47740cb5e5dSvi  * header field from the response, taken in reverse order and preserving
47840cb5e5dSvi  * all URI parameters.
47940cb5e5dSvi  *
48040cb5e5dSvi  * UAS behavior
48140cb5e5dSvi  * The route set MUST be set to the list of URIs in the Record-Route
48240cb5e5dSvi  * header field from the request, taken in order and preserving all URI
48340cb5e5dSvi  * parameters.
48440cb5e5dSvi  */
48540cb5e5dSvi static int
48640cb5e5dSvi sip_dialog_get_route_set(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what)
48740cb5e5dSvi {
48840cb5e5dSvi 	sip_header_t		rrhdr;
48940cb5e5dSvi 	sip_hdr_value_t		*value;
49040cb5e5dSvi 	int			error;
49140cb5e5dSvi 	sip_dlg_route_set_t	*rset_head = NULL;
49240cb5e5dSvi 	sip_dlg_route_set_t	*rset_tail = NULL;
49340cb5e5dSvi 	sip_dlg_route_set_t	*rset;
49440cb5e5dSvi 	int			rset_cnt = 0;
49540cb5e5dSvi 	int			rset_len = 0;
49640cb5e5dSvi 
49740cb5e5dSvi 	(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
49840cb5e5dSvi 	rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, NULL);
49940cb5e5dSvi 	while (rrhdr != NULL) {
50040cb5e5dSvi 		(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
50140cb5e5dSvi 		value = (sip_hdr_value_t *)sip_get_header_value(rrhdr, &error);
50240cb5e5dSvi 		while (value != NULL && error == 0) {
50340cb5e5dSvi 			char	*crlf;
50440cb5e5dSvi 
50540cb5e5dSvi 			if (value->sip_value_state == SIP_VALUE_BAD) {
50640cb5e5dSvi 				value = (sip_hdr_value_t *)sip_get_next_value(
50740cb5e5dSvi 				    (sip_header_value_t)value, &error);
50840cb5e5dSvi 				continue;
50940cb5e5dSvi 			}
51040cb5e5dSvi 			rset = sip_add_route_to_set(value);
51140cb5e5dSvi 			if (rset == NULL)
51240cb5e5dSvi 				goto r_error;
51340cb5e5dSvi 			/*
51440cb5e5dSvi 			 * Add one for COMMA
51540cb5e5dSvi 			 */
51640cb5e5dSvi 			rset_cnt++;
51740cb5e5dSvi 			rset_len += (value->sip_value_end -
51840cb5e5dSvi 			    value->sip_value_start);
51940cb5e5dSvi 			/*
52040cb5e5dSvi 			 * Check for CRLF
52140cb5e5dSvi 			 */
52240cb5e5dSvi 			crlf = value->sip_value_end - strlen(SIP_CRLF);
52340cb5e5dSvi 			while (crlf != NULL &&
52440cb5e5dSvi 			    strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) {
52540cb5e5dSvi 				rset_len -= strlen(SIP_CRLF);
52640cb5e5dSvi 				crlf -= strlen(SIP_CRLF);
52740cb5e5dSvi 			}
52840cb5e5dSvi 			if (rset_head == NULL) {
529*943efbc3Sgm 				if (rset_tail != NULL) {
530*943efbc3Sgm 					sip_write_to_log((void *)dialog,
531*943efbc3Sgm 					    SIP_DIALOG_LOG | SIP_ASSERT_ERROR,
532*943efbc3Sgm 					    __FILE__, __LINE__);
533*943efbc3Sgm 				}
53440cb5e5dSvi 				assert(rset_tail == NULL);
53540cb5e5dSvi 				rset_head = rset_tail = rset;
53640cb5e5dSvi 			} else if (what == SIP_UAS_DIALOG) {
53740cb5e5dSvi 				rset_tail->sip_dlg_route_next = rset;
53840cb5e5dSvi 				rset_tail = rset;
53940cb5e5dSvi 			} else if (what == SIP_UAC_DIALOG) {
54040cb5e5dSvi 				rset->sip_dlg_route_next = rset_head;
54140cb5e5dSvi 				rset_head = rset;
54240cb5e5dSvi 			} else {
543*943efbc3Sgm 				sip_write_to_log((void *)dialog,
544*943efbc3Sgm 				    SIP_DIALOG_LOG | SIP_ASSERT_ERROR,
545*943efbc3Sgm 				    __FILE__, __LINE__);
54640cb5e5dSvi 				assert(0);
54740cb5e5dSvi 			}
54840cb5e5dSvi 			value = (sip_hdr_value_t *)sip_get_next_value(
54940cb5e5dSvi 			    (sip_header_value_t)value, &error);
55040cb5e5dSvi 		}
55140cb5e5dSvi 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
55240cb5e5dSvi 		rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, rrhdr);
55340cb5e5dSvi 	}
55440cb5e5dSvi 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
55540cb5e5dSvi 	if (rset_cnt == 0)
55640cb5e5dSvi 		return (0);
55740cb5e5dSvi 	if (sip_dialog_set_route_hdr(dialog, rset_head, rset_cnt,
55840cb5e5dSvi 	    rset_len) != 0) {
55940cb5e5dSvi 		goto r_error;
56040cb5e5dSvi 	}
56140cb5e5dSvi 	return (0);
56240cb5e5dSvi r_error:
56340cb5e5dSvi 	sip_dialog_free_rset(rset_head);
56440cb5e5dSvi 	return (ENOMEM);
56540cb5e5dSvi }
56640cb5e5dSvi 
56740cb5e5dSvi /*
56840cb5e5dSvi  * UAS behavior:
56940cb5e5dSvi  * The remote sequence number MUST be set to the value of the sequence
57040cb5e5dSvi  * number in the CSeq header field of the request.  The local sequence
57140cb5e5dSvi  * number MUST be empty.  The call identifier component of the dialog ID
57240cb5e5dSvi  * MUST be set to the value of the Call-ID in the request.  The local
57340cb5e5dSvi  * tag component of the dialog ID MUST be set to the tag in the To field
57440cb5e5dSvi  * in the response to the request (which always includes a tag), and the
57540cb5e5dSvi  * remote tag component of the dialog ID MUST be set to the tag from the
57640cb5e5dSvi  * From field in the request.  A UAS MUST be prepared to receive a
57740cb5e5dSvi  * request without a tag in the From field, in which case the tag is
57840cb5e5dSvi  * considered to have a value of null.
57940cb5e5dSvi  * The remote URI MUST be set to the URI in the From field, and the
58040cb5e5dSvi  * local URI MUST be set to the URI in the To field.
58140cb5e5dSvi  * The remote target MUST be set to the URI from the Contact header field
58240cb5e5dSvi  * of the request.
58340cb5e5dSvi  *
58440cb5e5dSvi  * UAC behavior:
58540cb5e5dSvi  * The local sequence number MUST be set to the value of the sequence
58640cb5e5dSvi  * number in the CSeq header field of the request.  The remote sequence
58740cb5e5dSvi  * number MUST be empty (it is established when the remote UA sends a
58840cb5e5dSvi  * request within the dialog).  The call identifier component of the
58940cb5e5dSvi  * dialog ID MUST be set to the value of the Call-ID in the request.
59040cb5e5dSvi  * The local tag component of the dialog ID MUST be set to the tag in
59140cb5e5dSvi  * the From field in the request, and the remote tag component of the
59240cb5e5dSvi  * dialog ID MUST be set to the tag in the To field of the response.  A
59340cb5e5dSvi  * UAC MUST be prepared to receive a response without a tag in the To
59440cb5e5dSvi  * field, in which case the tag is considered to have a value of null.
59540cb5e5dSvi  * The remote URI MUST be set to the URI in the To field, and the local
59640cb5e5dSvi  * URI MUST be set to the URI in the From field.
59740cb5e5dSvi  * The remote target MUST be set to the URI from the Contact header field
59840cb5e5dSvi  * of the response.
59940cb5e5dSvi  */
60040cb5e5dSvi 
60140cb5e5dSvi 
60240cb5e5dSvi /*
60340cb5e5dSvi  * This is the routine that seeds a dialog.
60440cb5e5dSvi  */
60540cb5e5dSvi sip_dialog_t
60640cb5e5dSvi sip_seed_dialog(sip_conn_object_t obj, _sip_msg_t *sip_msg,
60740cb5e5dSvi     boolean_t dlg_on_fork, int dlg_type)
60840cb5e5dSvi {
60940cb5e5dSvi 	_sip_dialog_t		*dialog;
61040cb5e5dSvi 	int			cseq;
61140cb5e5dSvi 	sip_header_t		fhdr = NULL;
61240cb5e5dSvi 	sip_header_t		thdr = NULL;
61340cb5e5dSvi 	sip_header_t		chdr;
61440cb5e5dSvi 	sip_header_t		cihdr;
61540cb5e5dSvi 	sip_header_t		evhdr = NULL;
61640cb5e5dSvi 	const struct sip_value	*value;
61740cb5e5dSvi 	sip_dialog_timer_obj_t	*tim_obj = NULL;
61840cb5e5dSvi 	const sip_str_t		*callid;
61940cb5e5dSvi 	sip_method_t		method;
62040cb5e5dSvi 	int			timer1 = sip_timer_T1;
62140cb5e5dSvi 	int			error;
62240cb5e5dSvi 
62340cb5e5dSvi 	if (!sip_msg_is_request((sip_msg_t)sip_msg, &error))
62440cb5e5dSvi 		return (NULL);
62540cb5e5dSvi 
62640cb5e5dSvi 	method = sip_get_request_method((sip_msg_t)sip_msg, &error);
62740cb5e5dSvi 	/*
62840cb5e5dSvi 	 * Only INVITE and SUBSCRIBE supported
62940cb5e5dSvi 	 */
63040cb5e5dSvi 	if (error != 0 || (method != INVITE && method != SUBSCRIBE))
63140cb5e5dSvi 		return (NULL);
63240cb5e5dSvi 
63340cb5e5dSvi 	/*
63440cb5e5dSvi 	 * A request outside of a dialog MUST NOT contain a To tag
63540cb5e5dSvi 	 */
63640cb5e5dSvi 	if (sip_get_to_tag((sip_msg_t)sip_msg, NULL) != NULL)
63740cb5e5dSvi 		return (NULL);
63840cb5e5dSvi 
63940cb5e5dSvi 	if (dlg_type == SIP_UAS_DIALOG) {
64040cb5e5dSvi 		thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg,
64140cb5e5dSvi 		    SIP_DLG_XCHG_FROM);
64240cb5e5dSvi 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
64340cb5e5dSvi 	} else {
64440cb5e5dSvi 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
64540cb5e5dSvi 		fhdr = sip_search_for_header(sip_msg, SIP_FROM, NULL);
64640cb5e5dSvi 	}
64740cb5e5dSvi 	cihdr = sip_search_for_header(sip_msg, SIP_CALL_ID, NULL);
64840cb5e5dSvi 	chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
64940cb5e5dSvi 	if (method == SUBSCRIBE)
65040cb5e5dSvi 		evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL);
65140cb5e5dSvi 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
65240cb5e5dSvi 	if ((fhdr == NULL && thdr == NULL) || cihdr == NULL || chdr == NULL ||
65340cb5e5dSvi 	    (method == SUBSCRIBE && evhdr == NULL)) {
65440cb5e5dSvi 		if (thdr != NULL)
65540cb5e5dSvi 			sip_free_header(thdr);
65640cb5e5dSvi 		return (NULL);
65740cb5e5dSvi 	}
65840cb5e5dSvi 
65940cb5e5dSvi 	/*
66040cb5e5dSvi 	 * Sanity check since we just store the headers in the dialog
66140cb5e5dSvi 	 */
66240cb5e5dSvi 	if (sip_get_from_tag((sip_msg_t)sip_msg, NULL) == NULL ||
66340cb5e5dSvi 	    sip_get_from_uri_str((sip_msg_t)sip_msg, NULL) == NULL ||
66440cb5e5dSvi 	    ((cseq = sip_get_callseq_num((sip_msg_t)sip_msg, NULL)) == -1) ||
66540cb5e5dSvi 	    (callid = sip_get_callid((sip_msg_t)sip_msg, NULL)) == NULL ||
66640cb5e5dSvi 	    sip_get_to_uri_str((sip_msg_t)sip_msg, NULL) == NULL ||
66740cb5e5dSvi 	    ((value = sip_get_header_value(chdr, NULL)) == NULL) ||
66840cb5e5dSvi 	    sip_get_contact_uri_str((sip_header_value_t)value, NULL) == NULL) {
66940cb5e5dSvi 		if (thdr != NULL)
67040cb5e5dSvi 			sip_free_header(thdr);
67140cb5e5dSvi 		return (NULL);
67240cb5e5dSvi 	}
67340cb5e5dSvi 
67440cb5e5dSvi 	tim_obj = calloc(1, sizeof (sip_dialog_timer_obj_t));
67540cb5e5dSvi 	if (tim_obj == NULL) {
67640cb5e5dSvi 		if (thdr != NULL)
67740cb5e5dSvi 			sip_free_header(thdr);
67840cb5e5dSvi 		return (NULL);
67940cb5e5dSvi 	}
68040cb5e5dSvi 	dialog = calloc(1, sizeof (_sip_dialog_t));
68140cb5e5dSvi 	if (dialog == NULL) {
68240cb5e5dSvi 		if (thdr != NULL)
68340cb5e5dSvi 			sip_free_header(thdr);
68440cb5e5dSvi 		return (NULL);
68540cb5e5dSvi 	}
68640cb5e5dSvi 	/*
68740cb5e5dSvi 	 * We will take the TO header with the tag when we complete this
68840cb5e5dSvi 	 * dialog
68940cb5e5dSvi 	 */
69040cb5e5dSvi 	if (dlg_type == SIP_UAS_DIALOG) {
69140cb5e5dSvi 		dialog->sip_dlg_remote_uri_tag = thdr;
69240cb5e5dSvi 		/*
69340cb5e5dSvi 		 * We take the remote target from the incoming request on the
69440cb5e5dSvi 		 * UAS. For the UAC, we will take it from the response.
69540cb5e5dSvi 		 */
69640cb5e5dSvi 		if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) ==
69740cb5e5dSvi 		    NULL) {
69840cb5e5dSvi 			goto dia_err;
69940cb5e5dSvi 		}
70040cb5e5dSvi 	} else {
70140cb5e5dSvi 		if ((dialog->sip_dlg_local_uri_tag = sip_dup_header(fhdr)) ==
70240cb5e5dSvi 		    NULL) {
70340cb5e5dSvi 			goto dia_err;
70440cb5e5dSvi 		}
705d8a40387Sgm 		/*
706d8a40387Sgm 		 * We take the local contact from the originating request on
707d8a40387Sgm 		 * UAC. For the UAS, we will take it from the response.
708d8a40387Sgm 		 */
709d8a40387Sgm 		if ((dialog->sip_dlg_local_contact = sip_dup_header(chdr)) ==
710d8a40387Sgm 		    NULL) {
711d8a40387Sgm 			goto dia_err;
712d8a40387Sgm 		} else {
713d8a40387Sgm 			dialog->sip_dlg_new_local_contact = NULL;
714d8a40387Sgm 		}
71540cb5e5dSvi 	}
71640cb5e5dSvi 	if ((dialog->sip_dlg_call_id = sip_dup_header(cihdr)) == NULL)
71740cb5e5dSvi 		goto dia_err;
71840cb5e5dSvi 	if (method == SUBSCRIBE) {
71940cb5e5dSvi 		dialog->sip_dlg_event = sip_dup_header(evhdr);
72040cb5e5dSvi 		if (dialog->sip_dlg_event == NULL) {
72140cb5e5dSvi 			goto dia_err;
72240cb5e5dSvi 		}
72340cb5e5dSvi 	}
72440cb5e5dSvi 	dialog->sip_dlg_rset.sip_str_ptr = NULL;
72540cb5e5dSvi 	dialog->sip_dlg_rset.sip_str_len = 0;
72640cb5e5dSvi 	dialog->sip_dlg_req_uri.sip_str_ptr = NULL;
72740cb5e5dSvi 	dialog->sip_dlg_req_uri.sip_str_len = 0;
72840cb5e5dSvi 	/*
72940cb5e5dSvi 	 * Get the route set from the request, if present
73040cb5e5dSvi 	 */
73140cb5e5dSvi 	if (dlg_type == SIP_UAS_DIALOG &&
73240cb5e5dSvi 	    sip_dialog_get_route_set(dialog, sip_msg, dlg_type) != 0) {
73340cb5e5dSvi 		goto dia_err;
73440cb5e5dSvi 	}
73540cb5e5dSvi 	if (dlg_type == SIP_UAC_DIALOG)
73640cb5e5dSvi 		dialog->sip_dlg_local_cseq = cseq;
73740cb5e5dSvi 	else
73840cb5e5dSvi 		dialog->sip_dlg_remote_cseq = cseq;
73940cb5e5dSvi 	dialog->sip_dlg_type = dlg_type;
74040cb5e5dSvi 	dialog->sip_dlg_on_fork = dlg_on_fork;
74140cb5e5dSvi 	dialog->sip_dlg_method = method;
74240cb5e5dSvi 	/*
74340cb5e5dSvi 	 * Set the partial dialog timer with the INVITE timeout val
74440cb5e5dSvi 	 */
74540cb5e5dSvi 	if (sip_conn_timer1 != NULL)
74640cb5e5dSvi 		timer1 = sip_conn_timer1(obj);
74740cb5e5dSvi 	SIP_INIT_TIMER(dialog->sip_dlg_timer, 64 * timer1);
74840cb5e5dSvi 	tim_obj->dialog = dialog;
74940cb5e5dSvi 	/*
75040cb5e5dSvi 	 * Since at the client we never pass the partial dialog, we need not
75140cb5e5dSvi 	 * invoke the callback when the partial dialog self-destructs.
75240cb5e5dSvi 	 */
75340cb5e5dSvi 	if (dlg_type == SIP_UAS_DIALOG)
75440cb5e5dSvi 		tim_obj->func = sip_ulp_dlg_del_cb;
75540cb5e5dSvi 	SIP_SCHED_TIMER(dialog->sip_dlg_timer, (void *)tim_obj,
75640cb5e5dSvi 	    sip_dlg_self_destruct);
75740cb5e5dSvi 	if (!SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
75840cb5e5dSvi 		goto dia_err;
75940cb5e5dSvi 	(void) pthread_mutex_init(&dialog->sip_dlg_mutex, NULL);
76040cb5e5dSvi 
76140cb5e5dSvi 	if (dlg_type == SIP_UAC_DIALOG) {
76240cb5e5dSvi 		const sip_str_t	*local_tag;
76340cb5e5dSvi 
76440cb5e5dSvi 		local_tag = sip_get_from_tag((sip_msg_t)sip_msg, NULL);
765*943efbc3Sgm 		if (local_tag == NULL) {
766*943efbc3Sgm 			sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
767*943efbc3Sgm 			    SIP_ASSERT_ERROR, __FILE__, __LINE__);
768*943efbc3Sgm 		}
76940cb5e5dSvi 		assert(local_tag != NULL);
77040cb5e5dSvi 		sip_md5_hash(local_tag->sip_str_ptr, local_tag->sip_str_len,
77140cb5e5dSvi 		    callid->sip_str_ptr, callid->sip_str_len,
77240cb5e5dSvi 		    NULL, 0, NULL, 0, NULL, 0, NULL, 0,
77340cb5e5dSvi 		    (uchar_t *)dialog->sip_dlg_id);
77440cb5e5dSvi 
77540cb5e5dSvi 
77640cb5e5dSvi 		/*
77740cb5e5dSvi 		 * Add it to the partial hash table
77840cb5e5dSvi 		 */
77940cb5e5dSvi 		if (sip_hash_add(sip_dialog_phash, (void *)dialog,
78040cb5e5dSvi 		    SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) {
78140cb5e5dSvi 			goto dia_err;
78240cb5e5dSvi 		}
78340cb5e5dSvi 	}
784*943efbc3Sgm 
785*943efbc3Sgm 	dialog->sip_dlg_msgcnt = 1;
786*943efbc3Sgm 	sip_add_log(&dialog->sip_dlg_log[dialog->sip_dlg_state],
787*943efbc3Sgm 	    (sip_msg_t)sip_msg, dialog->sip_dlg_msgcnt, SIP_DIALOG_LOG);
788*943efbc3Sgm 
78940cb5e5dSvi 	SIP_DLG_REFCNT_INCR(dialog);
79040cb5e5dSvi 	return ((sip_dialog_t)dialog);
79140cb5e5dSvi dia_err:
79240cb5e5dSvi 	sip_release_dialog_res(dialog);
79340cb5e5dSvi 	if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
79440cb5e5dSvi 		SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
79540cb5e5dSvi 	if (tim_obj != NULL)
79640cb5e5dSvi 		free(tim_obj);
79740cb5e5dSvi 	return (NULL);
79840cb5e5dSvi }
79940cb5e5dSvi 
80040cb5e5dSvi /*
80140cb5e5dSvi  * When creating a dialog from a NOTIFY request, we need to get the FROM
80240cb5e5dSvi  * header for the dialog from the TO header of the NOTIFY.
80340cb5e5dSvi  */
80440cb5e5dSvi _sip_header_t *
80540cb5e5dSvi sip_dlg_xchg_from_to(sip_msg_t sip_msg, int what)
80640cb5e5dSvi {
80740cb5e5dSvi 	int			len;
80840cb5e5dSvi 	_sip_header_t		*newhdr;
80940cb5e5dSvi 	int			cnt;
81040cb5e5dSvi 	const struct sip_header	*hdr;
81140cb5e5dSvi 	int			hdrsize;
81240cb5e5dSvi 	int			error;
81340cb5e5dSvi 
81440cb5e5dSvi 	hdr = sip_get_header(sip_msg, what == SIP_DLG_XCHG_FROM ? SIP_FROM :
81540cb5e5dSvi 	    SIP_TO, NULL, &error);
81640cb5e5dSvi 	if (error != 0 || hdr == NULL)
81740cb5e5dSvi 		return (NULL);
81840cb5e5dSvi 	if (sip_parse_goto_values((_sip_header_t *)hdr) != 0)
81940cb5e5dSvi 		return (NULL);
82040cb5e5dSvi 	len = hdr->sip_hdr_end - hdr->sip_hdr_current;
82140cb5e5dSvi 	if (what == SIP_DLG_XCHG_FROM) {
82240cb5e5dSvi 		hdrsize = len + strlen(SIP_TO) + SIP_SPACE_LEN + sizeof (char) +
82340cb5e5dSvi 		    SIP_SPACE_LEN;
82440cb5e5dSvi 	} else {
82540cb5e5dSvi 		hdrsize = len + strlen(SIP_FROM) + SIP_SPACE_LEN +
82640cb5e5dSvi 		    sizeof (char) + SIP_SPACE_LEN;
82740cb5e5dSvi 	}
82840cb5e5dSvi 	newhdr = sip_new_header(hdrsize);
82940cb5e5dSvi 	if (newhdr == NULL)
83040cb5e5dSvi 		return (NULL);
83140cb5e5dSvi 	if (what == SIP_DLG_XCHG_FROM) {
83240cb5e5dSvi 		cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1,
83340cb5e5dSvi 		    "%s %c ", SIP_TO, SIP_HCOLON);
83440cb5e5dSvi 	} else {
83540cb5e5dSvi 		cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1,
83640cb5e5dSvi 		    "%s %c ", SIP_FROM, SIP_HCOLON);
83740cb5e5dSvi 	}
83840cb5e5dSvi 	newhdr->sip_hdr_current += cnt;
83940cb5e5dSvi 	(void) strncpy(newhdr->sip_hdr_current, hdr->sip_hdr_current, len);
84040cb5e5dSvi 	newhdr->sip_hdr_current += len;
84140cb5e5dSvi 	assert(newhdr->sip_hdr_current == newhdr->sip_hdr_end);
84240cb5e5dSvi 	assert(hdr->sip_header_functions != NULL);
84340cb5e5dSvi 
84440cb5e5dSvi 	/*
84540cb5e5dSvi 	 * FROM and TO have common parsing functions
84640cb5e5dSvi 	 */
84740cb5e5dSvi 	newhdr->sip_header_functions = hdr->sip_header_functions;
84840cb5e5dSvi 	newhdr->sip_hdr_current = newhdr->sip_hdr_start;
84940cb5e5dSvi 
85040cb5e5dSvi 	return (newhdr);
85140cb5e5dSvi }
85240cb5e5dSvi 
85340cb5e5dSvi /*
85440cb5e5dSvi  * This is the response that completes the dialog that was created
85540cb5e5dSvi  * in sip_seed_dialog().
85640cb5e5dSvi  */
85740cb5e5dSvi sip_dialog_t
85840cb5e5dSvi sip_complete_dialog(_sip_msg_t *sip_msg, _sip_dialog_t *dialog)
85940cb5e5dSvi {
86040cb5e5dSvi 	_sip_header_t		*thdr;
86140cb5e5dSvi 	_sip_header_t		*evhdr = NULL;
86240cb5e5dSvi 	_sip_header_t		*substate = NULL;
86340cb5e5dSvi 	sip_header_t		chdr = NULL;
86440cb5e5dSvi 	int			resp_code;
86540cb5e5dSvi 	const sip_str_t		*ttag;
86640cb5e5dSvi 	const sip_str_t		*remtag;
86740cb5e5dSvi 	const sip_str_t		*callid;
86840cb5e5dSvi 	const struct sip_value 	*val;
86940cb5e5dSvi 	sip_method_t		method;
87040cb5e5dSvi 	int			error = 0;
87140cb5e5dSvi 	int			prev_state;
87240cb5e5dSvi 	boolean_t		alloc_thdr = B_FALSE;
87340cb5e5dSvi 
87440cb5e5dSvi 	if (sip_msg_is_request((sip_msg_t)sip_msg, &error) && error == 0)
87540cb5e5dSvi 		method = sip_get_request_method((sip_msg_t)sip_msg, &error);
87640cb5e5dSvi 	else
87740cb5e5dSvi 		method = sip_get_callseq_method((sip_msg_t)sip_msg, &error);
87840cb5e5dSvi 	if (error != 0 || dialog == NULL ||
87940cb5e5dSvi 	    (sip_msg_is_request((sip_msg_t)sip_msg, &error) &&
88040cb5e5dSvi 	    (dialog->sip_dlg_method == INVITE || method != NOTIFY))) {
88140cb5e5dSvi 		return (NULL);
88240cb5e5dSvi 	}
88340cb5e5dSvi 	if ((dialog->sip_dlg_type == SIP_UAC_DIALOG && method != NOTIFY &&
88440cb5e5dSvi 	    sip_get_callseq_num((sip_msg_t)sip_msg, NULL) !=
88540cb5e5dSvi 	    dialog->sip_dlg_local_cseq) ||
88640cb5e5dSvi 	    (dialog->sip_dlg_type == SIP_UAS_DIALOG && method != NOTIFY &&
88740cb5e5dSvi 	    sip_get_callseq_num((sip_msg_t)sip_msg, NULL) !=
88840cb5e5dSvi 	    dialog->sip_dlg_remote_cseq)) {
88940cb5e5dSvi 		return (NULL);
89040cb5e5dSvi 	}
89140cb5e5dSvi 	if (method == NOTIFY) {
89240cb5e5dSvi 		const sip_str_t	*sstate;
89340cb5e5dSvi 
89440cb5e5dSvi 		thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg,
89540cb5e5dSvi 		    SIP_DLG_XCHG_FROM);
89640cb5e5dSvi 		if (thdr == NULL)
89740cb5e5dSvi 			return (NULL);
89840cb5e5dSvi 		alloc_thdr = B_TRUE;
89940cb5e5dSvi 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
90040cb5e5dSvi 		chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
90140cb5e5dSvi 		if (chdr == NULL) {
90240cb5e5dSvi 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
90340cb5e5dSvi 			sip_free_header(thdr);
90440cb5e5dSvi 			return (NULL);
90540cb5e5dSvi 		}
90640cb5e5dSvi 		evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL);
90740cb5e5dSvi 		if (evhdr == NULL) {
90840cb5e5dSvi 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
90940cb5e5dSvi 			sip_free_header(thdr);
91040cb5e5dSvi 			return (NULL);
91140cb5e5dSvi 		}
91240cb5e5dSvi 		substate = sip_search_for_header(sip_msg,
91340cb5e5dSvi 		    SIP_SUBSCRIPTION_STATE, NULL);
91440cb5e5dSvi 		if (substate == NULL) {
91540cb5e5dSvi 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
91640cb5e5dSvi 			sip_free_header(thdr);
91740cb5e5dSvi 			return (NULL);
91840cb5e5dSvi 		}
91940cb5e5dSvi 		(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
92040cb5e5dSvi 		sstate = sip_get_substate((sip_msg_t)sip_msg, &error);
92140cb5e5dSvi 		if (sstate == NULL || error != 0) {
92240cb5e5dSvi 			sip_free_header(thdr);
92340cb5e5dSvi 			return (NULL);
92440cb5e5dSvi 		}
92540cb5e5dSvi 		if ((sstate->sip_str_len != strlen("pending") &&
92640cb5e5dSvi 		    sstate->sip_str_len != strlen("active")) ||
92740cb5e5dSvi 		    ((sstate->sip_str_len == strlen("pending") &&
92840cb5e5dSvi 		    strncasecmp(sstate->sip_str_ptr, "pending",
92940cb5e5dSvi 		    strlen("pending")) != 0) ||
93040cb5e5dSvi 		    (sstate->sip_str_len == strlen("active") &&
93140cb5e5dSvi 		    strncasecmp(sstate->sip_str_ptr, "active",
93240cb5e5dSvi 		    strlen("active")) != 0))) {
93340cb5e5dSvi 			sip_free_header(thdr);
93440cb5e5dSvi 			return (NULL);
93540cb5e5dSvi 		}
93640cb5e5dSvi 		ttag = sip_get_from_tag((sip_msg_t)sip_msg, NULL);
93740cb5e5dSvi 	} else {
93840cb5e5dSvi 		if (dialog->sip_dlg_type == SIP_UAS_DIALOG) {
93940cb5e5dSvi 			thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg,
94040cb5e5dSvi 			    SIP_DLG_XCHG_TO);
94140cb5e5dSvi 			alloc_thdr = B_TRUE;
94240cb5e5dSvi 		} else {
94340cb5e5dSvi 			(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
94440cb5e5dSvi 			thdr = sip_search_for_header(sip_msg, SIP_TO, NULL);
94540cb5e5dSvi 			if (dialog->sip_dlg_remote_target == NULL) {
94640cb5e5dSvi 				chdr = sip_search_for_header(sip_msg,
94740cb5e5dSvi 				    SIP_CONTACT, NULL);
94840cb5e5dSvi 			}
94940cb5e5dSvi 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
95040cb5e5dSvi 		}
95140cb5e5dSvi 		if (thdr == NULL) {
95240cb5e5dSvi 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
95340cb5e5dSvi 			return (NULL);
95440cb5e5dSvi 		}
95540cb5e5dSvi 		ttag = sip_get_to_tag((sip_msg_t)sip_msg, NULL);
95640cb5e5dSvi 	}
95740cb5e5dSvi 	if (ttag == NULL) {
95840cb5e5dSvi 		if (alloc_thdr)
95940cb5e5dSvi 			sip_free_header(thdr);
96040cb5e5dSvi 		return (NULL);
96140cb5e5dSvi 	}
96240cb5e5dSvi 	prev_state = dialog->sip_dlg_state;
96340cb5e5dSvi 
96440cb5e5dSvi 	if (method == NOTIFY) {
96540cb5e5dSvi 		int			error;
96640cb5e5dSvi 		const sip_str_t		*dlg_id_val = NULL;
96740cb5e5dSvi 		const sip_str_t		*event;
96840cb5e5dSvi 		const sip_str_t		*id_val = NULL;
96940cb5e5dSvi 		sip_header_value_t	ev_val;
97040cb5e5dSvi 		sip_hdr_value_t		*dlg_ev_val = NULL;
97140cb5e5dSvi 
97240cb5e5dSvi 		event = sip_get_event((sip_msg_t)sip_msg, &error);
97340cb5e5dSvi 		if (event == NULL || error != 0) {
97440cb5e5dSvi 			sip_free_header(thdr);
97540cb5e5dSvi 			return (NULL);
97640cb5e5dSvi 		}
97740cb5e5dSvi 		ev_val = (sip_header_value_t)sip_get_header_value(evhdr,
97840cb5e5dSvi 		    &error);
97940cb5e5dSvi 		if (ev_val != NULL)
98040cb5e5dSvi 			id_val = sip_get_param_value(ev_val, "id", &error);
98140cb5e5dSvi 		if (error == 0) {
98240cb5e5dSvi 			dlg_ev_val = (sip_hdr_value_t *)sip_get_header_value(
98340cb5e5dSvi 			    dialog->sip_dlg_event, &error);
98440cb5e5dSvi 		}
98540cb5e5dSvi 		if (dlg_ev_val == NULL || error != 0) {
98640cb5e5dSvi 			sip_free_header(thdr);
98740cb5e5dSvi 			return (NULL);
98840cb5e5dSvi 		}
98940cb5e5dSvi 		dlg_id_val = sip_get_param_value((sip_header_value_t)dlg_ev_val,
99040cb5e5dSvi 		    "id", &error);
99140cb5e5dSvi 		if (error != 0 ||
99240cb5e5dSvi 		    dlg_ev_val->str_val_len != event->sip_str_len ||
99340cb5e5dSvi 		    strncmp(dlg_ev_val->str_val_ptr, event->sip_str_ptr,
99440cb5e5dSvi 		    event->sip_str_len != 0)) {
99540cb5e5dSvi 			sip_free_header(thdr);
99640cb5e5dSvi 			return (NULL);
99740cb5e5dSvi 		}
99840cb5e5dSvi 		if ((dlg_id_val == NULL && id_val != NULL) ||
99940cb5e5dSvi 		    (dlg_id_val != NULL && id_val == NULL)) {
100040cb5e5dSvi 			sip_free_header(thdr);
100140cb5e5dSvi 			return (NULL);
100240cb5e5dSvi 		} else if (dlg_id_val != NULL && id_val != NULL) {
100340cb5e5dSvi 			if (dlg_id_val->sip_str_len != id_val->sip_str_len ||
100440cb5e5dSvi 			    strncasecmp(dlg_id_val->sip_str_ptr,
100540cb5e5dSvi 			    id_val->sip_str_ptr, dlg_id_val->sip_str_len) !=
100640cb5e5dSvi 			    0) {
100740cb5e5dSvi 				sip_free_header(thdr);
100840cb5e5dSvi 				return (NULL);
100940cb5e5dSvi 			}
101040cb5e5dSvi 		}
101140cb5e5dSvi 		if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
101240cb5e5dSvi 			dialog->sip_dlg_remote_uri_tag = thdr;
101340cb5e5dSvi 			if ((dialog->sip_dlg_remote_target =
101440cb5e5dSvi 			    sip_dup_header(chdr)) == NULL) {
101540cb5e5dSvi 				sip_free_header(thdr);
101640cb5e5dSvi 				return (NULL);
101740cb5e5dSvi 			}
101840cb5e5dSvi 		} else {
101940cb5e5dSvi 			dialog->sip_dlg_local_uri_tag = thdr;
102040cb5e5dSvi 		}
102140cb5e5dSvi 		dialog->sip_dlg_state = SIP_DLG_CONFIRMED;
102240cb5e5dSvi 	} else {
102340cb5e5dSvi 		resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
102440cb5e5dSvi 		(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
1025*943efbc3Sgm 		if (dialog->sip_dlg_state != SIP_DLG_NEW) {
1026*943efbc3Sgm 			sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
1027*943efbc3Sgm 			    SIP_ASSERT_ERROR, __FILE__, __LINE__);
1028*943efbc3Sgm 		}
102940cb5e5dSvi 		assert(dialog->sip_dlg_state == SIP_DLG_NEW);
103040cb5e5dSvi 		if (dialog->sip_dlg_remote_target == NULL && chdr != NULL) {
1031*943efbc3Sgm 			if (dialog->sip_dlg_type != SIP_UAC_DIALOG) {
1032*943efbc3Sgm 				sip_write_to_log((void *)dialog,
1033*943efbc3Sgm 				    SIP_DIALOG_LOG | SIP_ASSERT_ERROR,
1034*943efbc3Sgm 				    __FILE__, __LINE__);
1035*943efbc3Sgm 			}
103640cb5e5dSvi 			assert(dialog->sip_dlg_type == SIP_UAC_DIALOG);
103740cb5e5dSvi 			if ((dialog->sip_dlg_remote_target =
103840cb5e5dSvi 			    sip_dup_header(chdr)) == NULL) {
103940cb5e5dSvi 				(void) pthread_mutex_unlock(
104040cb5e5dSvi 				    &dialog->sip_dlg_mutex);
104140cb5e5dSvi 				if (alloc_thdr)
104240cb5e5dSvi 					sip_free_header(thdr);
10432c2c4183Svi 				goto terminate_new_dlg;
104440cb5e5dSvi 			}
104540cb5e5dSvi 			if (sip_dialog_get_route_set(dialog, sip_msg,
104640cb5e5dSvi 			    dialog->sip_dlg_type) != 0) {
104740cb5e5dSvi 				(void) pthread_mutex_unlock(
104840cb5e5dSvi 				    &dialog->sip_dlg_mutex);
104940cb5e5dSvi 				if (alloc_thdr)
105040cb5e5dSvi 					sip_free_header(thdr);
10512c2c4183Svi 				goto terminate_new_dlg;
105240cb5e5dSvi 			}
105340cb5e5dSvi 		}
105440cb5e5dSvi 		if (SIP_PROVISIONAL_RESP(resp_code)) {
105540cb5e5dSvi 			dialog->sip_dlg_state = SIP_DLG_EARLY;
105640cb5e5dSvi 		} else if (SIP_OK_RESP(resp_code)) {
105740cb5e5dSvi 			/*
105840cb5e5dSvi 			 * Per 12.1 the UAS must include the contact header
105940cb5e5dSvi 			 * for a dialog establishing response, so if we
106040cb5e5dSvi 			 * don't find one, we terminate it.
106140cb5e5dSvi 			 */
106240cb5e5dSvi 			if (dialog->sip_dlg_remote_target == NULL) {
106340cb5e5dSvi 				(void) pthread_mutex_unlock(
106440cb5e5dSvi 				    &dialog->sip_dlg_mutex);
106540cb5e5dSvi 				if (sip_ulp_dlg_del_cb != NULL) {
106640cb5e5dSvi 					sip_ulp_dlg_del_cb(dialog,
106740cb5e5dSvi 					    (sip_msg_t)sip_msg, NULL);
106840cb5e5dSvi 				}
106940cb5e5dSvi 				if (alloc_thdr)
107040cb5e5dSvi 					sip_free_header(thdr);
10712c2c4183Svi 				goto terminate_new_dlg;
107240cb5e5dSvi 			}
107340cb5e5dSvi 			dialog->sip_dlg_state = SIP_DLG_CONFIRMED;
107440cb5e5dSvi 		} else {
107540cb5e5dSvi 			(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
107640cb5e5dSvi 			if (sip_ulp_dlg_del_cb != NULL) {
107740cb5e5dSvi 				sip_ulp_dlg_del_cb(dialog, (sip_msg_t)sip_msg,
107840cb5e5dSvi 				    NULL);
107940cb5e5dSvi 			}
108040cb5e5dSvi 			if (alloc_thdr)
108140cb5e5dSvi 				sip_free_header(thdr);
10822c2c4183Svi 			goto terminate_new_dlg;
108340cb5e5dSvi 		}
108440cb5e5dSvi 		if (dialog->sip_dlg_type == SIP_UAS_DIALOG) {
108540cb5e5dSvi 			dialog->sip_dlg_local_uri_tag = thdr;
108640cb5e5dSvi 		} else {
108740cb5e5dSvi 			if ((dialog->sip_dlg_remote_uri_tag =
108840cb5e5dSvi 			    sip_dup_header(thdr)) == NULL) {
108940cb5e5dSvi 				(void) pthread_mutex_unlock(
109040cb5e5dSvi 				    &dialog->sip_dlg_mutex);
10912c2c4183Svi 				goto terminate_new_dlg;
109240cb5e5dSvi 			}
109340cb5e5dSvi 		}
109440cb5e5dSvi 	}
109540cb5e5dSvi 
1096d8a40387Sgm 	/*
1097d8a40387Sgm 	 * We take the local contact for UAS Dialog from the response (either
1098d8a40387Sgm 	 * NOTIFY for SUBSCRIBE request or from final response 2xx to INVITE
1099d8a40387Sgm 	 * request)
1100d8a40387Sgm 	 */
1101d8a40387Sgm 	if ((dialog->sip_dlg_type == SIP_UAS_DIALOG) && (dialog->sip_dlg_state
1102d8a40387Sgm 	    == SIP_DLG_CONFIRMED)) {
1103d8a40387Sgm 		if (chdr == NULL) {
1104d8a40387Sgm 			(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
1105d8a40387Sgm 			chdr = sip_search_for_header(sip_msg, SIP_CONTACT,
1106d8a40387Sgm 			    NULL);
1107d8a40387Sgm 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
1108d8a40387Sgm 		}
1109d8a40387Sgm 		if ((chdr == NULL) || ((dialog->sip_dlg_local_contact =
1110d8a40387Sgm 		    sip_dup_header(chdr)) == NULL)) {
1111d8a40387Sgm 			(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1112d8a40387Sgm 			if (alloc_thdr)
1113d8a40387Sgm 				sip_free_header(thdr);
1114d8a40387Sgm 			goto terminate_new_dlg;
1115d8a40387Sgm 		}
1116d8a40387Sgm 	}
1117d8a40387Sgm 
111840cb5e5dSvi 	/*
111940cb5e5dSvi 	 * Cancel the partial dialog timer
112040cb5e5dSvi 	 */
112140cb5e5dSvi 	if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
112240cb5e5dSvi 		SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
112340cb5e5dSvi 
112440cb5e5dSvi 	if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
112540cb5e5dSvi 		val =  sip_get_header_value(dialog->sip_dlg_local_uri_tag,
112640cb5e5dSvi 		    &error);
112740cb5e5dSvi 	} else {
112840cb5e5dSvi 		val =  sip_get_header_value(dialog->sip_dlg_remote_uri_tag,
112940cb5e5dSvi 		    &error);
113040cb5e5dSvi 	}
1131*943efbc3Sgm 	if (val == NULL || error != 0) {
1132*943efbc3Sgm 		sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
1133*943efbc3Sgm 		    SIP_ASSERT_ERROR, __FILE__, __LINE__);
1134*943efbc3Sgm 	}
113540cb5e5dSvi 	assert(val != NULL && error == 0);
113640cb5e5dSvi 	remtag = sip_get_param_value((sip_header_value_t)val, "tag", &error);
113740cb5e5dSvi 
113840cb5e5dSvi 	val = sip_get_header_value(dialog->sip_dlg_call_id, &error);
113940cb5e5dSvi 	callid = &((sip_hdr_value_t *)val)->str_val;
114040cb5e5dSvi 
114140cb5e5dSvi 	/*
114240cb5e5dSvi 	 * Get an ID for this dialog
114340cb5e5dSvi 	 */
114440cb5e5dSvi 	if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
114540cb5e5dSvi 		sip_md5_hash(remtag->sip_str_ptr, remtag->sip_str_len,
114640cb5e5dSvi 		    ttag->sip_str_ptr, ttag->sip_str_len,
114740cb5e5dSvi 		    callid->sip_str_ptr, callid->sip_str_len,
114840cb5e5dSvi 		    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id);
114940cb5e5dSvi 	} else {
115040cb5e5dSvi 		sip_md5_hash(ttag->sip_str_ptr, ttag->sip_str_len,
115140cb5e5dSvi 		    remtag->sip_str_ptr, remtag->sip_str_len,
115240cb5e5dSvi 		    callid->sip_str_ptr, callid->sip_str_len,
115340cb5e5dSvi 		    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id);
115440cb5e5dSvi 	}
115540cb5e5dSvi 
115640cb5e5dSvi 	SIP_DLG_REFCNT_INCR(dialog);
115740cb5e5dSvi 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
115840cb5e5dSvi 
115940cb5e5dSvi 	/*
116040cb5e5dSvi 	 * Add it to the hash table
116140cb5e5dSvi 	 */
116240cb5e5dSvi 	if (sip_hash_add(sip_dialog_hash, (void *)dialog,
116340cb5e5dSvi 	    SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) {
11642c2c4183Svi 	terminate_new_dlg:
116540cb5e5dSvi 		/*
116640cb5e5dSvi 		 * So that sip_dialog_delete() does not try to remove
116740cb5e5dSvi 		 * this from the hash table.
116840cb5e5dSvi 		 */
116940cb5e5dSvi 		(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
117040cb5e5dSvi 		if (dialog->sip_dlg_type == SIP_UAS_DIALOG) {
11712c2c4183Svi 			if (dialog->sip_dlg_local_uri_tag != NULL) {
11722c2c4183Svi 				sip_free_header(dialog->sip_dlg_local_uri_tag);
11732c2c4183Svi 				dialog->sip_dlg_local_uri_tag = NULL;
11742c2c4183Svi 			}
117540cb5e5dSvi 		} else {
11762c2c4183Svi 			if (dialog->sip_dlg_remote_uri_tag != NULL) {
11772c2c4183Svi 				sip_free_header(dialog->sip_dlg_remote_uri_tag);
11782c2c4183Svi 				dialog->sip_dlg_remote_uri_tag = NULL;
11792c2c4183Svi 			}
118040cb5e5dSvi 		}
118140cb5e5dSvi 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
118240cb5e5dSvi 		sip_dialog_terminate(dialog, (sip_msg_t)sip_msg);
118340cb5e5dSvi 		return (NULL);
118440cb5e5dSvi 	}
118540cb5e5dSvi 	if (sip_dlg_ulp_state_cb != NULL) {
118640cb5e5dSvi 		sip_dlg_ulp_state_cb((sip_dialog_t)dialog,
118740cb5e5dSvi 		    (sip_msg_t)sip_msg, prev_state, dialog->sip_dlg_state);
118840cb5e5dSvi 	}
118940cb5e5dSvi 	return ((sip_dialog_t)dialog);
119040cb5e5dSvi }
119140cb5e5dSvi 
119240cb5e5dSvi /*
119340cb5e5dSvi  * Check if this dialog is a match.
119440cb5e5dSvi  */
119540cb5e5dSvi boolean_t
119640cb5e5dSvi sip_dialog_match(void *obj, void *hindex)
119740cb5e5dSvi {
119840cb5e5dSvi 	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
119940cb5e5dSvi 
120040cb5e5dSvi 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
120140cb5e5dSvi 	if (dialog->sip_dlg_state == SIP_DLG_DESTROYED) {
120240cb5e5dSvi 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
120340cb5e5dSvi 		return (B_FALSE);
120440cb5e5dSvi 	}
120540cb5e5dSvi 	if (bcmp(dialog->sip_dlg_id, hindex,
120640cb5e5dSvi 	    sizeof (dialog->sip_dlg_id)) == 0) {
120740cb5e5dSvi 		SIP_DLG_REFCNT_INCR(dialog);
120840cb5e5dSvi 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
120940cb5e5dSvi 		return (B_TRUE);
121040cb5e5dSvi 	}
121140cb5e5dSvi 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
121240cb5e5dSvi 	return (B_FALSE);
121340cb5e5dSvi }
121440cb5e5dSvi 
121540cb5e5dSvi /*
121640cb5e5dSvi  * Don't delete, just take it out of the hash
121740cb5e5dSvi  */
121840cb5e5dSvi boolean_t
121940cb5e5dSvi sip_dialog_dontfree(void *obj, void *hindex, int *found)
122040cb5e5dSvi {
122140cb5e5dSvi 	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
122240cb5e5dSvi 
122340cb5e5dSvi 	*found = 0;
122440cb5e5dSvi 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
122540cb5e5dSvi 	if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id))
122640cb5e5dSvi 	    == 0) {
122740cb5e5dSvi 		*found = 1;
122840cb5e5dSvi 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
122940cb5e5dSvi 		return (B_TRUE);
123040cb5e5dSvi 	}
123140cb5e5dSvi 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
123240cb5e5dSvi 	return (B_FALSE);
123340cb5e5dSvi }
123440cb5e5dSvi 
123540cb5e5dSvi /*
123640cb5e5dSvi  * Free resources associated with the dialog, the object will be removed
123740cb5e5dSvi  * from the hash list by sip_hash_delete.
123840cb5e5dSvi  */
123940cb5e5dSvi boolean_t
124040cb5e5dSvi sip_dialog_free(void *obj, void *hindex, int *found)
124140cb5e5dSvi {
124240cb5e5dSvi 	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
124340cb5e5dSvi 
124440cb5e5dSvi 	*found = 0;
124540cb5e5dSvi 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
124640cb5e5dSvi 	if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id))
124740cb5e5dSvi 	    == 0) {
124840cb5e5dSvi 		*found = 1;
1249*943efbc3Sgm 		if (dialog->sip_dlg_state != SIP_DLG_DESTROYED) {
1250*943efbc3Sgm 			sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
1251*943efbc3Sgm 			    SIP_ASSERT_ERROR, __FILE__, __LINE__);
1252*943efbc3Sgm 		}
125340cb5e5dSvi 		assert(dialog->sip_dlg_state == SIP_DLG_DESTROYED);
125440cb5e5dSvi 		if (dialog->sip_dlg_ref_cnt != 0) {
125540cb5e5dSvi 			(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
125640cb5e5dSvi 			return (B_FALSE);
125740cb5e5dSvi 		}
1258*943efbc3Sgm 		sip_write_to_log((void *)dialog, SIP_DIALOG_LOG, NULL, 0);
125940cb5e5dSvi 		sip_release_dialog_res(dialog);
126040cb5e5dSvi 		return (B_TRUE);
126140cb5e5dSvi 	}
126240cb5e5dSvi 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
126340cb5e5dSvi 	return (B_FALSE);
126440cb5e5dSvi }
126540cb5e5dSvi 
126640cb5e5dSvi /*
126740cb5e5dSvi  * The UAS will receive the request from the transaction layer.  If the
126840cb5e5dSvi  * request has a tag in the To header field, the UAS core computes the
126940cb5e5dSvi  * dialog identifier corresponding to the request and compares it with
127040cb5e5dSvi  * existing dialogs.  If there is a match, this is a mid-dialog request.
127140cb5e5dSvi  */
127240cb5e5dSvi sip_dialog_t
127340cb5e5dSvi sip_dialog_find(_sip_msg_t *sip_msg)
127440cb5e5dSvi {
127540cb5e5dSvi 	const sip_str_t	*localtag;
127640cb5e5dSvi 	const sip_str_t	*remtag;
127740cb5e5dSvi 	const sip_str_t	*callid;
127840cb5e5dSvi 	uint16_t	digest[8];
127940cb5e5dSvi 	_sip_dialog_t	*dialog;
128040cb5e5dSvi 	boolean_t	is_request;
128140cb5e5dSvi 	int		error;
128240cb5e5dSvi 
128340cb5e5dSvi 	is_request = sip_msg_is_request((sip_msg_t)sip_msg, &error);
128440cb5e5dSvi 	if (error != 0)
128540cb5e5dSvi 		return (NULL);
128640cb5e5dSvi 	if (is_request) {
128740cb5e5dSvi 		localtag = sip_get_to_tag((sip_msg_t)sip_msg, &error);
128840cb5e5dSvi 		if (error == 0)
128940cb5e5dSvi 			remtag = sip_get_from_tag((sip_msg_t)sip_msg, &error);
129040cb5e5dSvi 	} else {
129140cb5e5dSvi 		remtag = sip_get_to_tag((sip_msg_t)sip_msg, &error);
129240cb5e5dSvi 		if (error == 0)
129340cb5e5dSvi 			localtag = sip_get_from_tag((sip_msg_t)sip_msg, &error);
129440cb5e5dSvi 	}
129540cb5e5dSvi 	if (error != 0)
129640cb5e5dSvi 		return (NULL);
129740cb5e5dSvi 	callid = sip_get_callid((sip_msg_t)sip_msg, &error);
129840cb5e5dSvi 	if (error != 0 || remtag == NULL || localtag == NULL ||
129940cb5e5dSvi 	    callid == NULL) {
130040cb5e5dSvi 		return (NULL);
130140cb5e5dSvi 	}
130240cb5e5dSvi 	sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len,
130340cb5e5dSvi 	    remtag->sip_str_ptr, remtag->sip_str_len,
130440cb5e5dSvi 	    callid->sip_str_ptr, callid->sip_str_len,
130540cb5e5dSvi 	    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest);
130640cb5e5dSvi 
130740cb5e5dSvi 	dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_hash,
130840cb5e5dSvi 	    (void *)digest, SIP_DIGEST_TO_HASH(digest), sip_dialog_match);
130940cb5e5dSvi 	if (dialog == NULL) {
131040cb5e5dSvi 		sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len,
131140cb5e5dSvi 		    NULL, 0, callid->sip_str_ptr, callid->sip_str_len,
131240cb5e5dSvi 		    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest);
131340cb5e5dSvi 		dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_phash,
131440cb5e5dSvi 		    (void *)digest, SIP_DIGEST_TO_HASH(digest),
131540cb5e5dSvi 		    sip_dialog_match);
131640cb5e5dSvi 	}
131740cb5e5dSvi 	return ((sip_dialog_t)dialog);
131840cb5e5dSvi }
131940cb5e5dSvi 
132040cb5e5dSvi /*
132140cb5e5dSvi  * We keep this partial dialog for the duration of the INVITE
132240cb5e5dSvi  * transaction timeout duration, i.e. Timer B.
132340cb5e5dSvi  */
132440cb5e5dSvi void
132540cb5e5dSvi sip_dlg_self_destruct(void *args)
132640cb5e5dSvi {
132740cb5e5dSvi 	sip_dialog_timer_obj_t	*tim_obj = (sip_dialog_timer_obj_t *)args;
132840cb5e5dSvi 	_sip_dialog_t		*dialog = (_sip_dialog_t *)tim_obj->dialog;
132940cb5e5dSvi 	int			index;
133040cb5e5dSvi 
133140cb5e5dSvi 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
1332*943efbc3Sgm 	if (dialog->sip_dlg_state != SIP_DLG_NEW) {
1333*943efbc3Sgm 		sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
1334*943efbc3Sgm 		    SIP_ASSERT_ERROR, __FILE__, __LINE__);
1335*943efbc3Sgm 	}
133640cb5e5dSvi 	assert(dialog->sip_dlg_state == SIP_DLG_NEW);
133740cb5e5dSvi 	dialog->sip_dlg_state = SIP_DLG_DESTROYED;
133840cb5e5dSvi 	if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
133940cb5e5dSvi 		index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id);
134040cb5e5dSvi 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
134140cb5e5dSvi 		sip_hash_delete(sip_dialog_phash, (void *)dialog->sip_dlg_id,
134240cb5e5dSvi 		    index, sip_dialog_dontfree);
134340cb5e5dSvi 	} else {
134440cb5e5dSvi 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
134540cb5e5dSvi 	}
134640cb5e5dSvi 	if (tim_obj->func != NULL)
134740cb5e5dSvi 		tim_obj->func(dialog, NULL, NULL);
134840cb5e5dSvi 	free(tim_obj);
134940cb5e5dSvi 	SIP_DLG_REFCNT_DECR(dialog);
135040cb5e5dSvi }
135140cb5e5dSvi 
135240cb5e5dSvi /*
135340cb5e5dSvi  * Terminate a dialog
135440cb5e5dSvi  */
135540cb5e5dSvi void
135640cb5e5dSvi sip_dialog_terminate(_sip_dialog_t *dialog, sip_msg_t sip_msg)
135740cb5e5dSvi {
135840cb5e5dSvi 	int	prev_state;
135940cb5e5dSvi 
136040cb5e5dSvi 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
136140cb5e5dSvi 	prev_state = dialog->sip_dlg_state;
136240cb5e5dSvi 	dialog->sip_dlg_state = SIP_DLG_DESTROYED;
136340cb5e5dSvi 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
136440cb5e5dSvi 	if (sip_dlg_ulp_state_cb != NULL) {
136540cb5e5dSvi 		sip_dlg_ulp_state_cb((sip_dialog_t)dialog, sip_msg, prev_state,
136640cb5e5dSvi 		    dialog->sip_dlg_state);
136740cb5e5dSvi 	}
136840cb5e5dSvi 	SIP_DLG_REFCNT_DECR(dialog);
136940cb5e5dSvi }
137040cb5e5dSvi 
137140cb5e5dSvi /*
137240cb5e5dSvi  * Delete a dialog
137340cb5e5dSvi  */
137440cb5e5dSvi void
137540cb5e5dSvi sip_dialog_delete(_sip_dialog_t *dialog)
137640cb5e5dSvi {
137740cb5e5dSvi 	int	index;
137840cb5e5dSvi 
137940cb5e5dSvi 	/*
138040cb5e5dSvi 	 * partial dialog, not in the hash table
138140cb5e5dSvi 	 */
138240cb5e5dSvi 	if (dialog->sip_dlg_local_uri_tag == NULL ||
138340cb5e5dSvi 	    dialog->sip_dlg_remote_uri_tag == NULL) {
138440cb5e5dSvi 		/*
138540cb5e5dSvi 		 * Cancel the partial dialog timer
138640cb5e5dSvi 		 */
138740cb5e5dSvi 		if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
138840cb5e5dSvi 			SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
1389*943efbc3Sgm 		sip_write_to_log((void *)dialog, SIP_DIALOG_LOG, NULL, 0);
139040cb5e5dSvi 		sip_release_dialog_res(dialog);
139140cb5e5dSvi 		return;
139240cb5e5dSvi 	}
139340cb5e5dSvi 	index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id);
139440cb5e5dSvi 	sip_hash_delete(sip_dialog_hash, (void *)dialog->sip_dlg_id, index,
139540cb5e5dSvi 	    sip_dialog_free);
139640cb5e5dSvi }
139740cb5e5dSvi 
139840cb5e5dSvi /*
139940cb5e5dSvi  * Get the remote target from the CONTACT header from the 200 OK response
140040cb5e5dSvi  */
140140cb5e5dSvi static boolean_t
140240cb5e5dSvi sip_get_rtarg(_sip_dialog_t *dialog, _sip_msg_t *sip_msg)
140340cb5e5dSvi {
140440cb5e5dSvi 	sip_header_t	chdr;
140540cb5e5dSvi 
140640cb5e5dSvi 	if (dialog->sip_dlg_remote_target != NULL)
140740cb5e5dSvi 		return (B_TRUE);
140840cb5e5dSvi 
140940cb5e5dSvi 	(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
141040cb5e5dSvi 	chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
141140cb5e5dSvi 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
141240cb5e5dSvi 	if (chdr == NULL)
141340cb5e5dSvi 		return (B_FALSE);
141440cb5e5dSvi 	if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) == NULL)
141540cb5e5dSvi 		return (B_FALSE);
141640cb5e5dSvi 
141740cb5e5dSvi 	return (B_TRUE);
141840cb5e5dSvi }
141940cb5e5dSvi 
142040cb5e5dSvi /*
142140cb5e5dSvi  * Process an incoming request/response
142240cb5e5dSvi  */
142340cb5e5dSvi /* ARGSUSED */
142440cb5e5dSvi int
142540cb5e5dSvi sip_dialog_process(_sip_msg_t *sip_msg, sip_dialog_t *sip_dialog)
142640cb5e5dSvi {
142740cb5e5dSvi 	boolean_t	request;
142840cb5e5dSvi 	_sip_dialog_t	*_dialog;
142940cb5e5dSvi 	int		error;
143040cb5e5dSvi 
1431*943efbc3Sgm 	_dialog = (_sip_dialog_t *)*sip_dialog;
1432*943efbc3Sgm 
1433*943efbc3Sgm 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
1434*943efbc3Sgm 	_dialog->sip_dlg_msgcnt++;
1435*943efbc3Sgm 	sip_add_log(&_dialog->sip_dlg_log[_dialog->sip_dlg_state],
1436*943efbc3Sgm 	    (sip_msg_t)sip_msg, _dialog->sip_dlg_msgcnt, SIP_DIALOG_LOG);
1437*943efbc3Sgm 	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
1438*943efbc3Sgm 
143940cb5e5dSvi 	request = sip_msg_is_request((sip_msg_t)sip_msg, &error);
144040cb5e5dSvi 	if (error != 0)
144140cb5e5dSvi 		return (EINVAL);
144240cb5e5dSvi 	if (request) {
144340cb5e5dSvi 		uint32_t	cseq;
144440cb5e5dSvi 		sip_method_t	method;
144540cb5e5dSvi 
144640cb5e5dSvi 		cseq = sip_get_callseq_num((sip_msg_t)sip_msg, &error);
144740cb5e5dSvi 		if (error != 0)
144840cb5e5dSvi 			return (EINVAL);
144940cb5e5dSvi 		method = sip_get_callseq_method((sip_msg_t)sip_msg, &error);
145040cb5e5dSvi 		if (error != 0)
145140cb5e5dSvi 			return (EINVAL);
145240cb5e5dSvi 		if (sip_get_request_method((sip_msg_t)sip_msg, &error) !=
145340cb5e5dSvi 		    method) {
145440cb5e5dSvi 			return (EINVAL);
145540cb5e5dSvi 		}
145640cb5e5dSvi 		(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
145740cb5e5dSvi 		/*
145840cb5e5dSvi 		 * Requests that do not change in any way the state
145940cb5e5dSvi 		 * of a dialog may be received within a dialog.
146040cb5e5dSvi 		 * They are processed as if they had been received
146140cb5e5dSvi 		 * outside the dialog.
146240cb5e5dSvi 		 * For dialogs that have been established with an
146340cb5e5dSvi 		 * INVITE, the only target refresh request defined is
146440cb5e5dSvi 		 * re-INVITE.
146540cb5e5dSvi 		 */
146640cb5e5dSvi 		if (_dialog->sip_dlg_method == INVITE &&
146740cb5e5dSvi 		    method == INVITE && _dialog->sip_dlg_remote_cseq != 0 &&
146840cb5e5dSvi 		    SIP_CSEQ_LT(cseq, _dialog->sip_dlg_remote_cseq)) {
146940cb5e5dSvi 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
147040cb5e5dSvi 			return (EPROTO);
147140cb5e5dSvi 		}
147240cb5e5dSvi 		/*
147340cb5e5dSvi 		 * Target-Refresh request
147440cb5e5dSvi 		 */
147540cb5e5dSvi 		if (_dialog->sip_dlg_method == INVITE && method == INVITE) {
147640cb5e5dSvi 			sip_header_t	chdr;
147740cb5e5dSvi 			sip_header_t	nchdr;
147840cb5e5dSvi 
147940cb5e5dSvi 			(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
148040cb5e5dSvi 			chdr = sip_search_for_header(sip_msg, SIP_CONTACT,
148140cb5e5dSvi 			    NULL);
148240cb5e5dSvi 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
148340cb5e5dSvi 			if (chdr != NULL &&
148440cb5e5dSvi 			    (nchdr = sip_dup_header(chdr)) != NULL) {
148540cb5e5dSvi 				if (_dialog->sip_dlg_remote_target != NULL) {
148640cb5e5dSvi 					sip_free_header(
148740cb5e5dSvi 					    _dialog->sip_dlg_remote_target);
148840cb5e5dSvi 				}
148940cb5e5dSvi 				_dialog->sip_dlg_remote_target = nchdr;
149040cb5e5dSvi 			}
149140cb5e5dSvi 		}
149240cb5e5dSvi 		_dialog->sip_dlg_remote_cseq = cseq;
149340cb5e5dSvi 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
149440cb5e5dSvi 	} else {
149540cb5e5dSvi 		int		resp_code;
149640cb5e5dSvi 		sip_method_t	method;
149740cb5e5dSvi 		int		error;
149840cb5e5dSvi 
149940cb5e5dSvi 		resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
150040cb5e5dSvi 		if (error == 0) {
150140cb5e5dSvi 			method = sip_get_callseq_method((sip_msg_t)sip_msg,
150240cb5e5dSvi 			    &error);
150340cb5e5dSvi 		}
150440cb5e5dSvi 		if (error != 0)
150540cb5e5dSvi 			return (error);
150640cb5e5dSvi 
150740cb5e5dSvi 		(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
15085878c602Sgm 		if (_dialog->sip_dlg_state == SIP_DLG_DESTROYED) {
15095878c602Sgm 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
15105878c602Sgm 			return (0);
15115878c602Sgm 		}
1512*943efbc3Sgm 		if (_dialog->sip_dlg_state != SIP_DLG_EARLY &&
1513*943efbc3Sgm 		    _dialog->sip_dlg_state != SIP_DLG_CONFIRMED) {
1514*943efbc3Sgm 			sip_write_to_log((void *)_dialog, SIP_DIALOG_LOG |
1515*943efbc3Sgm 			    SIP_ASSERT_ERROR, __FILE__, __LINE__);
1516*943efbc3Sgm 		}
151740cb5e5dSvi 		assert(_dialog->sip_dlg_state == SIP_DLG_EARLY ||
151840cb5e5dSvi 		    _dialog->sip_dlg_state == SIP_DLG_CONFIRMED);
151940cb5e5dSvi 		/*
152040cb5e5dSvi 		 * Let the user delete the dialog if it is not a 1XX/2XX resp
152140cb5e5dSvi 		 * for an early INVITE dialog.
152240cb5e5dSvi 		 */
152340cb5e5dSvi 		if (SIP_OK_RESP(resp_code)) {
152440cb5e5dSvi 			if (method == INVITE) {
152540cb5e5dSvi 				if (!sip_get_rtarg(_dialog, sip_msg)) {
152640cb5e5dSvi 					(void) pthread_mutex_unlock(
152740cb5e5dSvi 					    &_dialog->sip_dlg_mutex);
152840cb5e5dSvi 					if (sip_ulp_dlg_del_cb != NULL) {
152940cb5e5dSvi 						sip_ulp_dlg_del_cb(
153040cb5e5dSvi 						    (sip_dialog_t)_dialog,
153140cb5e5dSvi 						    (sip_msg_t)sip_msg, NULL);
153240cb5e5dSvi 					}
153340cb5e5dSvi 					sip_dialog_terminate(_dialog,
153440cb5e5dSvi 					    (sip_msg_t)sip_msg);
153540cb5e5dSvi 					return (0);
153640cb5e5dSvi 				}
153740cb5e5dSvi 				if (_dialog->sip_dlg_state == SIP_DLG_EARLY) {
153840cb5e5dSvi 					_dialog->sip_dlg_state =
153940cb5e5dSvi 					    SIP_DLG_CONFIRMED;
154040cb5e5dSvi 					(void) sip_dlg_recompute_rset(_dialog,
154140cb5e5dSvi 					    sip_msg, SIP_UAC_DIALOG);
1542*943efbc3Sgm 					(void) pthread_mutex_unlock(
1543*943efbc3Sgm 					    &_dialog->sip_dlg_mutex);
154440cb5e5dSvi 					if (sip_dlg_ulp_state_cb != NULL) {
154540cb5e5dSvi 						sip_dlg_ulp_state_cb(
154640cb5e5dSvi 						    (sip_dialog_t)_dialog,
154740cb5e5dSvi 						    sip_msg, SIP_DLG_EARLY,
154840cb5e5dSvi 						    _dialog->sip_dlg_state);
154940cb5e5dSvi 					}
155040cb5e5dSvi 					return (0);
1551d8a40387Sgm 				} else if (_dialog->sip_dlg_new_local_contact
1552d8a40387Sgm 				    != NULL) {
1553*943efbc3Sgm 					if (_dialog->sip_dlg_local_contact ==
1554*943efbc3Sgm 					    NULL) {
1555*943efbc3Sgm 						(void) sip_write_to_log((void *)
1556*943efbc3Sgm 						    _dialog, SIP_DIALOG_LOG |
1557*943efbc3Sgm 						    SIP_ASSERT_ERROR,  __FILE__,
1558*943efbc3Sgm 						    __LINE__);
1559*943efbc3Sgm 					}
1560d8a40387Sgm 					assert(_dialog->sip_dlg_local_contact
1561d8a40387Sgm 					    != NULL);
1562d8a40387Sgm 					sip_free_header(_dialog->
1563111456ccSgm 					    sip_dlg_local_contact);
1564d8a40387Sgm 					_dialog->sip_dlg_local_contact =
1565d8a40387Sgm 					    _dialog->sip_dlg_new_local_contact;
1566d8a40387Sgm 					_dialog->sip_dlg_new_local_contact =
1567d8a40387Sgm 					    NULL;
156840cb5e5dSvi 				}
156940cb5e5dSvi 			}
157040cb5e5dSvi 		}
157140cb5e5dSvi 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
157240cb5e5dSvi 	}
157340cb5e5dSvi 	return (0);
157440cb5e5dSvi }
157540cb5e5dSvi 
157640cb5e5dSvi /*
157740cb5e5dSvi  * Copy partial dialog to create a complete dialog
157840cb5e5dSvi  */
157940cb5e5dSvi _sip_dialog_t *
158040cb5e5dSvi sip_copy_partial_dialog(_sip_dialog_t *dialog)
158140cb5e5dSvi {
158240cb5e5dSvi 	_sip_dialog_t	*new_dlg;
158340cb5e5dSvi 
158440cb5e5dSvi 	new_dlg =  calloc(1, sizeof (_sip_dialog_t));
158540cb5e5dSvi 	if (new_dlg == NULL)
158640cb5e5dSvi 		return (NULL);
158740cb5e5dSvi 	if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) {
158840cb5e5dSvi 		new_dlg->sip_dlg_req_uri.sip_str_ptr =
158940cb5e5dSvi 		    malloc(dialog->sip_dlg_req_uri.sip_str_len + 1);
159040cb5e5dSvi 		if (new_dlg->sip_dlg_req_uri.sip_str_ptr == NULL) {
159140cb5e5dSvi 			free(new_dlg);
159240cb5e5dSvi 			return (NULL);
159340cb5e5dSvi 		}
159440cb5e5dSvi 		(void) strncpy(new_dlg->sip_dlg_req_uri.sip_str_ptr,
159540cb5e5dSvi 		    dialog->sip_dlg_req_uri.sip_str_ptr,
159640cb5e5dSvi 		    dialog->sip_dlg_req_uri.sip_str_len);
159740cb5e5dSvi 		new_dlg->sip_dlg_req_uri.sip_str_ptr[
159840cb5e5dSvi 		    dialog->sip_dlg_req_uri.sip_str_len] = '\0';
159940cb5e5dSvi 		new_dlg->sip_dlg_req_uri.sip_str_len =
160040cb5e5dSvi 		    dialog->sip_dlg_req_uri.sip_str_len;
160140cb5e5dSvi 	}
160240cb5e5dSvi 	if (dialog->sip_dlg_route_set != NULL) {
1603*943efbc3Sgm 		if (dialog->sip_dlg_rset.sip_str_ptr == NULL) {
1604*943efbc3Sgm 			sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
1605*943efbc3Sgm 			    SIP_ASSERT_ERROR, __FILE__, __LINE__);
1606*943efbc3Sgm 		}
160740cb5e5dSvi 		assert(dialog->sip_dlg_rset.sip_str_ptr != NULL);
160840cb5e5dSvi 		new_dlg->sip_dlg_rset.sip_str_ptr =
160940cb5e5dSvi 		    malloc(dialog->sip_dlg_rset.sip_str_len + 1);
161040cb5e5dSvi 		if (new_dlg->sip_dlg_rset.sip_str_ptr == NULL) {
161140cb5e5dSvi 			if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL)
161240cb5e5dSvi 				free(new_dlg->sip_dlg_req_uri.sip_str_ptr);
161340cb5e5dSvi 			free(new_dlg);
161440cb5e5dSvi 			return (NULL);
161540cb5e5dSvi 		}
161640cb5e5dSvi 		(void) strncpy(new_dlg->sip_dlg_rset.sip_str_ptr,
161740cb5e5dSvi 		    dialog->sip_dlg_rset.sip_str_ptr,
161840cb5e5dSvi 		    dialog->sip_dlg_rset.sip_str_len);
161940cb5e5dSvi 		new_dlg->sip_dlg_rset.sip_str_ptr[
162040cb5e5dSvi 		    dialog->sip_dlg_rset.sip_str_len] = '\0';
162140cb5e5dSvi 		new_dlg->sip_dlg_rset.sip_str_len =
162240cb5e5dSvi 		    dialog->sip_dlg_rset.sip_str_len;
162340cb5e5dSvi 
162440cb5e5dSvi 		new_dlg->sip_dlg_route_set =
162540cb5e5dSvi 		    sip_dup_header(dialog->sip_dlg_route_set);
162640cb5e5dSvi 		if (new_dlg->sip_dlg_route_set == NULL) {
162740cb5e5dSvi 			free(new_dlg->sip_dlg_rset.sip_str_ptr);
162840cb5e5dSvi 			if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL)
162940cb5e5dSvi 				free(new_dlg->sip_dlg_req_uri.sip_str_ptr);
163040cb5e5dSvi 			free(new_dlg);
163140cb5e5dSvi 			return (NULL);
163240cb5e5dSvi 		}
163340cb5e5dSvi 	}
163440cb5e5dSvi 	if ((new_dlg->sip_dlg_local_uri_tag =
163540cb5e5dSvi 	    sip_dup_header(dialog->sip_dlg_local_uri_tag)) == NULL ||
163640cb5e5dSvi 	    (new_dlg->sip_dlg_remote_target =
163740cb5e5dSvi 	    sip_dup_header(dialog->sip_dlg_remote_target)) == NULL ||
1638d8a40387Sgm 	    (new_dlg->sip_dlg_local_contact =
1639d8a40387Sgm 	    sip_dup_header(dialog->sip_dlg_local_contact)) == NULL ||
164040cb5e5dSvi 	    (new_dlg->sip_dlg_call_id =
164140cb5e5dSvi 	    sip_dup_header(dialog->sip_dlg_call_id)) == NULL) {
164240cb5e5dSvi 		sip_release_dialog_res(new_dlg);
164340cb5e5dSvi 		return (NULL);
164440cb5e5dSvi 	}
164540cb5e5dSvi 	if (dialog->sip_dlg_event != NULL) {
164640cb5e5dSvi 		new_dlg->sip_dlg_event = sip_dup_header(dialog->sip_dlg_event);
164740cb5e5dSvi 		if (new_dlg->sip_dlg_event == NULL) {
164840cb5e5dSvi 			sip_release_dialog_res(new_dlg);
164940cb5e5dSvi 			return (NULL);
165040cb5e5dSvi 		}
165140cb5e5dSvi 	}
165240cb5e5dSvi 	new_dlg->sip_dlg_local_cseq = dialog->sip_dlg_local_cseq;
165340cb5e5dSvi 	new_dlg->sip_dlg_type = dialog->sip_dlg_type;
165440cb5e5dSvi 	new_dlg->sip_dlg_on_fork = B_FALSE;
165540cb5e5dSvi 	(void) pthread_mutex_init(&new_dlg->sip_dlg_mutex, NULL);
165640cb5e5dSvi 
165740cb5e5dSvi 	return (new_dlg);
165840cb5e5dSvi }
165940cb5e5dSvi 
166040cb5e5dSvi /*
166140cb5e5dSvi  * Update the dialog using the response
166240cb5e5dSvi  */
166340cb5e5dSvi sip_dialog_t
166440cb5e5dSvi sip_update_dialog(sip_dialog_t dialog, _sip_msg_t *sip_msg)
166540cb5e5dSvi {
166640cb5e5dSvi 	_sip_dialog_t	*_dialog;
166740cb5e5dSvi 	boolean_t	isreq;
166840cb5e5dSvi 	sip_method_t	method;
166940cb5e5dSvi 	int		resp_code = 0;
167040cb5e5dSvi 	int		prev_state;
167140cb5e5dSvi 	boolean_t	decr_ref = B_FALSE;
167240cb5e5dSvi 	int		error;
167340cb5e5dSvi 
1674*943efbc3Sgm 	_dialog = (_sip_dialog_t *)dialog;
1675*943efbc3Sgm 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
1676*943efbc3Sgm 	_dialog->sip_dlg_msgcnt++;
1677*943efbc3Sgm 	sip_add_log(&_dialog->sip_dlg_log[_dialog->sip_dlg_state],
1678*943efbc3Sgm 	    (sip_msg_t)sip_msg, _dialog->sip_dlg_msgcnt, SIP_DIALOG_LOG);
1679*943efbc3Sgm 	(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
1680*943efbc3Sgm 
168140cb5e5dSvi 	isreq = sip_msg_is_request((sip_msg_t)sip_msg, &error);
168240cb5e5dSvi 	if (error != 0)
168340cb5e5dSvi 		return (dialog);
168440cb5e5dSvi 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
168540cb5e5dSvi 	if (isreq) {
168640cb5e5dSvi 		method = sip_get_request_method((sip_msg_t)sip_msg, &error);
168740cb5e5dSvi 		if (error != 0 || _dialog->sip_dlg_method != SUBSCRIBE ||
168840cb5e5dSvi 		    method != NOTIFY) {
168940cb5e5dSvi 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
169040cb5e5dSvi 			return (dialog);
169140cb5e5dSvi 		}
169240cb5e5dSvi 	} else {
169340cb5e5dSvi 		resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
169440cb5e5dSvi 		if (error != 0) {
169540cb5e5dSvi 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
169640cb5e5dSvi 			return (dialog);
169740cb5e5dSvi 		}
1698d8a40387Sgm 		method = sip_get_callseq_method((sip_msg_t)sip_msg, &error);
1699d8a40387Sgm 		if (error != 0) {
1700d8a40387Sgm 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
1701d8a40387Sgm 			return (dialog);
1702d8a40387Sgm 		}
170340cb5e5dSvi 	}
170440cb5e5dSvi 	prev_state = _dialog->sip_dlg_state;
170540cb5e5dSvi 	if (_dialog->sip_dlg_state == SIP_DLG_CONFIRMED) {
170640cb5e5dSvi 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
170740cb5e5dSvi 	} else if (_dialog->sip_dlg_state == SIP_DLG_EARLY) {
170840cb5e5dSvi 		/*
170940cb5e5dSvi 		 * Let the user delete the dialog if it is not a 1XX/2XX resp
171040cb5e5dSvi 		 * for an early dialog.
171140cb5e5dSvi 		 */
1712*943efbc3Sgm 		if (isreq) {
1713*943efbc3Sgm 			sip_write_to_log((void *)_dialog, SIP_DIALOG_LOG |
1714*943efbc3Sgm 			    SIP_ASSERT_ERROR, __FILE__, __LINE__);
1715*943efbc3Sgm 		}
171640cb5e5dSvi 		assert(!isreq);
171740cb5e5dSvi 		if (SIP_OK_RESP(resp_code)) {
171840cb5e5dSvi 			_dialog->sip_dlg_state = SIP_DLG_CONFIRMED;
1719d8a40387Sgm 			/*
1720d8a40387Sgm 			 * If we recieved provisional response before we would
1721d8a40387Sgm 			 * not have captured local contact. So store it now.
1722d8a40387Sgm 			 */
1723d8a40387Sgm 			if (_dialog->sip_dlg_type == SIP_UAS_DIALOG && _dialog->
1724d8a40387Sgm 			    sip_dlg_method == INVITE && method == INVITE) {
1725d8a40387Sgm 				sip_header_t chdr;
1726d8a40387Sgm 				(void) pthread_mutex_lock(&sip_msg->
1727d8a40387Sgm 				    sip_msg_mutex);
1728d8a40387Sgm 				chdr = sip_search_for_header(sip_msg,
1729d8a40387Sgm 				    SIP_CONTACT, NULL);
1730d8a40387Sgm 				(void) pthread_mutex_unlock(&sip_msg->
1731d8a40387Sgm 				    sip_msg_mutex);
1732d8a40387Sgm 				if (chdr != NULL) {
1733d8a40387Sgm 					_dialog->sip_dlg_local_contact
1734d8a40387Sgm 					    = sip_dup_header(chdr);
1735d8a40387Sgm 					_dialog->sip_dlg_new_local_contact =
1736d8a40387Sgm 					    NULL;
1737d8a40387Sgm 				}
1738d8a40387Sgm 			}
173940cb5e5dSvi 			(void) sip_dlg_recompute_rset(_dialog, sip_msg,
174040cb5e5dSvi 			    SIP_UAS_DIALOG);
1741*943efbc3Sgm 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
174240cb5e5dSvi 			if (sip_dlg_ulp_state_cb != NULL) {
174340cb5e5dSvi 				sip_dlg_ulp_state_cb(dialog, (sip_msg_t)sip_msg,
174440cb5e5dSvi 				    prev_state, dialog->sip_dlg_state);
174540cb5e5dSvi 			}
174640cb5e5dSvi 		} else {
174740cb5e5dSvi 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
174840cb5e5dSvi 		}
174940cb5e5dSvi 	} else if (_dialog->sip_dlg_state == SIP_DLG_NEW) {
175040cb5e5dSvi 		if (!isreq && _dialog->sip_dlg_method == SUBSCRIBE &&
175140cb5e5dSvi 		    SIP_PROVISIONAL_RESP(resp_code)) {
175240cb5e5dSvi 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
175340cb5e5dSvi 			return (dialog);
175440cb5e5dSvi 		}
175540cb5e5dSvi 		if (_dialog->sip_dlg_type == SIP_UAC_DIALOG) {
175640cb5e5dSvi 			_sip_dialog_t	*new_dlg;
175740cb5e5dSvi 
175840cb5e5dSvi 			if (_dialog->sip_dlg_on_fork) {
175940cb5e5dSvi 				new_dlg = sip_copy_partial_dialog(_dialog);
176040cb5e5dSvi 				if (new_dlg == NULL) {
176140cb5e5dSvi 					(void) pthread_mutex_unlock(
176240cb5e5dSvi 					    &_dialog->sip_dlg_mutex);
176340cb5e5dSvi 					return (dialog);
176440cb5e5dSvi 				}
176540cb5e5dSvi 				/*
176640cb5e5dSvi 				 * This decr/incr dance is because the caller
176740cb5e5dSvi 				 * has incremented the ref on the partial
176840cb5e5dSvi 				 * dialog, we release it here and incr the
176940cb5e5dSvi 				 * ref on the new dialog which will be
177040cb5e5dSvi 				 * released by the caller.
177140cb5e5dSvi 				 */
177240cb5e5dSvi 				(void) pthread_mutex_unlock(
177340cb5e5dSvi 				    &_dialog->sip_dlg_mutex);
177440cb5e5dSvi 				SIP_DLG_REFCNT_DECR(_dialog);
177540cb5e5dSvi 				_dialog = new_dlg;
177640cb5e5dSvi 				(void) pthread_mutex_lock(
177740cb5e5dSvi 				    &_dialog->sip_dlg_mutex);
177840cb5e5dSvi 				SIP_DLG_REFCNT_INCR(_dialog);
177940cb5e5dSvi 			} else {
178040cb5e5dSvi 				int	index;
178140cb5e5dSvi 
178240cb5e5dSvi 				/*
178340cb5e5dSvi 				 * take it out of the list so that further
178440cb5e5dSvi 				 * responses will not result in a dialog.
178540cb5e5dSvi 				 * We will have an extra refcount when we
178640cb5e5dSvi 				 * come back from sip_complete_dialog(), i.e.
178740cb5e5dSvi 				 * one when the partial dialog was created -
178840cb5e5dSvi 				 * in sip_seed_dialog(), one held by the caller
178940cb5e5dSvi 				 * and one that will be added by
179040cb5e5dSvi 				 * sip_complete_dialog(). We need to release
179140cb5e5dSvi 				 * the one added by the sip_seed_dialog(),
179240cb5e5dSvi 				 * since the one in sip_complete_dialog()
179340cb5e5dSvi 				 * is for the same purpose.
179440cb5e5dSvi 				 */
179540cb5e5dSvi 				if (SIP_IS_TIMER_RUNNING(
179640cb5e5dSvi 				    _dialog->sip_dlg_timer)) {
179740cb5e5dSvi 					SIP_CANCEL_TIMER(
179840cb5e5dSvi 					    _dialog->sip_dlg_timer);
179940cb5e5dSvi 				}
180040cb5e5dSvi 				index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id);
180140cb5e5dSvi 				(void) pthread_mutex_unlock(
180240cb5e5dSvi 				    &_dialog->sip_dlg_mutex);
180340cb5e5dSvi 				sip_hash_delete(sip_dialog_phash,
180440cb5e5dSvi 				    (void *)_dialog->sip_dlg_id,
180540cb5e5dSvi 				    index, sip_dialog_dontfree);
180640cb5e5dSvi 				(void) pthread_mutex_lock(
180740cb5e5dSvi 				    &_dialog->sip_dlg_mutex);
180840cb5e5dSvi 				decr_ref = B_TRUE;
180940cb5e5dSvi 			}
181040cb5e5dSvi 		} else {
181140cb5e5dSvi 			decr_ref = B_TRUE;
181240cb5e5dSvi 		}
181340cb5e5dSvi 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
181440cb5e5dSvi 		if ((dialog = sip_complete_dialog(sip_msg, _dialog)) ==
181540cb5e5dSvi 		    NULL) {
18162c2c4183Svi 			if (_dialog->sip_dlg_type == SIP_UAC_DIALOG && decr_ref)
18172c2c4183Svi 				SIP_DLG_REFCNT_DECR(_dialog);
181840cb5e5dSvi 			return (NULL);
181940cb5e5dSvi 		}
182040cb5e5dSvi 		if (decr_ref)
182140cb5e5dSvi 			SIP_DLG_REFCNT_DECR(_dialog);
182240cb5e5dSvi 	} else {
182340cb5e5dSvi 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
182440cb5e5dSvi 	}
182540cb5e5dSvi 	return (dialog);
182640cb5e5dSvi }
182740cb5e5dSvi 
182840cb5e5dSvi /*
182940cb5e5dSvi  * Initialize the hash table
183040cb5e5dSvi  */
183140cb5e5dSvi void
183240cb5e5dSvi sip_dialog_init(void (*ulp_dlg_del) (sip_dialog_t, sip_msg_t, void *),
183340cb5e5dSvi     void (*ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int))
183440cb5e5dSvi {
183540cb5e5dSvi 	int	cnt;
183640cb5e5dSvi 
183740cb5e5dSvi 	for (cnt = 0; cnt < SIP_HASH_SZ; cnt++) {
183840cb5e5dSvi 		sip_dialog_hash[cnt].hash_count = 0;
183940cb5e5dSvi 		sip_dialog_hash[cnt].hash_head = NULL;
184040cb5e5dSvi 		sip_dialog_hash[cnt].hash_tail = NULL;
184140cb5e5dSvi 		(void) pthread_mutex_init(
184240cb5e5dSvi 		    &sip_dialog_hash[cnt].sip_hash_mutex, NULL);
184340cb5e5dSvi 		sip_dialog_phash[cnt].hash_count = 0;
184440cb5e5dSvi 		sip_dialog_phash[cnt].hash_head = NULL;
184540cb5e5dSvi 		sip_dialog_phash[cnt].hash_tail = NULL;
184640cb5e5dSvi 		(void) pthread_mutex_init(
184740cb5e5dSvi 		    &sip_dialog_phash[cnt].sip_hash_mutex, NULL);
184840cb5e5dSvi 	}
184940cb5e5dSvi 	if (ulp_dlg_del != NULL)
185040cb5e5dSvi 		sip_ulp_dlg_del_cb = ulp_dlg_del;
185140cb5e5dSvi 
185240cb5e5dSvi 	if (ulp_state_cb != NULL)
185340cb5e5dSvi 		sip_dlg_ulp_state_cb = ulp_state_cb;
185440cb5e5dSvi }
1855d8a40387Sgm 
1856d8a40387Sgm /*
1857d8a40387Sgm  * Copy the new contact header of re-INVITE
1858d8a40387Sgm  */
1859d8a40387Sgm void
1860d8a40387Sgm sip_dialog_add_new_contact(sip_dialog_t dialog, _sip_msg_t *sip_msg)
1861d8a40387Sgm {
1862d8a40387Sgm 	sip_header_t chdr = NULL;
1863d8a40387Sgm 	sip_header_t nhdr = NULL;
1864d8a40387Sgm 
1865d8a40387Sgm 	(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
1866d8a40387Sgm 	chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
1867d8a40387Sgm 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
1868d8a40387Sgm 
1869d8a40387Sgm 	if (chdr == NULL)
1870d8a40387Sgm 		return;
1871d8a40387Sgm 
1872d8a40387Sgm 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
1873d8a40387Sgm 	if (dialog->sip_dlg_method != INVITE || dialog->sip_dlg_state
1874d8a40387Sgm 	    != SIP_DLG_CONFIRMED) {
1875d8a40387Sgm 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1876d8a40387Sgm 		return;
1877d8a40387Sgm 	}
1878d8a40387Sgm 
1879d8a40387Sgm 	if (((nhdr = sip_dup_header(chdr)) != NULL)) {
1880d8a40387Sgm 		if (dialog->sip_dlg_new_local_contact != NULL)
1881d8a40387Sgm 			sip_free_header(dialog->sip_dlg_new_local_contact);
1882d8a40387Sgm 		dialog->sip_dlg_new_local_contact = nhdr;
1883d8a40387Sgm 	}
1884d8a40387Sgm 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1885d8a40387Sgm }
1886*943efbc3Sgm 
1887*943efbc3Sgm /*
1888*943efbc3Sgm  * Given a state, return the  string - This is mostly for debug purposes
1889*943efbc3Sgm  */
1890*943efbc3Sgm char *
1891*943efbc3Sgm sip_get_dialog_state_str(int state)
1892*943efbc3Sgm {
1893*943efbc3Sgm 	switch (state) {
1894*943efbc3Sgm 		case SIP_DLG_NEW:
1895*943efbc3Sgm 			return ("SIP_DLG_NEW");
1896*943efbc3Sgm 		case SIP_DLG_EARLY:
1897*943efbc3Sgm 			return ("SIP_DLG_EARLY");
1898*943efbc3Sgm 		case SIP_DLG_CONFIRMED:
1899*943efbc3Sgm 			return ("SIP_DLG_CONFIRMED");
1900*943efbc3Sgm 		case SIP_DLG_DESTROYED:
1901*943efbc3Sgm 			return ("SIP_DLG_DESTROYED");
1902*943efbc3Sgm 		default:
1903*943efbc3Sgm 			return ("UNKNOWN");
1904*943efbc3Sgm 	}
1905*943efbc3Sgm }
1906