140cb5e5vi/*
240cb5e5vi * CDDL HEADER START
340cb5e5vi *
440cb5e5vi * The contents of this file are subject to the terms of the
540cb5e5vi * Common Development and Distribution License (the "License").
640cb5e5vi * You may not use this file except in compliance with the License.
740cb5e5vi *
840cb5e5vi * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
940cb5e5vi * or http://www.opensolaris.org/os/licensing.
1040cb5e5vi * See the License for the specific language governing permissions
1140cb5e5vi * and limitations under the License.
1240cb5e5vi *
1340cb5e5vi * When distributing Covered Code, include this CDDL HEADER in each
1440cb5e5vi * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1540cb5e5vi * If applicable, add the following below this CDDL HEADER, with the
1640cb5e5vi * fields enclosed by brackets "[]" replaced with your own identifying
1740cb5e5vi * information: Portions Copyright [yyyy] [name of copyright owner]
1840cb5e5vi *
1940cb5e5vi * CDDL HEADER END
2040cb5e5vi */
2140cb5e5vi
2240cb5e5vi/*
23943efbcgm * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2440cb5e5vi * Use is subject to license terms.
2540cb5e5vi */
2640cb5e5vi
2740cb5e5vi#pragma ident	"%Z%%M%	%I%	%E% SMI"
2840cb5e5vi
292c2c418vi#include <stdio.h>
302c2c418vi#include <stdlib.h>
312c2c418vi#include <assert.h>
322c2c418vi#include <errno.h>
332c2c418vi#include <pthread.h>
342c2c418vi#include <strings.h>
352c2c418vi#include <sip.h>
362c2c418vi
3740cb5e5vi#include "sip_msg.h"
3840cb5e5vi#include "sip_miscdefs.h"
392c2c418vi#include "sip_hash.h"
4040cb5e5vi#include "sip_dialog.h"
4140cb5e5vi#include "sip_parse_generic.h"
4240cb5e5vi
4340cb5e5vi#define	SIP_DLG_XCHG_FROM	0
4440cb5e5vi#define	SIP_DLG_XCHG_TO		1
4540cb5e5vi
4640cb5e5vi/*
4740cb5e5vi * Dialog state change callback function
4840cb5e5vi */
4940cb5e5vivoid (*sip_dlg_ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int) = NULL;
5040cb5e5vivoid (*sip_ulp_dlg_del_cb)(sip_dialog_t, sip_msg_t, void *) = NULL;
5140cb5e5vi
5240cb5e5viboolean_t	sip_incomplete_dialog(sip_dialog_t);
5340cb5e5vi
5440cb5e5vi/*
5540cb5e5vi * Exchange From/To header
5640cb5e5vi */
5740cb5e5vi_sip_header_t *sip_dlg_xchg_from_to(sip_msg_t, int);
5840cb5e5vi
5940cb5e5vi/*
6040cb5e5vi * Complete dialog hash table
6140cb5e5vi */
6240cb5e5visip_hash_t sip_dialog_hash[SIP_HASH_SZ];
6340cb5e5vi
6440cb5e5vi/*
6540cb5e5vi * Partial dialog hash table
6640cb5e5vi */
6740cb5e5visip_hash_t sip_dialog_phash[SIP_HASH_SZ];
6840cb5e5vi
6940cb5e5vi/*
7040cb5e5vi * Route set structure
7140cb5e5vi */
7240cb5e5vitypedef struct sip_dlg_route_set_s  {
7340cb5e5vi	char		*sip_dlg_route;
7440cb5e5vi	sip_str_t	sip_dlg_ruri;
7540cb5e5vi	boolean_t	sip_dlg_route_lr;
7640cb5e5vi	struct sip_dlg_route_set_s *sip_dlg_route_next;
7740cb5e5vi}sip_dlg_route_set_t;
7840cb5e5vi
7940cb5e5visip_dialog_t		sip_seed_dialog(sip_conn_object_t, _sip_msg_t *,
8040cb5e5vi			    boolean_t, int);
8140cb5e5visip_dialog_t		sip_complete_dialog(_sip_msg_t *, _sip_dialog_t *);
8240cb5e5viint			sip_dialog_process(_sip_msg_t *, sip_dialog_t *);
8340cb5e5vivoid			sip_dialog_delete(_sip_dialog_t *);
8440cb5e5vivoid			sip_dialog_init();
8540cb5e5visip_dialog_t		sip_dialog_find(_sip_msg_t *);
8640cb5e5viboolean_t		sip_dialog_match(void *, void *);
8740cb5e5viboolean_t		sip_dialog_free(void *, void *, int *);
8840cb5e5visip_dialog_t		sip_update_dialog(sip_dialog_t, _sip_msg_t *);
8940cb5e5vichar			*sip_dialog_req_uri(sip_dialog_t);
9040cb5e5vi
9140cb5e5vistatic void		sip_release_dialog_res(_sip_dialog_t *);
9240cb5e5vivoid			sip_dlg_self_destruct(void *);
9340cb5e5vistatic int		sip_dialog_get_route_set(_sip_dialog_t *, _sip_msg_t *,
9440cb5e5vi			    int);
9540cb5e5vistatic void		sip_dialog_free_rset(sip_dlg_route_set_t *);
9640cb5e5vi
9740cb5e5vi/*
9840cb5e5vi * Timer object for partial dialogs
9940cb5e5vi */
10040cb5e5vitypedef struct sip_dialog_timer_obj_s {
10140cb5e5vi	_sip_dialog_t	*dialog;
10240cb5e5vi	void		(*func)(sip_dialog_t, sip_msg_t, void *);
10340cb5e5vi} sip_dialog_timer_obj_t;
10440cb5e5vi
10540cb5e5vi/*
10640cb5e5vi * To avoid duplication all over the place
10740cb5e5vi */
10840cb5e5vistatic void
10940cb5e5visip_release_dialog_res(_sip_dialog_t *dialog)
11040cb5e5vi{
111943efbcgm	int			count = 0;
112943efbcgm	sip_msg_chain_t		*msg_chain;
113943efbcgm	sip_msg_chain_t		*nmsg_chain;
11440cb5e5vi
115943efbcgm	if (dialog->sip_dlg_ref_cnt != 0) {
116943efbcgm		sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
117943efbcgm		    SIP_ASSERT_ERROR, __FILE__,  __LINE__);
118943efbcgm	}
11940cb5e5vi	assert(dialog->sip_dlg_ref_cnt == 0);
12040cb5e5vi	if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
12140cb5e5vi		SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
12240cb5e5vi	if (dialog->sip_dlg_call_id != NULL)
12340cb5e5vi		sip_free_header(dialog->sip_dlg_call_id);
12440cb5e5vi	if (dialog->sip_dlg_local_uri_tag != NULL)
12540cb5e5vi		sip_free_header(dialog->sip_dlg_local_uri_tag);
12640cb5e5vi	if (dialog->sip_dlg_remote_uri_tag != NULL)
12740cb5e5vi		sip_free_header(dialog->sip_dlg_remote_uri_tag);
12840cb5e5vi	if (dialog->sip_dlg_remote_target != NULL)
12940cb5e5vi		sip_free_header(dialog->sip_dlg_remote_target);
130d8a4038gm	if (dialog->sip_dlg_local_contact != NULL)
131d8a4038gm		sip_free_header(dialog->sip_dlg_local_contact);
132d8a4038gm	if (dialog->sip_dlg_new_local_contact != NULL)
133d8a4038gm		sip_free_header(dialog->sip_dlg_new_local_contact);
13440cb5e5vi	if (dialog->sip_dlg_route_set != NULL)
13540cb5e5vi		sip_free_header(dialog->sip_dlg_route_set);
13640cb5e5vi	if (dialog->sip_dlg_event != NULL)
13740cb5e5vi		sip_free_header(dialog->sip_dlg_event);
13840cb5e5vi	if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) {
13940cb5e5vi		free(dialog->sip_dlg_req_uri.sip_str_ptr);
14040cb5e5vi		dialog->sip_dlg_req_uri.sip_str_ptr = NULL;
14140cb5e5vi		dialog->sip_dlg_req_uri.sip_str_len = 0;
14240cb5e5vi	}
14340cb5e5vi	if (dialog->sip_dlg_rset.sip_str_ptr != NULL) {
14440cb5e5vi		free(dialog->sip_dlg_rset.sip_str_ptr);
14540cb5e5vi		dialog->sip_dlg_rset.sip_str_len = 0;
14640cb5e5vi		dialog->sip_dlg_rset.sip_str_ptr = NULL;
14740cb5e5vi	}
148943efbcgm	for (count = 0; count <= SIP_DLG_DESTROYED; count++) {
149943efbcgm		msg_chain = dialog->sip_dlg_log[count].sip_msgs;
150943efbcgm		while (msg_chain != NULL) {
151943efbcgm			nmsg_chain = msg_chain->next;
152943efbcgm			if (msg_chain->sip_msg != NULL)
153943efbcgm				free(msg_chain->sip_msg);
154943efbcgm			free(msg_chain);
155943efbcgm			msg_chain = nmsg_chain;
156943efbcgm		}
157943efbcgm	}
15840cb5e5vi	(void) pthread_mutex_destroy(&dialog->sip_dlg_mutex);
15940cb5e5vi	free(dialog);
16040cb5e5vi}
16140cb5e5vi
16240cb5e5vi/*
16340cb5e5vi * Get the route information from the 'value' and add it to the route
16440cb5e5vi * set.
16540cb5e5vi */
16640cb5e5vistatic sip_dlg_route_set_t *
16740cb5e5visip_add_route_to_set(sip_hdr_value_t *value)
16840cb5e5vi{
16940cb5e5vi	int			vlen = 0;
17040cb5e5vi	sip_dlg_route_set_t	*rset;
17140cb5e5vi	char			*crlf;
17240cb5e5vi	const sip_param_t	*uri_param;
17340cb5e5vi	int			error;
17440cb5e5vi
17540cb5e5vi	rset = calloc(1, sizeof (*rset));
17640cb5e5vi	if (rset == NULL)
17740cb5e5vi		return (NULL);
17840cb5e5vi	rset->sip_dlg_route_next = NULL;
17940cb5e5vi	vlen = value->sip_value_end - value->sip_value_start;
18040cb5e5vi
18140cb5e5vi	/*
18240cb5e5vi	 * check for CRLF
18340cb5e5vi	 */
18440cb5e5vi	crlf = value->sip_value_end - strlen(SIP_CRLF);
18540cb5e5vi	while (crlf != NULL && strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) {
18640cb5e5vi		vlen -= strlen(SIP_CRLF);
18740cb5e5vi		crlf -= strlen(SIP_CRLF);
18840cb5e5vi	}
18940cb5e5vi	rset->sip_dlg_route = calloc(1, vlen + 1);
19040cb5e5vi	if (rset->sip_dlg_route == NULL) {
19140cb5e5vi		free(rset);
19240cb5e5vi		return (NULL);
19340cb5e5vi	}
19440cb5e5vi	/*
19540cb5e5vi	 * loose routing
19640cb5e5vi	 */
19740cb5e5vi	rset->sip_dlg_route_lr = B_FALSE;
19840cb5e5vi	(void) strncpy(rset->sip_dlg_route, value->sip_value_start, vlen);
19940cb5e5vi	rset->sip_dlg_ruri.sip_str_ptr = rset->sip_dlg_route +
20040cb5e5vi	    (value->cftr_uri.sip_str_ptr - value->sip_value_start);
20140cb5e5vi	rset->sip_dlg_ruri.sip_str_len = value->cftr_uri.sip_str_len;
20240cb5e5vi	rset->sip_dlg_route[vlen] = '\0';
20340cb5e5vi
20440cb5e5vi	assert(value->sip_value_parsed_uri != NULL);
20540cb5e5vi	/*
20640cb5e5vi	 * Check if the 'lr' param is present for this route.
20740cb5e5vi	 */
20840cb5e5vi	uri_param = sip_get_uri_params(value->sip_value_parsed_uri, &error);
20940cb5e5vi	if (error != 0) {
21040cb5e5vi		free(rset->sip_dlg_route);
21140cb5e5vi		free(rset);
21240cb5e5vi		return (NULL);
21340cb5e5vi	}
21440cb5e5vi	if (uri_param != NULL) {
21540cb5e5vi		rset->sip_dlg_route_lr = sip_is_param_present(uri_param, "lr",
21640cb5e5vi		    strlen("lr"));
21740cb5e5vi	}
21840cb5e5vi	return (rset);
21940cb5e5vi}
22040cb5e5vi
22140cb5e5vi/*
22240cb5e5vi * Depending on the route-set, determine the request URI.
22340cb5e5vi */
22440cb5e5vichar *
22540cb5e5visip_dialog_req_uri(sip_dialog_t dialog)
22640cb5e5vi{
22740cb5e5vi	const sip_str_t		*req_uri;
22840cb5e5vi	char			*uri;
22940cb5e5vi	_sip_dialog_t		*_dialog;
23040cb5e5vi
23140cb5e5vi	_dialog = (_sip_dialog_t *)dialog;
23240cb5e5vi	if (_dialog->sip_dlg_route_set == NULL ||
23340cb5e5vi	    _dialog->sip_dlg_req_uri.sip_str_ptr == NULL) {
23440cb5e5vi		const struct sip_value	*val;
23540cb5e5vi
23640cb5e5vi		val = sip_get_header_value(_dialog->sip_dlg_remote_target,
23740cb5e5vi		    NULL);
23840cb5e5vi		if (val == NULL)
23940cb5e5vi			return (NULL);
24040cb5e5vi		req_uri = &((sip_hdr_value_t *)val)->cftr_uri;
24140cb5e5vi	} else {
24240cb5e5vi		req_uri = &_dialog->sip_dlg_req_uri;
24340cb5e5vi	}
24440cb5e5vi	uri = (char *)malloc(req_uri->sip_str_len + 1);
24540cb5e5vi	if (uri == NULL)
24640cb5e5vi		return (NULL);
24740cb5e5vi	(void) strncpy(uri, req_uri->sip_str_ptr, req_uri->sip_str_len);
24840cb5e5vi	uri[req_uri->sip_str_len] = '\0';
24940cb5e5vi
25040cb5e5vi	return (uri);
25140cb5e5vi}
25240cb5e5vi
25340cb5e5vi/*
25440cb5e5vi * Free the route set.
25540cb5e5vi */
25640cb5e5vivoid
25740cb5e5visip_dialog_free_rset(sip_dlg_route_set_t *rset)
25840cb5e5vi{
25940cb5e5vi	sip_dlg_route_set_t	*next;
26040cb5e5vi
26140cb5e5vi	while (rset != NULL) {
26240cb5e5vi		next = rset->sip_dlg_route_next;
26340cb5e5vi		rset->sip_dlg_route_next = NULL;
26440cb5e5vi		free(rset->sip_dlg_route);
26540cb5e5vi		free(rset);
26640cb5e5vi		rset = next;
26740cb5e5vi	}
26840cb5e5vi}
26940cb5e5vi
27040cb5e5vi/*
27140cb5e5vi * Recompute route-set
27240cb5e5vi */
27340cb5e5vistatic int
27440cb5e5visip_dlg_recompute_rset(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what)
27540cb5e5vi{
27640cb5e5vi	int ret;
27740cb5e5vi
27840cb5e5vi	if (dialog->sip_dlg_route_set != NULL) {
27940cb5e5vi		sip_free_header(dialog->sip_dlg_route_set);
28040cb5e5vi		dialog->sip_dlg_route_set = NULL;
28140cb5e5vi	}
28240cb5e5vi	if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) {
28340cb5e5vi		free(dialog->sip_dlg_req_uri.sip_str_ptr);
28440cb5e5vi		dialog->sip_dlg_req_uri.sip_str_ptr = NULL;
28540cb5e5vi		dialog->sip_dlg_req_uri.sip_str_len = 0;
28640cb5e5vi	}
28740cb5e5vi	if (dialog->sip_dlg_rset.sip_str_ptr != NULL) {
28840cb5e5vi		free(dialog->sip_dlg_rset.sip_str_ptr);
28940cb5e5vi		dialog->sip_dlg_rset.sip_str_ptr = NULL;
29040cb5e5vi		dialog->sip_dlg_rset.sip_str_len = 0;
29140cb5e5vi	}
29240cb5e5vi	ret = sip_dialog_get_route_set(dialog, sip_msg, what);
29340cb5e5vi	return (ret);
29440cb5e5vi}
29540cb5e5vi
29640cb5e5vi/*
29740cb5e5vi * If the route set is empty, the UAC MUST place the remote target URI
29840cb5e5vi * into the Request-URI.  The UAC MUST NOT add a Route header field to
29940cb5e5vi * the request.
30040cb5e5vi *
30140cb5e5vi * If the route set is not empty, and the first URI in the route set
30240cb5e5vi * contains the lr parameter (see Section 19.1.1), the UAC MUST place
30340cb5e5vi * the remote target URI into the Request-URI and MUST include a Route
30440cb5e5vi * header field containing the route set values in order, including all
30540cb5e5vi * parameters.
30640cb5e5vi *
30740cb5e5vi * If the route set is not empty, and its first URI does not contain the
30840cb5e5vi * lr parameter, the UAC MUST place the first URI from the route set
30940cb5e5vi * into the Request-URI, stripping any parameters that are not allowed
31040cb5e5vi * in a Request-URI.  The UAC MUST add a Route header field containing
31140cb5e5vi * the remainder of the route set values in order, including all
31240cb5e5vi * parameters.  The UAC MUST then place the remote target URI into the
31340cb5e5vi * Route header field as the last value.
31440cb5e5vi */
31540cb5e5viint
31640cb5e5visip_dialog_set_route_hdr(_sip_dialog_t *dialog, sip_dlg_route_set_t *rset_head,
31740cb5e5vi    int rcnt, int rlen)
31840cb5e5vi{
31940cb5e5vi	size_t			rset_len;
32040cb5e5vi	_sip_header_t		*rhdr;
32140cb5e5vi	char			*rset;
32240cb5e5vi	char			*rp;
32340cb5e5vi	char			*rsp;
32440cb5e5vi	int			count;
32540cb5e5vi	sip_dlg_route_set_t	*route;
32640cb5e5vi	boolean_t		first = B_TRUE;
32740cb5e5vi	const sip_str_t		*to_uri;
32840cb5e5vi	char			*uri = NULL;
32940cb5e5vi	int			rspl;
33040cb5e5vi	int			rpl;
33140cb5e5vi
332943efbcgm	if (rcnt <= 0) {
333943efbcgm		sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
334943efbcgm		    SIP_ASSERT_ERROR, __FILE__, __LINE__);
335943efbcgm	}
33640cb5e5vi	assert(rcnt > 0);
33740cb5e5vi
33840cb5e5vi	dialog->sip_dlg_rset.sip_str_len = rlen + rcnt - 1;
33940cb5e5vi	dialog->sip_dlg_rset.sip_str_ptr = malloc(rlen + rcnt);
34040cb5e5vi	if (dialog->sip_dlg_rset.sip_str_ptr == NULL)
34140cb5e5vi		return (ENOMEM);
34240cb5e5vi	rsp = dialog->sip_dlg_rset.sip_str_ptr;
34340cb5e5vi	rspl = rlen + rcnt;
34440cb5e5vi	route = rset_head;
34540cb5e5vi	rset_len = rlen;
34640cb5e5vi	if (!route->sip_dlg_route_lr) {
34740cb5e5vi		const struct sip_value	*val;
34840cb5e5vi
34940cb5e5vi		val = sip_get_header_value(dialog->sip_dlg_remote_target, NULL);
35040cb5e5vi		to_uri = &((sip_hdr_value_t *)val)->cftr_uri;
35140cb5e5vi		uri = (char *)malloc(to_uri->sip_str_len + 1);
35240cb5e5vi		if (uri == NULL) {
35340cb5e5vi			free(dialog->sip_dlg_rset.sip_str_ptr);
35440cb5e5vi			dialog->sip_dlg_rset.sip_str_len = 0;
35540cb5e5vi			dialog->sip_dlg_rset.sip_str_ptr = NULL;
35640cb5e5vi			return (ENOMEM);
35740cb5e5vi		}
35840cb5e5vi		(void) strncpy(uri, to_uri->sip_str_ptr, to_uri->sip_str_len);
35940cb5e5vi		uri[to_uri->sip_str_len] = '\0';
36040cb5e5vi		rset_len = rlen - strlen(route->sip_dlg_route) + strlen(uri) +
36140cb5e5vi		    SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN +
36240cb5e5vi		    sizeof (char);
36340cb5e5vi		count = snprintf(rsp, rspl, "%s", route->sip_dlg_route);
36440cb5e5vi		dialog->sip_dlg_req_uri.sip_str_ptr = malloc(
36540cb5e5vi		    route->sip_dlg_ruri.sip_str_len + 1);
36640cb5e5vi		if (dialog->sip_dlg_req_uri.sip_str_ptr == NULL) {
36740cb5e5vi			free(uri);
36840cb5e5vi			free(dialog->sip_dlg_rset.sip_str_ptr);
36940cb5e5vi			dialog->sip_dlg_rset.sip_str_len = 0;
37040cb5e5vi			dialog->sip_dlg_rset.sip_str_ptr = NULL;
37140cb5e5vi			return (ENOMEM);
37240cb5e5vi		}
37340cb5e5vi		(void) strncpy(dialog->sip_dlg_req_uri.sip_str_ptr, rsp +
37440cb5e5vi		    (route->sip_dlg_ruri.sip_str_ptr - route->sip_dlg_route),
37540cb5e5vi		    route->sip_dlg_ruri.sip_str_len);
37640cb5e5vi		dialog->sip_dlg_req_uri.sip_str_ptr[
37740cb5e5vi		    route->sip_dlg_ruri.sip_str_len] = '\0';
37840cb5e5vi		dialog->sip_dlg_req_uri.sip_str_len =
37940cb5e5vi		    route->sip_dlg_ruri.sip_str_len;
38040cb5e5vi
38140cb5e5vi		rsp += count;
38240cb5e5vi		rspl -= count;
38340cb5e5vi		route = route->sip_dlg_route_next;
38440cb5e5vi	}
38540cb5e5vi
38640cb5e5vi	/*
38740cb5e5vi	 * rcnt - 1 is for the number of COMMAs
38840cb5e5vi	 */
38940cb5e5vi	rset_len += strlen(SIP_ROUTE) + SIP_SPACE_LEN + sizeof (char) +
39040cb5e5vi	    SIP_SPACE_LEN + rcnt - 1;
39140cb5e5vi	rset = malloc(rset_len + 1);
39240cb5e5vi	if (rset == NULL) {
39340cb5e5vi		free(dialog->sip_dlg_rset.sip_str_ptr);
39440cb5e5vi		dialog->sip_dlg_rset.sip_str_len = 0;
39540cb5e5vi		dialog->sip_dlg_rset.sip_str_ptr = NULL;
39640cb5e5vi		return (ENOMEM);
39740cb5e5vi	}
39840cb5e5vi	rhdr = sip_new_header(rset_len + strlen(SIP_CRLF));
39940cb5e5vi	if (rhdr == NULL) {
40040cb5e5vi		free(rset);
40140cb5e5vi		free(dialog->sip_dlg_rset.sip_str_ptr);
40240cb5e5vi		dialog->sip_dlg_rset.sip_str_len = 0;
40340cb5e5vi		dialog->sip_dlg_rset.sip_str_ptr = NULL;
40440cb5e5vi		return (ENOMEM);
40540cb5e5vi	}
40640cb5e5vi
40740cb5e5vi	rp = rset;
40840cb5e5vi	rpl = rset_len + 1;
40940cb5e5vi	count = snprintf(rp, rpl, "%s %c ", SIP_ROUTE, SIP_HCOLON);
41040cb5e5vi	rp += count;
41140cb5e5vi	rpl -= count;
41240cb5e5vi
41340cb5e5vi	while (route != NULL) {
41440cb5e5vi		if (first) {
41540cb5e5vi			count = snprintf(rp, rpl, "%s", route->sip_dlg_route);
41640cb5e5vi			rp += count;
41740cb5e5vi			rpl -= count;
41840cb5e5vi			first = B_FALSE;
41940cb5e5vi			if (uri != NULL) {
42040cb5e5vi				count = snprintf(rsp, rspl, "%c%s",
42140cb5e5vi				    SIP_COMMA, route->sip_dlg_route);
42240cb5e5vi			} else {
42340cb5e5vi				count = snprintf(rsp, rspl, "%s",
42440cb5e5vi				    route->sip_dlg_route);
42540cb5e5vi			}
42640cb5e5vi			rsp += count;
42740cb5e5vi			rspl -= count;
42840cb5e5vi		} else {
42940cb5e5vi			count = snprintf(rp, rpl, "%c%s", SIP_COMMA,
43040cb5e5vi			    route->sip_dlg_route);
43140cb5e5vi			rp += count;
43240cb5e5vi			rpl -= count;
43340cb5e5vi			count = snprintf(rsp, rspl, "%c%s", SIP_COMMA,
43440cb5e5vi			    route->sip_dlg_route);
43540cb5e5vi			rsp += count;
43640cb5e5vi			rspl -= count;
43740cb5e5vi		}
43840cb5e5vi		route = route->sip_dlg_route_next;
43940cb5e5vi	}
440943efbcgm	if (rsp > dialog->sip_dlg_rset.sip_str_ptr +
441943efbcgm	    dialog->sip_dlg_rset.sip_str_len) {
442943efbcgm		sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
443943efbcgm		    SIP_ASSERT_ERROR, __FILE__, __LINE__);
444943efbcgm	}
44540cb5e5vi	assert(rsp <= dialog->sip_dlg_rset.sip_str_ptr +
44640cb5e5vi	    dialog->sip_dlg_rset.sip_str_len);
44740cb5e5vi	dialog->sip_dlg_rset.sip_str_ptr[dialog->sip_dlg_rset.sip_str_len] =
44840cb5e5vi	    '\0';
44940cb5e5vi	if (uri != NULL) {
45040cb5e5vi		if (first) {
45140cb5e5vi			count = snprintf(rp, rpl, "%c %s %c", SIP_LAQUOT,
45240cb5e5vi			    uri, SIP_RAQUOT);
45340cb5e5vi		} else {
45440cb5e5vi			count = snprintf(rp, rpl, "%c%c %s %c", SIP_COMMA,
45540cb5e5vi			    SIP_LAQUOT, uri, SIP_RAQUOT);
45640cb5e5vi		}
45740cb5e5vi		rp += count;
45840cb5e5vi		rpl -= count;
45940cb5e5vi		free(uri);
46040cb5e5vi	}
461943efbcgm	if (rp > rset + rset_len) {
462943efbcgm		sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
463943efbcgm		    SIP_ASSERT_ERROR, __FILE__, __LINE__);
464943efbcgm	}
46540cb5e5vi	assert(rp <= rset + rset_len);
46640cb5e5vi	(void) snprintf(rhdr->sip_hdr_start, rset_len + strlen(SIP_CRLF) + 1,
46740cb5e5vi	    "%s%s", rset, SIP_CRLF);
46840cb5e5vi	free(rset);
46940cb5e5vi	dialog->sip_dlg_route_set = (sip_header_t)rhdr;
47040cb5e5vi	sip_dialog_free_rset(rset_head);
47140cb5e5vi	return (0);
47240cb5e5vi}
47340cb5e5vi
47440cb5e5vi/*
47540cb5e5vi * UAC Behavior
47640cb5e5vi * The route set MUST be set to the list of URIs in the Record-Route
47740cb5e5vi * header field from the response, taken in reverse order and preserving
47840cb5e5vi * all URI parameters.
47940cb5e5vi *
48040cb5e5vi * UAS behavior
48140cb5e5vi * The route set MUST be set to the list of URIs in the Record-Route
48240cb5e5vi * header field from the request, taken in order and preserving all URI
48340cb5e5vi * parameters.
48440cb5e5vi */
48540cb5e5vistatic int
48640cb5e5visip_dialog_get_route_set(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what)
48740cb5e5vi{
48840cb5e5vi	sip_header_t		rrhdr;
48940cb5e5vi	sip_hdr_value_t		*value;
49040cb5e5vi	int			error;
49140cb5e5vi	sip_dlg_route_set_t	*rset_head = NULL;
49240cb5e5vi	sip_dlg_route_set_t	*rset_tail = NULL;
49340cb5e5vi	sip_dlg_route_set_t	*rset;
49440cb5e5vi	int			rset_cnt = 0;
49540cb5e5vi	int			rset_len = 0;
49640cb5e5vi
49740cb5e5vi	(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
49840cb5e5vi	rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, NULL);
49940cb5e5vi	while (rrhdr != NULL) {
50040cb5e5vi		(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
50140cb5e5vi		value = (sip_hdr_value_t *)sip_get_header_value(rrhdr, &error);
50240cb5e5vi		while (value != NULL && error == 0) {
50340cb5e5vi			char	*crlf;
50440cb5e5vi
50540cb5e5vi			if (value->sip_value_state == SIP_VALUE_BAD) {
50640cb5e5vi				value = (sip_hdr_value_t *)sip_get_next_value(
50740cb5e5vi				    (sip_header_value_t)value, &error);
50840cb5e5vi				continue;
50940cb5e5vi			}
51040cb5e5vi			rset = sip_add_route_to_set(value);
51140cb5e5vi			if (rset == NULL)
51240cb5e5vi				goto r_error;
51340cb5e5vi			/*
51440cb5e5vi			 * Add one for COMMA
51540cb5e5vi			 */
51640cb5e5vi			rset_cnt++;
51740cb5e5vi			rset_len += (value->sip_value_end -
51840cb5e5vi			    value->sip_value_start);
51940cb5e5vi			/*
52040cb5e5vi			 * Check for CRLF
52140cb5e5vi			 */
52240cb5e5vi			crlf = value->sip_value_end - strlen(SIP_CRLF);
52340cb5e5vi			while (crlf != NULL &&
52440cb5e5vi			    strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) {
52540cb5e5vi				rset_len -= strlen(SIP_CRLF);
52640cb5e5vi				crlf -= strlen(SIP_CRLF);
52740cb5e5vi			}
52840cb5e5vi			if (rset_head == NULL) {
529943efbcgm				if (rset_tail != NULL) {
530943efbcgm					sip_write_to_log((void *)dialog,
531943efbcgm					    SIP_DIALOG_LOG | SIP_ASSERT_ERROR,
532943efbcgm					    __FILE__, __LINE__);
533943efbcgm				}
53440cb5e5vi				assert(rset_tail == NULL);
53540cb5e5vi				rset_head = rset_tail = rset;
53640cb5e5vi			} else if (what == SIP_UAS_DIALOG) {
53740cb5e5vi				rset_tail->sip_dlg_route_next = rset;
53840cb5e5vi				rset_tail = rset;
53940cb5e5vi			} else if (what == SIP_UAC_DIALOG) {
54040cb5e5vi				rset->sip_dlg_route_next = rset_head;
54140cb5e5vi				rset_head = rset;
54240cb5e5vi			} else {
543943efbcgm				sip_write_to_log((void *)dialog,
544943efbcgm				    SIP_DIALOG_LOG | SIP_ASSERT_ERROR,
545943efbcgm				    __FILE__, __LINE__);
54640cb5e5vi				assert(0);
54740cb5e5vi			}
54840cb5e5vi			value = (sip_hdr_value_t *)sip_get_next_value(
54940cb5e5vi			    (sip_header_value_t)value, &error);
55040cb5e5vi		}
55140cb5e5vi		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
55240cb5e5vi		rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, rrhdr);
55340cb5e5vi	}
55440cb5e5vi	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
55540cb5e5vi	if (rset_cnt == 0)
55640cb5e5vi		return (0);
55740cb5e5vi	if (sip_dialog_set_route_hdr(dialog, rset_head, rset_cnt,
55840cb5e5vi	    rset_len) != 0) {
55940cb5e5vi		goto r_error;
56040cb5e5vi	}
56140cb5e5vi	return (0);
56240cb5e5vir_error:
56340cb5e5vi	sip_dialog_free_rset(rset_head);
56440cb5e5vi	return (ENOMEM);
56540cb5e5vi}
56640cb5e5vi
56740cb5e5vi/*
56840cb5e5vi * UAS behavior:
56940cb5e5vi * The remote sequence number MUST be set to the value of the sequence
57040cb5e5vi * number in the CSeq header field of the request.  The local sequence
57140cb5e5vi * number MUST be empty.  The call identifier component of the dialog ID
57240cb5e5vi * MUST be set to the value of the Call-ID in the request.  The local
57340cb5e5vi * tag component of the dialog ID MUST be set to the tag in the To field
57440cb5e5vi * in the response to the request (which always includes a tag), and the
57540cb5e5vi * remote tag component of the dialog ID MUST be set to the tag from the
57640cb5e5vi * From field in the request.  A UAS MUST be prepared to receive a
57740cb5e5vi * request without a tag in the From field, in which case the tag is
57840cb5e5vi * considered to have a value of null.
57940cb5e5vi * The remote URI MUST be set to the URI in the From field, and the
58040cb5e5vi * local URI MUST be set to the URI in the To field.
58140cb5e5vi * The remote target MUST be set to the URI from the Contact header field
58240cb5e5vi * of the request.
58340cb5e5vi *
58440cb5e5vi * UAC behavior:
58540cb5e5vi * The local sequence number MUST be set to the value of the sequence
58640cb5e5vi * number in the CSeq header field of the request.  The remote sequence
58740cb5e5vi * number MUST be empty (it is established when the remote UA sends a
58840cb5e5vi * request within the dialog).  The call identifier component of the
58940cb5e5vi * dialog ID MUST be set to the value of the Call-ID in the request.
59040cb5e5vi * The local tag component of the dialog ID MUST be set to the tag in
59140cb5e5vi * the From field in the request, and the remote tag component of the
59240cb5e5vi * dialog ID MUST be set to the tag in the To field of the response.  A
59340cb5e5vi * UAC MUST be prepared to receive a response without a tag in the To
59440cb5e5vi * field, in which case the tag is considered to have a value of null.
59540cb5e5vi * The remote URI MUST be set to the URI in the To field, and the local
59640cb5e5vi * URI MUST be set to the URI in the From field.
59740cb5e5vi * The remote target MUST be set to the URI from the Contact header field
59840cb5e5vi * of the response.
59940cb5e5vi */
60040cb5e5vi
60140cb5e5vi
60240cb5e5vi/*
60340cb5e5vi * This is the routine that seeds a dialog.
60440cb5e5vi */
60540cb5e5visip_dialog_t
60640cb5e5visip_seed_dialog(sip_conn_object_t obj, _sip_msg_t *sip_msg,
60740cb5e5vi    boolean_t dlg_on_fork, int dlg_type)
60840cb5e5vi{
60940cb5e5vi	_sip_dialog_t		*dialog;
61040cb5e5vi	int			cseq;
61140cb5e5vi	sip_header_t		fhdr = NULL;
61240cb5e5vi	sip_header_t		thdr = NULL;
61340cb5e5vi	sip_header_t		chdr;
61440cb5e5vi	sip_header_t		cihdr;
61540cb5e5vi	sip_header_t		evhdr = NULL;
61640cb5e5vi	const struct sip_value	*value;
61740cb5e5vi	sip_dialog_timer_obj_t	*tim_obj = NULL;
61840cb5e5vi	const sip_str_t		*callid;
61940cb5e5vi	sip_method_t		method;
62040cb5e5vi	int			timer1 = sip_timer_T1;
62140cb5e5vi	int			error;
62240cb5e5vi
62340cb5e5vi	if (!sip_msg_is_request((sip_msg_t)sip_msg, &error))
62440cb5e5vi		return (NULL);
62540cb5e5vi
62640cb5e5vi	method = sip_get_request_method((sip_msg_t)sip_msg, &error);
62740cb5e5vi	/*
62840cb5e5vi	 * Only INVITE and SUBSCRIBE supported
62940cb5e5vi	 */
63040cb5e5vi	if (error != 0 || (method != INVITE && method != SUBSCRIBE))
63140cb5e5vi		return (NULL);
63240cb5e5vi
63340cb5e5vi	/*
63440cb5e5vi	 * A request outside of a dialog MUST NOT contain a To tag
63540cb5e5vi	 */
63640cb5e5vi	if (sip_get_to_tag((sip_msg_t)sip_msg, NULL) != NULL)
63740cb5e5vi		return (NULL);
63840cb5e5vi
63940cb5e5vi	if (dlg_type == SIP_UAS_DIALOG) {
64040cb5e5vi		thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg,
64140cb5e5vi		    SIP_DLG_XCHG_FROM);
64240cb5e5vi		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
64340cb5e5vi	} else {
64440cb5e5vi		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
64540cb5e5vi		fhdr = sip_search_for_header(sip_msg, SIP_FROM, NULL);
64640cb5e5vi	}
64740cb5e5vi	cihdr = sip_search_for_header(sip_msg, SIP_CALL_ID, NULL);
64840cb5e5vi	chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
64940cb5e5vi	if (method == SUBSCRIBE)
65040cb5e5vi		evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL);
65140cb5e5vi	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
65240cb5e5vi	if ((fhdr == NULL && thdr == NULL) || cihdr == NULL || chdr == NULL ||
65340cb5e5vi	    (method == SUBSCRIBE && evhdr == NULL)) {
65440cb5e5vi		if (thdr != NULL)
65540cb5e5vi			sip_free_header(thdr);
65640cb5e5vi		return (NULL);
65740cb5e5vi	}
65840cb5e5vi
65940cb5e5vi	/*
66040cb5e5vi	 * Sanity check since we just store the headers in the dialog
66140cb5e5vi	 */
66240cb5e5vi	if (sip_get_from_tag((sip_msg_t)sip_msg, NULL) == NULL ||
66340cb5e5vi	    sip_get_from_uri_str((sip_msg_t)sip_msg, NULL) == NULL ||
66440cb5e5vi	    ((cseq = sip_get_callseq_num((sip_msg_t)sip_msg, NULL)) == -1) ||
66540cb5e5vi	    (callid = sip_get_callid((sip_msg_t)sip_msg, NULL)) == NULL ||
66640cb5e5vi	    sip_get_to_uri_str((sip_msg_t)sip_msg, NULL) == NULL ||
66740cb5e5vi	    ((value = sip_get_header_value(chdr, NULL)) == NULL) ||
66840cb5e5vi	    sip_get_contact_uri_str((sip_header_value_t)value, NULL) == NULL) {
66940cb5e5vi		if (thdr != NULL)
67040cb5e5vi			sip_free_header(thdr);
67140cb5e5vi		return (NULL);
67240cb5e5vi	}
67340cb5e5vi
67440cb5e5vi	tim_obj = calloc(1, sizeof (sip_dialog_timer_obj_t));
67540cb5e5vi	if (tim_obj == NULL) {
67640cb5e5vi		if (thdr != NULL)
67740cb5e5vi			sip_free_header(thdr);
67840cb5e5vi		return (NULL);
67940cb5e5vi	}
68040cb5e5vi	dialog = calloc(1, sizeof (_sip_dialog_t));
68140cb5e5vi	if (dialog == NULL) {
68240cb5e5vi		if (thdr != NULL)
68340cb5e5vi			sip_free_header(thdr);
68440cb5e5vi		return (NULL);
68540cb5e5vi	}
68640cb5e5vi	/*
68740cb5e5vi	 * We will take the TO header with the tag when we complete this
68840cb5e5vi	 * dialog
68940cb5e5vi	 */
69040cb5e5vi	if (dlg_type == SIP_UAS_DIALOG) {
69140cb5e5vi		dialog->sip_dlg_remote_uri_tag = thdr;
69240cb5e5vi		/*
69340cb5e5vi		 * We take the remote target from the incoming request on the
69440cb5e5vi		 * UAS. For the UAC, we will take it from the response.
69540cb5e5vi		 */
69640cb5e5vi		if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) ==
69740cb5e5vi		    NULL) {
69840cb5e5vi			goto dia_err;
69940cb5e5vi		}
70040cb5e5vi	} else {
70140cb5e5vi		if ((dialog->sip_dlg_local_uri_tag = sip_dup_header(fhdr)) ==
70240cb5e5vi		    NULL) {
70340cb5e5vi			goto dia_err;
70440cb5e5vi		}
705d8a4038gm		/*
706d8a4038gm		 * We take the local contact from the originating request on
707d8a4038gm		 * UAC. For the UAS, we will take it from the response.
708d8a4038gm		 */
709d8a4038gm		if ((dialog->sip_dlg_local_contact = sip_dup_header(chdr)) ==
710d8a4038gm		    NULL) {
711d8a4038gm			goto dia_err;
712d8a4038gm		} else {
713d8a4038gm			dialog->sip_dlg_new_local_contact = NULL;
714d8a4038gm		}
71540cb5e5vi	}
71640cb5e5vi	if ((dialog->sip_dlg_call_id = sip_dup_header(cihdr)) == NULL)
71740cb5e5vi		goto dia_err;
71840cb5e5vi	if (method == SUBSCRIBE) {
71940cb5e5vi		dialog->sip_dlg_event = sip_dup_header(evhdr);
72040cb5e5vi		if (dialog->sip_dlg_event == NULL) {
72140cb5e5vi			goto dia_err;
72240cb5e5vi		}
72340cb5e5vi	}
72440cb5e5vi	dialog->sip_dlg_rset.sip_str_ptr = NULL;
72540cb5e5vi	dialog->sip_dlg_rset.sip_str_len = 0;
72640cb5e5vi	dialog->sip_dlg_req_uri.sip_str_ptr = NULL;
72740cb5e5vi	dialog->sip_dlg_req_uri.sip_str_len = 0;
72840cb5e5vi	/*
72940cb5e5vi	 * Get the route set from the request, if present
73040cb5e5vi	 */
73140cb5e5vi	if (dlg_type == SIP_UAS_DIALOG &&
73240cb5e5vi	    sip_dialog_get_route_set(dialog, sip_msg, dlg_type) != 0) {
73340cb5e5vi		goto dia_err;
73440cb5e5vi	}
73540cb5e5vi	if (dlg_type == SIP_UAC_DIALOG)
73640cb5e5vi		dialog->sip_dlg_local_cseq = cseq;
73740cb5e5vi	else
73840cb5e5vi		dialog->sip_dlg_remote_cseq = cseq;
73940cb5e5vi	dialog->sip_dlg_type = dlg_type;
74040cb5e5vi	dialog->sip_dlg_on_fork = dlg_on_fork;
74140cb5e5vi	dialog->sip_dlg_method = method;
74240cb5e5vi	/*
74340cb5e5vi	 * Set the partial dialog timer with the INVITE timeout val
74440cb5e5vi	 */
74540cb5e5vi	if (sip_conn_timer1 != NULL)
74640cb5e5vi		timer1 = sip_conn_timer1(obj);
74740cb5e5vi	SIP_INIT_TIMER(dialog->sip_dlg_timer, 64 * timer1);
74840cb5e5vi	tim_obj->dialog = dialog;
74940cb5e5vi	/*
75040cb5e5vi	 * Since at the client we never pass the partial dialog, we need not
75140cb5e5vi	 * invoke the callback when the partial dialog self-destructs.
75240cb5e5vi	 */
75340cb5e5vi	if (dlg_type == SIP_UAS_DIALOG)
75440cb5e5vi		tim_obj->func = sip_ulp_dlg_del_cb;
75540cb5e5vi	SIP_SCHED_TIMER(dialog->sip_dlg_timer, (void *)tim_obj,
75640cb5e5vi	    sip_dlg_self_destruct);
75740cb5e5vi	if (!SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
75840cb5e5vi		goto dia_err;
75940cb5e5vi	(void) pthread_mutex_init(&dialog->sip_dlg_mutex, NULL);
76040cb5e5vi
76140cb5e5vi	if (dlg_type == SIP_UAC_DIALOG) {
76240cb5e5vi		const sip_str_t	*local_tag;
76340cb5e5vi
76440cb5e5vi		local_tag = sip_get_from_tag((sip_msg_t)sip_msg, NULL);
765943efbcgm		if (local_tag == NULL) {
766943efbcgm			sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
767943efbcgm			    SIP_ASSERT_ERROR, __FILE__, __LINE__);
768943efbcgm		}
76940cb5e5vi		assert(local_tag != NULL);
77040cb5e5vi		sip_md5_hash(local_tag->sip_str_ptr, local_tag->sip_str_len,
77140cb5e5vi		    callid->sip_str_ptr, callid->sip_str_len,
77240cb5e5vi		    NULL, 0, NULL, 0, NULL, 0, NULL, 0,
77340cb5e5vi		    (uchar_t *)dialog->sip_dlg_id);
77440cb5e5vi
77540cb5e5vi
77640cb5e5vi		/*
77740cb5e5vi		 * Add it to the partial hash table
77840cb5e5vi		 */
77940cb5e5vi		if (sip_hash_add(sip_dialog_phash, (void *)dialog,
78040cb5e5vi		    SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) {
78140cb5e5vi			goto dia_err;
78240cb5e5vi		}
78340cb5e5vi	}
784943efbcgm
785943efbcgm	dialog->sip_dlg_msgcnt = 1;
786943efbcgm	sip_add_log(&dialog->sip_dlg_log[dialog->sip_dlg_state],
787943efbcgm	    (sip_msg_t)sip_msg, dialog->sip_dlg_msgcnt, SIP_DIALOG_LOG);
788943efbcgm
78940cb5e5vi	SIP_DLG_REFCNT_INCR(dialog);
79040cb5e5vi	return ((sip_dialog_t)dialog);
79140cb5e5vidia_err:
79240cb5e5vi	sip_release_dialog_res(dialog);
79340cb5e5vi	if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
79440cb5e5vi		SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
79540cb5e5vi	if (tim_obj != NULL)
79640cb5e5vi		free(tim_obj);
79740cb5e5vi	return (NULL);
79840cb5e5vi}
79940cb5e5vi
80040cb5e5vi/*
80140cb5e5vi * When creating a dialog from a NOTIFY request, we need to get the FROM
80240cb5e5vi * header for the dialog from the TO header of the NOTIFY.
80340cb5e5vi */
80440cb5e5vi_sip_header_t *
80540cb5e5visip_dlg_xchg_from_to(sip_msg_t sip_msg, int what)
80640cb5e5vi{
80740cb5e5vi	int			len;
80840cb5e5vi	_sip_header_t		*newhdr;
80940cb5e5vi	int			cnt;
81040cb5e5vi	const struct sip_header	*hdr;
81140cb5e5vi	int			hdrsize;
81240cb5e5vi	int			error;
81340cb5e5vi
81440cb5e5vi	hdr = sip_get_header(sip_msg, what == SIP_DLG_XCHG_FROM ? SIP_FROM :
81540cb5e5vi	    SIP_TO, NULL, &error);
81640cb5e5vi	if (error != 0 || hdr == NULL)
81740cb5e5vi		return (NULL);
81840cb5e5vi	if (sip_parse_goto_values((_sip_header_t *)hdr) != 0)
81940cb5e5vi		return (NULL);
82040cb5e5vi	len = hdr->sip_hdr_end - hdr->sip_hdr_current;
82140cb5e5vi	if (what == SIP_DLG_XCHG_FROM) {
82240cb5e5vi		hdrsize = len + strlen(SIP_TO) + SIP_SPACE_LEN + sizeof (char) +
82340cb5e5vi		    SIP_SPACE_LEN;
82440cb5e5vi	} else {
82540cb5e5vi		hdrsize = len + strlen(SIP_FROM) + SIP_SPACE_LEN +
82640cb5e5vi		    sizeof (char) + SIP_SPACE_LEN;
82740cb5e5vi	}
82840cb5e5vi	newhdr = sip_new_header(hdrsize);
82940cb5e5vi	if (newhdr == NULL)
83040cb5e5vi		return (NULL);
83140cb5e5vi	if (what == SIP_DLG_XCHG_FROM) {
83240cb5e5vi		cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1,
83340cb5e5vi		    "%s %c ", SIP_TO, SIP_HCOLON);
83440cb5e5vi	} else {
83540cb5e5vi		cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1,
83640cb5e5vi		    "%s %c ", SIP_FROM, SIP_HCOLON);
83740cb5e5vi	}
83840cb5e5vi	newhdr->sip_hdr_current += cnt;
83940cb5e5vi	(void) strncpy(newhdr->sip_hdr_current, hdr->sip_hdr_current, len);
84040cb5e5vi	newhdr->sip_hdr_current += len;
84140cb5e5vi	assert(newhdr->sip_hdr_current == newhdr->sip_hdr_end);
84240cb5e5vi	assert(hdr->sip_header_functions != NULL);
84340cb5e5vi
84440cb5e5vi	/*
84540cb5e5vi	 * FROM and TO have common parsing functions
84640cb5e5vi	 */
84740cb5e5vi	newhdr->sip_header_functions = hdr->sip_header_functions;
84840cb5e5vi	newhdr->sip_hdr_current = newhdr->sip_hdr_start;
84940cb5e5vi
85040cb5e5vi	return (newhdr);
85140cb5e5vi}
85240cb5e5vi
85340cb5e5vi/*
85440cb5e5vi * This is the response that completes the dialog that was created
85540cb5e5vi * in sip_seed_dialog().
85640cb5e5vi */
85740cb5e5visip_dialog_t
85840cb5e5visip_complete_dialog(_sip_msg_t *sip_msg, _sip_dialog_t *dialog)
85940cb5e5vi{
86040cb5e5vi	_sip_header_t		*thdr;
86140cb5e5vi	_sip_header_t		*evhdr = NULL;
86240cb5e5vi	_sip_header_t		*substate = NULL;
86340cb5e5vi	sip_header_t		chdr = NULL;
86440cb5e5vi	int			resp_code;
86540cb5e5vi	const sip_str_t		*ttag;
86640cb5e5vi	const sip_str_t		*remtag;
86740cb5e5vi	const sip_str_t		*callid;
86840cb5e5vi	const struct sip_value 	*val;
86940cb5e5vi	sip_method_t		method;
87040cb5e5vi	int			error = 0;
87140cb5e5vi	int			prev_state;
87240cb5e5vi	boolean_t		alloc_thdr = B_FALSE;
87340cb5e5vi
87440cb5e5vi	if (sip_msg_is_request((sip_msg_t)sip_msg, &error) && error == 0)
87540cb5e5vi		method = sip_get_request_method((sip_msg_t)sip_msg, &error);
87640cb5e5vi	else
87740cb5e5vi		method = sip_get_callseq_method((sip_msg_t)sip_msg, &error);
87840cb5e5vi	if (error != 0 || dialog == NULL ||
87940cb5e5vi	    (sip_msg_is_request((sip_msg_t)sip_msg, &error) &&
88040cb5e5vi	    (dialog->sip_dlg_method == INVITE || method != NOTIFY))) {
88140cb5e5vi		return (NULL);
88240cb5e5vi	}
88340cb5e5vi	if ((dialog->sip_dlg_type == SIP_UAC_DIALOG && method != NOTIFY &&
88440cb5e5vi	    sip_get_callseq_num((sip_msg_t)sip_msg, NULL) !=
88540cb5e5vi	    dialog->sip_dlg_local_cseq) ||
88640cb5e5vi	    (dialog->sip_dlg_type == SIP_UAS_DIALOG && method != NOTIFY &&
88740cb5e5vi	    sip_get_callseq_num((sip_msg_t)sip_msg, NULL) !=
88840cb5e5vi	    dialog->sip_dlg_remote_cseq)) {
88940cb5e5vi		return (NULL);
89040cb5e5vi	}
89140cb5e5vi	if (method == NOTIFY) {
89240cb5e5vi		const sip_str_t	*sstate;
89340cb5e5vi
89440cb5e5vi		thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg,
89540cb5e5vi		    SIP_DLG_XCHG_FROM);
89640cb5e5vi		if (thdr == NULL)
89740cb5e5vi			return (NULL);
89840cb5e5vi		alloc_thdr = B_TRUE;
89940cb5e5vi		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
90040cb5e5vi		chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
90140cb5e5vi		if (chdr == NULL) {
90240cb5e5vi			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
90340cb5e5vi			sip_free_header(thdr);
90440cb5e5vi			return (NULL);
90540cb5e5vi		}
90640cb5e5vi		evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL);
90740cb5e5vi		if (evhdr == NULL) {
90840cb5e5vi			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
90940cb5e5vi			sip_free_header(thdr);
91040cb5e5vi			return (NULL);
91140cb5e5vi		}
91240cb5e5vi		substate = sip_search_for_header(sip_msg,
91340cb5e5vi		    SIP_SUBSCRIPTION_STATE, NULL);
91440cb5e5vi		if (substate == NULL) {
91540cb5e5vi			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
91640cb5e5vi			sip_free_header(thdr);
91740cb5e5vi			return (NULL);
91840cb5e5vi		}
91940cb5e5vi		(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
92040cb5e5vi		sstate = sip_get_substate((sip_msg_t)sip_msg, &error);
92140cb5e5vi		if (sstate == NULL || error != 0) {
92240cb5e5vi			sip_free_header(thdr);
92340cb5e5vi			return (NULL);
92440cb5e5vi		}
92540cb5e5vi		if ((sstate->sip_str_len != strlen("pending") &&
92640cb5e5vi		    sstate->sip_str_len != strlen("active")) ||
92740cb5e5vi		    ((sstate->sip_str_len == strlen("pending") &&
92840cb5e5vi		    strncasecmp(sstate->sip_str_ptr, "pending",
92940cb5e5vi		    strlen("pending")) != 0) ||
93040cb5e5vi		    (sstate->sip_str_len == strlen("active") &&
93140cb5e5vi		    strncasecmp(sstate->sip_str_ptr, "active",
93240cb5e5vi		    strlen("active")) != 0))) {
93340cb5e5vi			sip_free_header(thdr);
93440cb5e5vi			return (NULL);
93540cb5e5vi		}
93640cb5e5vi		ttag = sip_get_from_tag((sip_msg_t)sip_msg, NULL);
93740cb5e5vi	} else {
93840cb5e5vi		if (dialog->sip_dlg_type == SIP_UAS_DIALOG) {
93940cb5e5vi			thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg,
94040cb5e5vi			    SIP_DLG_XCHG_TO);
94140cb5e5vi			alloc_thdr = B_TRUE;
94240cb5e5vi		} else {
94340cb5e5vi			(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
94440cb5e5vi			thdr = sip_search_for_header(sip_msg, SIP_TO, NULL);
94540cb5e5vi			if (dialog->sip_dlg_remote_target == NULL) {
94640cb5e5vi				chdr = sip_search_for_header(sip_msg,
94740cb5e5vi				    SIP_CONTACT, NULL);
94840cb5e5vi			}
94940cb5e5vi			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
95040cb5e5vi		}
95140cb5e5vi		if (thdr == NULL) {
95240cb5e5vi			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
95340cb5e5vi			return (NULL);
95440cb5e5vi		}
95540cb5e5vi		ttag = sip_get_to_tag((sip_msg_t)sip_msg, NULL);
95640cb5e5vi	}
95740cb5e5vi	if (ttag == NULL) {
95840cb5e5vi		if (alloc_thdr)
95940cb5e5vi			sip_free_header(thdr);
96040cb5e5vi		return (NULL);
96140cb5e5vi	}
96240cb5e5vi	prev_state = dialog->sip_dlg_state;
96340cb5e5vi
96440cb5e5vi	if (method == NOTIFY) {
96540cb5e5vi		int			error;
96640cb5e5vi		const sip_str_t		*dlg_id_val = NULL;
96740cb5e5vi		const sip_str_t		*event;
96840cb5e5vi		const sip_str_t		*id_val = NULL;
96940cb5e5vi		sip_header_value_t	ev_val;
97040cb5e5vi		sip_hdr_value_t		*dlg_ev_val = NULL;
97140cb5e5vi
97240cb5e5vi		event = sip_get_event((sip_msg_t)sip_msg, &error);
97340cb5e5vi		if (event == NULL || error != 0) {
97440cb5e5vi			sip_free_header(thdr);
97540cb5e5vi			return (NULL);
97640cb5e5vi		}
97740cb5e5vi		ev_val = (sip_header_value_t)sip_get_header_value(evhdr,
97840cb5e5vi		    &error);
97940cb5e5vi		if (ev_val != NULL)
98040cb5e5vi			id_val = sip_get_param_value(ev_val, "id", &error);
98140cb5e5vi		if (error == 0) {
98240cb5e5vi			dlg_ev_val = (sip_hdr_value_t *)sip_get_header_value(
98340cb5e5vi			    dialog->sip_dlg_event, &error);
98440cb5e5vi		}
98540cb5e5vi		if (dlg_ev_val == NULL || error != 0) {
98640cb5e5vi			sip_free_header(thdr);
98740cb5e5vi			return (NULL);
98840cb5e5vi		}
98940cb5e5vi		dlg_id_val = sip_get_param_value((sip_header_value_t)dlg_ev_val,
99040cb5e5vi		    "id", &error);
99140cb5e5vi		if (error != 0 ||
99240cb5e5vi		    dlg_ev_val->str_val_len != event->sip_str_len ||
99340cb5e5vi		    strncmp(dlg_ev_val->str_val_ptr, event->sip_str_ptr,
99440cb5e5vi		    event->sip_str_len != 0)) {
99540cb5e5vi			sip_free_header(thdr);
99640cb5e5vi			return (NULL);
99740cb5e5vi		}
99840cb5e5vi		if ((dlg_id_val == NULL && id_val != NULL) ||
99940cb5e5vi		    (dlg_id_val != NULL && id_val == NULL)) {
100040cb5e5vi			sip_free_header(thdr);
100140cb5e5vi			return (NULL);
100240cb5e5vi		} else if (dlg_id_val != NULL && id_val != NULL) {
100340cb5e5vi			if (dlg_id_val->sip_str_len != id_val->sip_str_len ||
100440cb5e5vi			    strncasecmp(dlg_id_val->sip_str_ptr,
100540cb5e5vi			    id_val->sip_str_ptr, dlg_id_val->sip_str_len) !=
100640cb5e5vi			    0) {
100740cb5e5vi				sip_free_header(thdr);
100840cb5e5vi				return (NULL);
100940cb5e5vi			}
101040cb5e5vi		}
101140cb5e5vi		if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
101240cb5e5vi			dialog->sip_dlg_remote_uri_tag = thdr;
101340cb5e5vi			if ((dialog->sip_dlg_remote_target =
101440cb5e5vi			    sip_dup_header(chdr)) == NULL) {
101540cb5e5vi				sip_free_header(thdr);
101640cb5e5vi				return (NULL);
101740cb5e5vi			}
101840cb5e5vi		} else {
101940cb5e5vi			dialog->sip_dlg_local_uri_tag = thdr;
102040cb5e5vi		}
102140cb5e5vi		dialog->sip_dlg_state = SIP_DLG_CONFIRMED;
102240cb5e5vi	} else {
102340cb5e5vi		resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
102440cb5e5vi		(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
1025943efbcgm		if (dialog->sip_dlg_state != SIP_DLG_NEW) {
1026943efbcgm			sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
1027943efbcgm			    SIP_ASSERT_ERROR, __FILE__, __LINE__);
1028943efbcgm		}
102940cb5e5vi		assert(dialog->sip_dlg_state == SIP_DLG_NEW);
103040cb5e5vi		if (dialog->sip_dlg_remote_target == NULL && chdr != NULL) {
1031943efbcgm			if (dialog->sip_dlg_type != SIP_UAC_DIALOG) {
1032943efbcgm				sip_write_to_log((void *)dialog,
1033943efbcgm				    SIP_DIALOG_LOG | SIP_ASSERT_ERROR,
1034943efbcgm				    __FILE__, __LINE__);
1035943efbcgm			}
103640cb5e5vi			assert(dialog->sip_dlg_type == SIP_UAC_DIALOG);
103740cb5e5vi			if ((dialog->sip_dlg_remote_target =
103840cb5e5vi			    sip_dup_header(chdr)) == NULL) {
103940cb5e5vi				(void) pthread_mutex_unlock(
104040cb5e5vi				    &dialog->sip_dlg_mutex);
104140cb5e5vi				if (alloc_thdr)
104240cb5e5vi					sip_free_header(thdr);
10432c2c418vi				goto terminate_new_dlg;
104440cb5e5vi			}
104540cb5e5vi			if (sip_dialog_get_route_set(dialog, sip_msg,
104640cb5e5vi			    dialog->sip_dlg_type) != 0) {
104740cb5e5vi				(void) pthread_mutex_unlock(
104840cb5e5vi				    &dialog->sip_dlg_mutex);
104940cb5e5vi				if (alloc_thdr)
105040cb5e5vi					sip_free_header(thdr);
10512c2c418vi				goto terminate_new_dlg;
105240cb5e5vi			}
105340cb5e5vi		}
105440cb5e5vi		if (SIP_PROVISIONAL_RESP(resp_code)) {
105540cb5e5vi			dialog->sip_dlg_state = SIP_DLG_EARLY;
105640cb5e5vi		} else if (SIP_OK_RESP(resp_code)) {
105740cb5e5vi			/*
105840cb5e5vi			 * Per 12.1 the UAS must include the contact header
105940cb5e5vi			 * for a dialog establishing response, so if we
106040cb5e5vi			 * don't find one, we terminate it.
106140cb5e5vi			 */
106240cb5e5vi			if (dialog->sip_dlg_remote_target == NULL) {
106340cb5e5vi				(void) pthread_mutex_unlock(
106440cb5e5vi				    &dialog->sip_dlg_mutex);
106540cb5e5vi				if (sip_ulp_dlg_del_cb != NULL) {
106640cb5e5vi					sip_ulp_dlg_del_cb(dialog,
106740cb5e5vi					    (sip_msg_t)sip_msg, NULL);
106840cb5e5vi				}
106940cb5e5vi				if (alloc_thdr)
107040cb5e5vi					sip_free_header(thdr);
10712c2c418vi				goto terminate_new_dlg;
107240cb5e5vi			}
107340cb5e5vi			dialog->sip_dlg_state = SIP_DLG_CONFIRMED;
107440cb5e5vi		} else {
107540cb5e5vi			(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
107640cb5e5vi			if (sip_ulp_dlg_del_cb != NULL) {
107740cb5e5vi				sip_ulp_dlg_del_cb(dialog, (sip_msg_t)sip_msg,
107840cb5e5vi				    NULL);
107940cb5e5vi			}
108040cb5e5vi			if (alloc_thdr)
108140cb5e5vi				sip_free_header(thdr);
10822c2c418vi			goto terminate_new_dlg;
108340cb5e5vi		}
108440cb5e5vi		if (dialog->sip_dlg_type == SIP_UAS_DIALOG) {
108540cb5e5vi			dialog->sip_dlg_local_uri_tag = thdr;
108640cb5e5vi		} else {
108740cb5e5vi			if ((dialog->sip_dlg_remote_uri_tag =
108840cb5e5vi			    sip_dup_header(thdr)) == NULL) {
108940cb5e5vi				(void) pthread_mutex_unlock(
109040cb5e5vi				    &dialog->sip_dlg_mutex);
10912c2c418vi				goto terminate_new_dlg;
109240cb5e5vi			}
109340cb5e5vi		}
109440cb5e5vi	}
109540cb5e5vi
109640cb5e5vi	/*
1097d8a4038gm	 * We take the local contact for UAS Dialog from the response (either
1098d8a4038gm	 * NOTIFY for SUBSCRIBE request or from final response 2xx to INVITE
1099d8a4038gm	 * request)
1100d8a4038gm	 */
1101d8a4038gm	if ((dialog->sip_dlg_type == SIP_UAS_DIALOG) && (dialog->sip_dlg_state
1102d8a4038gm	    == SIP_DLG_CONFIRMED)) {
1103d8a4038gm		if (chdr == NULL) {
1104d8a4038gm			(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
1105d8a4038gm			chdr = sip_search_for_header(sip_msg, SIP_CONTACT,
1106d8a4038gm			    NULL);
1107d8a4038gm			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
1108d8a4038gm		}
1109d8a4038gm		if ((chdr == NULL) || ((dialog->sip_dlg_local_contact =
1110d8a4038gm		    sip_dup_header(chdr)) == NULL)) {
1111d8a4038gm			(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1112d8a4038gm			if (alloc_thdr)
1113d8a4038gm				sip_free_header(thdr);
1114d8a4038gm			goto terminate_new_dlg;
1115d8a4038gm		}
1116d8a4038gm	}
1117d8a4038gm
1118d8a4038gm	/*
111940cb5e5vi	 * Cancel the partial dialog timer
112040cb5e5vi	 */
112140cb5e5vi	if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
112240cb5e5vi		SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
112340cb5e5vi
112440cb5e5vi	if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
112540cb5e5vi		val =  sip_get_header_value(dialog->sip_dlg_local_uri_tag,
112640cb5e5vi		    &error);
112740cb5e5vi	} else {
112840cb5e5vi		val =  sip_get_header_value(dialog->sip_dlg_remote_uri_tag,
112940cb5e5vi		    &error);
113040cb5e5vi	}
1131943efbcgm	if (val == NULL || error != 0) {
1132943efbcgm		sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
1133943efbcgm		    SIP_ASSERT_ERROR, __FILE__, __LINE__);
1134943efbcgm	}
113540cb5e5vi	assert(val != NULL && error == 0);
113640cb5e5vi	remtag = sip_get_param_value((sip_header_value_t)val, "tag", &error);
113740cb5e5vi
113840cb5e5vi	val = sip_get_header_value(dialog->sip_dlg_call_id, &error);
113940cb5e5vi	callid = &((sip_hdr_value_t *)val)->str_val;
114040cb5e5vi
114140cb5e5vi	/*
114240cb5e5vi	 * Get an ID for this dialog
114340cb5e5vi	 */
114440cb5e5vi	if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
114540cb5e5vi		sip_md5_hash(remtag->sip_str_ptr, remtag->sip_str_len,
114640cb5e5vi		    ttag->sip_str_ptr, ttag->sip_str_len,
114740cb5e5vi		    callid->sip_str_ptr, callid->sip_str_len,
114840cb5e5vi		    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id);
114940cb5e5vi	} else {
115040cb5e5vi		sip_md5_hash(ttag->sip_str_ptr, ttag->sip_str_len,
115140cb5e5vi		    remtag->sip_str_ptr, remtag->sip_str_len,
115240cb5e5vi		    callid->sip_str_ptr, callid->sip_str_len,
115340cb5e5vi		    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id);
115440cb5e5vi	}
115540cb5e5vi
115640cb5e5vi	SIP_DLG_REFCNT_INCR(dialog);
115740cb5e5vi	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
115840cb5e5vi
115940cb5e5vi	/*
116040cb5e5vi	 * Add it to the hash table
116140cb5e5vi	 */
116240cb5e5vi	if (sip_hash_add(sip_dialog_hash, (void *)dialog,
116340cb5e5vi	    SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) {
11642c2c418vi	terminate_new_dlg:
116540cb5e5vi		/*
116640cb5e5vi		 * So that sip_dialog_delete() does not try to remove
116740cb5e5vi		 * this from the hash table.
116840cb5e5vi		 */
116940cb5e5vi		(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
117040cb5e5vi		if (dialog->sip_dlg_type == SIP_UAS_DIALOG) {
11712c2c418vi			if (dialog->sip_dlg_local_uri_tag != NULL) {
11722c2c418vi				sip_free_header(dialog->sip_dlg_local_uri_tag);
11732c2c418vi				dialog->sip_dlg_local_uri_tag = NULL;
11742c2c418vi			}
117540cb5e5vi		} else {
11762c2c418vi			if (dialog->sip_dlg_remote_uri_tag != NULL) {
11772c2c418vi				sip_free_header(dialog->sip_dlg_remote_uri_tag);
11782c2c418vi				dialog->sip_dlg_remote_uri_tag = NULL;
11792c2c418vi			}
118040cb5e5vi		}
118140cb5e5vi		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
118240cb5e5vi		sip_dialog_terminate(dialog, (sip_msg_t)sip_msg);
118340cb5e5vi		return (NULL);
118440cb5e5vi	}
118540cb5e5vi	if (sip_dlg_ulp_state_cb != NULL) {
118640cb5e5vi		sip_dlg_ulp_state_cb((sip_dialog_t)dialog,
118740cb5e5vi		    (sip_msg_t)sip_msg, prev_state, dialog->sip_dlg_state);
118840cb5e5vi	}
118940cb5e5vi	return ((sip_dialog_t)dialog);
119040cb5e5vi}
119140cb5e5vi
119240cb5e5vi/*
119340cb5e5vi * Check if this dialog is a match.
119440cb5e5vi */
119540cb5e5viboolean_t
119640cb5e5visip_dialog_match(void *obj, void *hindex)
119740cb5e5vi{
119840cb5e5vi	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
119940cb5e5vi
120040cb5e5vi	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
120140cb5e5vi	if (dialog->sip_dlg_state == SIP_DLG_DESTROYED) {
120240cb5e5vi		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
120340cb5e5vi		return (B_FALSE);
120440cb5e5vi	}
120540cb5e5vi	if (bcmp(dialog->sip_dlg_id, hindex,
120640cb5e5vi	    sizeof (dialog->sip_dlg_id)) == 0) {
120740cb5e5vi		SIP_DLG_REFCNT_INCR(dialog);
120840cb5e5vi		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
120940cb5e5vi		return (B_TRUE);
121040cb5e5vi	}
121140cb5e5vi	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
121240cb5e5vi	return (B_FALSE);
121340cb5e5vi}
121440cb5e5vi
121540cb5e5vi/*
121640cb5e5vi * Don't delete, just take it out of the hash
121740cb5e5vi */
121840cb5e5viboolean_t
121940cb5e5visip_dialog_dontfree(void *obj, void *hindex, int *found)
122040cb5e5vi{
122140cb5e5vi	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
122240cb5e5vi
122340cb5e5vi	*found = 0;
122440cb5e5vi	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
122540cb5e5vi	if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id))
122640cb5e5vi	    == 0) {
122740cb5e5vi		*found = 1;
122840cb5e5vi		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
122940cb5e5vi		return (B_TRUE);
123040cb5e5vi	}
123140cb5e5vi	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
123240cb5e5vi	return (B_FALSE);
123340cb5e5vi}
123440cb5e5vi
123540cb5e5vi/*
123640cb5e5vi * Free resources associated with the dialog, the object will be removed
123740cb5e5vi * from the hash list by sip_hash_delete.
123840cb5e5vi */
123940cb5e5viboolean_t
124040cb5e5visip_dialog_free(void *obj, void *hindex, int *found)
124140cb5e5vi{
124240cb5e5vi	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
124340cb5e5vi
124440cb5e5vi	*found = 0;
124540cb5e5vi	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
124640cb5e5vi	if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id))
124740cb5e5vi	    == 0) {
124840cb5e5vi		*found = 1;
1249943efbcgm		if (dialog->sip_dlg_state != SIP_DLG_DESTROYED) {
1250943efbcgm			sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
1251943efbcgm			    SIP_ASSERT_ERROR, __FILE__, __LINE__);
1252943efbcgm		}
125340cb5e5vi		assert(dialog->sip_dlg_state == SIP_DLG_DESTROYED);
125440cb5e5vi		if (dialog->sip_dlg_ref_cnt != 0) {
125540cb5e5vi			(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
125640cb5e5vi			return (B_FALSE);
125740cb5e5vi		}
1258943efbcgm		sip_write_to_log((void *)dialog, SIP_DIALOG_LOG, NULL, 0);
125940cb5e5vi		sip_release_dialog_res(dialog);
126040cb5e5vi		return (B_TRUE);
126140cb5e5vi	}
126240cb5e5vi	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
126340cb5e5vi	return (B_FALSE);
126440cb5e5vi}
126540cb5e5vi
126640cb5e5vi/*
126740cb5e5vi * The UAS will receive the request from the transaction layer.  If the
126840cb5e5vi * request has a tag in the To header field, the UAS core computes the
126940cb5e5vi * dialog identifier corresponding to the request and compares it with
127040cb5e5vi * existing dialogs.  If there is a match, this is a mid-dialog request.
127140cb5e5vi */
127240cb5e5visip_dialog_t
127340cb5e5visip_dialog_find(_sip_msg_t *sip_msg)
127440cb5e5vi{
127540cb5e5vi	const sip_str_t	*localtag;
127640cb5e5vi	const sip_str_t	*remtag;
127740cb5e5vi	const sip_str_t	*callid;
127840cb5e5vi	uint16_t	digest[8];
127940cb5e5vi	_sip_dialog_t	*dialog;
128040cb5e5vi	boolean_t	is_request;
128140cb5e5vi	int		error;
128240cb5e5vi
128340cb5e5vi	is_request = sip_msg_is_request((sip_msg_t)sip_msg, &error);
128440cb5e5vi	if (error != 0)
128540cb5e5vi		return (NULL);
128640cb5e5vi	if (is_request) {
128740cb5e5vi		localtag = sip_get_to_tag((sip_msg_t)sip_msg, &error);
128840cb5e5vi		if (error == 0)
128940cb5e5vi			remtag = sip_get_from_tag((sip_msg_t)sip_msg, &error);
129040cb5e5vi	} else {
129140cb5e5vi		remtag = sip_get_to_tag((sip_msg_t)sip_msg, &error);
129240cb5e5vi		if (error == 0)
129340cb5e5vi			localtag = sip_get_from_tag((sip_msg_t)sip_msg, &error);
129440cb5e5vi	}
129540cb5e5vi	if (error != 0)
129640cb5e5vi		return (NULL);
129740cb5e5vi	callid = sip_get_callid((sip_msg_t)sip_msg, &error);
129840cb5e5vi	if (error != 0 || remtag == NULL || localtag == NULL ||
129940cb5e5vi	    callid == NULL) {
130040cb5e5vi		return (NULL);
130140cb5e5vi	}
130240cb5e5vi	sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len,
130340cb5e5vi	    remtag->sip_str_ptr, remtag->sip_str_len,
130440cb5e5vi	    callid->sip_str_ptr, callid->sip_str_len,
130540cb5e5vi	    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest);
130640cb5e5vi
130740cb5e5vi	dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_hash,
130840cb5e5vi	    (void *)digest, SIP_DIGEST_TO_HASH(digest), sip_dialog_match);
130940cb5e5vi	if (dialog == NULL) {
131040cb5e5vi		sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len,
131140cb5e5vi		    NULL, 0, callid->sip_str_ptr, callid->sip_str_len,
131240cb5e5vi		    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest);
131340cb5e5vi		dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_phash,
131440cb5e5vi		    (void *)digest, SIP_DIGEST_TO_HASH(digest),
131540cb5e5vi		    sip_dialog_match);
131640cb5e5vi	}
131740cb5e5vi	return ((sip_dialog_t)dialog);
131840cb5e5vi}
131940cb5e5vi
132040cb5e5vi/*
132140cb5e5vi * We keep this partial dialog for the duration of the INVITE
132240cb5e5vi * transaction timeout duration, i.e. Timer B.
132340cb5e5vi */
132440cb5e5vivoid
132540cb5e5visip_dlg_self_destruct(void *args)
132640cb5e5vi{
132740cb5e5vi	sip_dialog_timer_obj_t	*tim_obj = (sip_dialog_timer_obj_t *)args;
132840cb5e5vi	_sip_dialog_t		*dialog = (_sip_dialog_t *)tim_obj->dialog;
132940cb5e5vi	int			index;
133040cb5e5vi
133140cb5e5vi	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
1332943efbcgm	if (dialog->sip_dlg_state != SIP_DLG_NEW) {
1333943efbcgm		sip_write_to_log((void *)dialog, SIP_DIALOG_LOG |
1334943efbcgm		    SIP_ASSERT_ERROR, __FILE__, __LINE__);
1335943efbcgm	}
133640cb5e5vi	assert(dialog->sip_dlg_state == SIP_DLG_NEW);
133740cb5e5vi	dialog->sip_dlg_state = SIP_DLG_DESTROYED;
133840cb5e5vi	if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
133940cb5e5vi		index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id);
134040cb5e5vi		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
134140cb5e5vi		sip_hash_delete(sip_dialog_phash, (void *)dialog->sip_dlg_id,
134240cb5e5vi		    index, sip_dialog_dontfree);
134340cb5e5vi	} else {
134440cb5e5vi		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
134540cb5e5vi	}
134640cb5e5vi	if (tim_obj->func != NULL)
134740cb5e5vi		tim_obj->func(dialog, NULL, NULL);
134840cb5e5vi	free(tim_obj);
134940cb5e5vi	SIP_DLG_REFCNT_DECR(dialog);
135040cb5e5vi}
135140cb5e5vi
135240cb5e5vi/*
135340cb5e5vi * Terminate a dialog
135440cb5e5vi */
135540cb5e5vivoid
135640cb5e5visip_dialog_terminate(_sip_dialog_t *dialog, sip_msg_t sip_msg)
135740cb5e5vi{
135840cb5e5vi	int	prev_state;
135940cb5e5vi
136040cb5e5vi	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
136140cb5e5vi	prev_state = dialog->sip_dlg_state;
136240cb5e5vi	dialog->sip_dlg_state = SIP_DLG_DESTROYED;
136340cb5e5vi	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
136440cb5e5vi	if (sip_dlg_ulp_state_cb != NULL) {
136540cb5e5vi		sip_dlg_ulp_state_cb((sip_dialog_t)dialog,