xref: /illumos-gate/usr/src/lib/libsip/common/sip_dialog.c (revision d8a40387f8abe74df38502eca4b369b9eada4864)
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 /*
232c2c4183Svi  * Copyright 2007 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 {
11140cb5e5dSvi 
11240cb5e5dSvi 	assert(dialog->sip_dlg_ref_cnt == 0);
11340cb5e5dSvi 	if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
11440cb5e5dSvi 		SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
11540cb5e5dSvi 	if (dialog->sip_dlg_call_id != NULL)
11640cb5e5dSvi 		sip_free_header(dialog->sip_dlg_call_id);
11740cb5e5dSvi 	if (dialog->sip_dlg_local_uri_tag != NULL)
11840cb5e5dSvi 		sip_free_header(dialog->sip_dlg_local_uri_tag);
11940cb5e5dSvi 	if (dialog->sip_dlg_remote_uri_tag != NULL)
12040cb5e5dSvi 		sip_free_header(dialog->sip_dlg_remote_uri_tag);
12140cb5e5dSvi 	if (dialog->sip_dlg_remote_target != NULL)
12240cb5e5dSvi 		sip_free_header(dialog->sip_dlg_remote_target);
123*d8a40387Sgm 	if (dialog->sip_dlg_local_contact != NULL)
124*d8a40387Sgm 		sip_free_header(dialog->sip_dlg_local_contact);
125*d8a40387Sgm 	if (dialog->sip_dlg_new_local_contact != NULL)
126*d8a40387Sgm 		sip_free_header(dialog->sip_dlg_new_local_contact);
12740cb5e5dSvi 	if (dialog->sip_dlg_route_set != NULL)
12840cb5e5dSvi 		sip_free_header(dialog->sip_dlg_route_set);
12940cb5e5dSvi 	if (dialog->sip_dlg_event != NULL)
13040cb5e5dSvi 		sip_free_header(dialog->sip_dlg_event);
13140cb5e5dSvi 	if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) {
13240cb5e5dSvi 		free(dialog->sip_dlg_req_uri.sip_str_ptr);
13340cb5e5dSvi 		dialog->sip_dlg_req_uri.sip_str_ptr = NULL;
13440cb5e5dSvi 		dialog->sip_dlg_req_uri.sip_str_len = 0;
13540cb5e5dSvi 	}
13640cb5e5dSvi 	if (dialog->sip_dlg_rset.sip_str_ptr != NULL) {
13740cb5e5dSvi 		free(dialog->sip_dlg_rset.sip_str_ptr);
13840cb5e5dSvi 		dialog->sip_dlg_rset.sip_str_len = 0;
13940cb5e5dSvi 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
14040cb5e5dSvi 	}
14140cb5e5dSvi 	(void) pthread_mutex_destroy(&dialog->sip_dlg_mutex);
14240cb5e5dSvi 	free(dialog);
14340cb5e5dSvi }
14440cb5e5dSvi 
14540cb5e5dSvi /*
14640cb5e5dSvi  * Get the route information from the 'value' and add it to the route
14740cb5e5dSvi  * set.
14840cb5e5dSvi  */
14940cb5e5dSvi static sip_dlg_route_set_t *
15040cb5e5dSvi sip_add_route_to_set(sip_hdr_value_t *value)
15140cb5e5dSvi {
15240cb5e5dSvi 	int			vlen = 0;
15340cb5e5dSvi 	sip_dlg_route_set_t	*rset;
15440cb5e5dSvi 	char			*crlf;
15540cb5e5dSvi 	const sip_param_t	*uri_param;
15640cb5e5dSvi 	int			error;
15740cb5e5dSvi 
15840cb5e5dSvi 	rset = calloc(1, sizeof (*rset));
15940cb5e5dSvi 	if (rset == NULL)
16040cb5e5dSvi 		return (NULL);
16140cb5e5dSvi 	rset->sip_dlg_route_next = NULL;
16240cb5e5dSvi 	vlen = value->sip_value_end - value->sip_value_start;
16340cb5e5dSvi 
16440cb5e5dSvi 	/*
16540cb5e5dSvi 	 * check for CRLF
16640cb5e5dSvi 	 */
16740cb5e5dSvi 	crlf = value->sip_value_end - strlen(SIP_CRLF);
16840cb5e5dSvi 	while (crlf != NULL && strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) {
16940cb5e5dSvi 		vlen -= strlen(SIP_CRLF);
17040cb5e5dSvi 		crlf -= strlen(SIP_CRLF);
17140cb5e5dSvi 	}
17240cb5e5dSvi 	rset->sip_dlg_route = calloc(1, vlen + 1);
17340cb5e5dSvi 	if (rset->sip_dlg_route == NULL) {
17440cb5e5dSvi 		free(rset);
17540cb5e5dSvi 		return (NULL);
17640cb5e5dSvi 	}
17740cb5e5dSvi 	/*
17840cb5e5dSvi 	 * loose routing
17940cb5e5dSvi 	 */
18040cb5e5dSvi 	rset->sip_dlg_route_lr = B_FALSE;
18140cb5e5dSvi 	(void) strncpy(rset->sip_dlg_route, value->sip_value_start, vlen);
18240cb5e5dSvi 	rset->sip_dlg_ruri.sip_str_ptr = rset->sip_dlg_route +
18340cb5e5dSvi 	    (value->cftr_uri.sip_str_ptr - value->sip_value_start);
18440cb5e5dSvi 	rset->sip_dlg_ruri.sip_str_len = value->cftr_uri.sip_str_len;
18540cb5e5dSvi 	rset->sip_dlg_route[vlen] = '\0';
18640cb5e5dSvi 
18740cb5e5dSvi 	assert(value->sip_value_parsed_uri != NULL);
18840cb5e5dSvi 	/*
18940cb5e5dSvi 	 * Check if the 'lr' param is present for this route.
19040cb5e5dSvi 	 */
19140cb5e5dSvi 	uri_param = sip_get_uri_params(value->sip_value_parsed_uri, &error);
19240cb5e5dSvi 	if (error != 0) {
19340cb5e5dSvi 		free(rset->sip_dlg_route);
19440cb5e5dSvi 		free(rset);
19540cb5e5dSvi 		return (NULL);
19640cb5e5dSvi 	}
19740cb5e5dSvi 	if (uri_param != NULL) {
19840cb5e5dSvi 		rset->sip_dlg_route_lr = sip_is_param_present(uri_param, "lr",
19940cb5e5dSvi 		    strlen("lr"));
20040cb5e5dSvi 	}
20140cb5e5dSvi 	return (rset);
20240cb5e5dSvi }
20340cb5e5dSvi 
20440cb5e5dSvi /*
20540cb5e5dSvi  * Depending on the route-set, determine the request URI.
20640cb5e5dSvi  */
20740cb5e5dSvi char *
20840cb5e5dSvi sip_dialog_req_uri(sip_dialog_t dialog)
20940cb5e5dSvi {
21040cb5e5dSvi 	const sip_str_t		*req_uri;
21140cb5e5dSvi 	char			*uri;
21240cb5e5dSvi 	_sip_dialog_t		*_dialog;
21340cb5e5dSvi 
21440cb5e5dSvi 	_dialog = (_sip_dialog_t *)dialog;
21540cb5e5dSvi 	if (_dialog->sip_dlg_route_set == NULL ||
21640cb5e5dSvi 	    _dialog->sip_dlg_req_uri.sip_str_ptr == NULL) {
21740cb5e5dSvi 		const struct sip_value	*val;
21840cb5e5dSvi 
21940cb5e5dSvi 		val = sip_get_header_value(_dialog->sip_dlg_remote_target,
22040cb5e5dSvi 		    NULL);
22140cb5e5dSvi 		if (val == NULL)
22240cb5e5dSvi 			return (NULL);
22340cb5e5dSvi 		req_uri = &((sip_hdr_value_t *)val)->cftr_uri;
22440cb5e5dSvi 	} else {
22540cb5e5dSvi 		req_uri = &_dialog->sip_dlg_req_uri;
22640cb5e5dSvi 	}
22740cb5e5dSvi 	uri = (char *)malloc(req_uri->sip_str_len + 1);
22840cb5e5dSvi 	if (uri == NULL)
22940cb5e5dSvi 		return (NULL);
23040cb5e5dSvi 	(void) strncpy(uri, req_uri->sip_str_ptr, req_uri->sip_str_len);
23140cb5e5dSvi 	uri[req_uri->sip_str_len] = '\0';
23240cb5e5dSvi 
23340cb5e5dSvi 	return (uri);
23440cb5e5dSvi }
23540cb5e5dSvi 
23640cb5e5dSvi /*
23740cb5e5dSvi  * Free the route set.
23840cb5e5dSvi  */
23940cb5e5dSvi void
24040cb5e5dSvi sip_dialog_free_rset(sip_dlg_route_set_t *rset)
24140cb5e5dSvi {
24240cb5e5dSvi 	sip_dlg_route_set_t	*next;
24340cb5e5dSvi 
24440cb5e5dSvi 	while (rset != NULL) {
24540cb5e5dSvi 		next = rset->sip_dlg_route_next;
24640cb5e5dSvi 		rset->sip_dlg_route_next = NULL;
24740cb5e5dSvi 		free(rset->sip_dlg_route);
24840cb5e5dSvi 		free(rset);
24940cb5e5dSvi 		rset = next;
25040cb5e5dSvi 	}
25140cb5e5dSvi }
25240cb5e5dSvi 
25340cb5e5dSvi /*
25440cb5e5dSvi  * Recompute route-set
25540cb5e5dSvi  */
25640cb5e5dSvi static int
25740cb5e5dSvi sip_dlg_recompute_rset(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what)
25840cb5e5dSvi {
25940cb5e5dSvi 	int ret;
26040cb5e5dSvi 
26140cb5e5dSvi 	if (dialog->sip_dlg_route_set != NULL) {
26240cb5e5dSvi 		sip_free_header(dialog->sip_dlg_route_set);
26340cb5e5dSvi 		dialog->sip_dlg_route_set = NULL;
26440cb5e5dSvi 	}
26540cb5e5dSvi 	if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) {
26640cb5e5dSvi 		free(dialog->sip_dlg_req_uri.sip_str_ptr);
26740cb5e5dSvi 		dialog->sip_dlg_req_uri.sip_str_ptr = NULL;
26840cb5e5dSvi 		dialog->sip_dlg_req_uri.sip_str_len = 0;
26940cb5e5dSvi 	}
27040cb5e5dSvi 	if (dialog->sip_dlg_rset.sip_str_ptr != NULL) {
27140cb5e5dSvi 		free(dialog->sip_dlg_rset.sip_str_ptr);
27240cb5e5dSvi 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
27340cb5e5dSvi 		dialog->sip_dlg_rset.sip_str_len = 0;
27440cb5e5dSvi 	}
27540cb5e5dSvi 	ret = sip_dialog_get_route_set(dialog, sip_msg, what);
27640cb5e5dSvi 	return (ret);
27740cb5e5dSvi }
27840cb5e5dSvi 
27940cb5e5dSvi /*
28040cb5e5dSvi  * If the route set is empty, the UAC MUST place the remote target URI
28140cb5e5dSvi  * into the Request-URI.  The UAC MUST NOT add a Route header field to
28240cb5e5dSvi  * the request.
28340cb5e5dSvi  *
28440cb5e5dSvi  * If the route set is not empty, and the first URI in the route set
28540cb5e5dSvi  * contains the lr parameter (see Section 19.1.1), the UAC MUST place
28640cb5e5dSvi  * the remote target URI into the Request-URI and MUST include a Route
28740cb5e5dSvi  * header field containing the route set values in order, including all
28840cb5e5dSvi  * parameters.
28940cb5e5dSvi  *
29040cb5e5dSvi  * If the route set is not empty, and its first URI does not contain the
29140cb5e5dSvi  * lr parameter, the UAC MUST place the first URI from the route set
29240cb5e5dSvi  * into the Request-URI, stripping any parameters that are not allowed
29340cb5e5dSvi  * in a Request-URI.  The UAC MUST add a Route header field containing
29440cb5e5dSvi  * the remainder of the route set values in order, including all
29540cb5e5dSvi  * parameters.  The UAC MUST then place the remote target URI into the
29640cb5e5dSvi  * Route header field as the last value.
29740cb5e5dSvi  */
29840cb5e5dSvi int
29940cb5e5dSvi sip_dialog_set_route_hdr(_sip_dialog_t *dialog, sip_dlg_route_set_t *rset_head,
30040cb5e5dSvi     int rcnt, int rlen)
30140cb5e5dSvi {
30240cb5e5dSvi 	size_t			rset_len;
30340cb5e5dSvi 	_sip_header_t		*rhdr;
30440cb5e5dSvi 	char			*rset;
30540cb5e5dSvi 	char			*rp;
30640cb5e5dSvi 	char			*rsp;
30740cb5e5dSvi 	int			count;
30840cb5e5dSvi 	sip_dlg_route_set_t	*route;
30940cb5e5dSvi 	boolean_t		first = B_TRUE;
31040cb5e5dSvi 	const sip_str_t		*to_uri;
31140cb5e5dSvi 	char			*uri = NULL;
31240cb5e5dSvi 	int			rspl;
31340cb5e5dSvi 	int			rpl;
31440cb5e5dSvi 
31540cb5e5dSvi 	assert(rcnt > 0);
31640cb5e5dSvi 
31740cb5e5dSvi 	dialog->sip_dlg_rset.sip_str_len = rlen + rcnt - 1;
31840cb5e5dSvi 	dialog->sip_dlg_rset.sip_str_ptr = malloc(rlen + rcnt);
31940cb5e5dSvi 	if (dialog->sip_dlg_rset.sip_str_ptr == NULL)
32040cb5e5dSvi 		return (ENOMEM);
32140cb5e5dSvi 	rsp = dialog->sip_dlg_rset.sip_str_ptr;
32240cb5e5dSvi 	rspl = rlen + rcnt;
32340cb5e5dSvi 	route = rset_head;
32440cb5e5dSvi 	rset_len = rlen;
32540cb5e5dSvi 	if (!route->sip_dlg_route_lr) {
32640cb5e5dSvi 		const struct sip_value	*val;
32740cb5e5dSvi 
32840cb5e5dSvi 		val = sip_get_header_value(dialog->sip_dlg_remote_target, NULL);
32940cb5e5dSvi 		to_uri = &((sip_hdr_value_t *)val)->cftr_uri;
33040cb5e5dSvi 		uri = (char *)malloc(to_uri->sip_str_len + 1);
33140cb5e5dSvi 		if (uri == NULL) {
33240cb5e5dSvi 			free(dialog->sip_dlg_rset.sip_str_ptr);
33340cb5e5dSvi 			dialog->sip_dlg_rset.sip_str_len = 0;
33440cb5e5dSvi 			dialog->sip_dlg_rset.sip_str_ptr = NULL;
33540cb5e5dSvi 			return (ENOMEM);
33640cb5e5dSvi 		}
33740cb5e5dSvi 		(void) strncpy(uri, to_uri->sip_str_ptr, to_uri->sip_str_len);
33840cb5e5dSvi 		uri[to_uri->sip_str_len] = '\0';
33940cb5e5dSvi 		rset_len = rlen - strlen(route->sip_dlg_route) + strlen(uri) +
34040cb5e5dSvi 		    SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN +
34140cb5e5dSvi 		    sizeof (char);
34240cb5e5dSvi 		count = snprintf(rsp, rspl, "%s", route->sip_dlg_route);
34340cb5e5dSvi 		dialog->sip_dlg_req_uri.sip_str_ptr = malloc(
34440cb5e5dSvi 		    route->sip_dlg_ruri.sip_str_len + 1);
34540cb5e5dSvi 		if (dialog->sip_dlg_req_uri.sip_str_ptr == NULL) {
34640cb5e5dSvi 			free(uri);
34740cb5e5dSvi 			free(dialog->sip_dlg_rset.sip_str_ptr);
34840cb5e5dSvi 			dialog->sip_dlg_rset.sip_str_len = 0;
34940cb5e5dSvi 			dialog->sip_dlg_rset.sip_str_ptr = NULL;
35040cb5e5dSvi 			return (ENOMEM);
35140cb5e5dSvi 		}
35240cb5e5dSvi 		(void) strncpy(dialog->sip_dlg_req_uri.sip_str_ptr, rsp +
35340cb5e5dSvi 		    (route->sip_dlg_ruri.sip_str_ptr - route->sip_dlg_route),
35440cb5e5dSvi 		    route->sip_dlg_ruri.sip_str_len);
35540cb5e5dSvi 		dialog->sip_dlg_req_uri.sip_str_ptr[
35640cb5e5dSvi 		    route->sip_dlg_ruri.sip_str_len] = '\0';
35740cb5e5dSvi 		dialog->sip_dlg_req_uri.sip_str_len =
35840cb5e5dSvi 		    route->sip_dlg_ruri.sip_str_len;
35940cb5e5dSvi 
36040cb5e5dSvi 		rsp += count;
36140cb5e5dSvi 		rspl -= count;
36240cb5e5dSvi 		route = route->sip_dlg_route_next;
36340cb5e5dSvi 	}
36440cb5e5dSvi 
36540cb5e5dSvi 	/*
36640cb5e5dSvi 	 * rcnt - 1 is for the number of COMMAs
36740cb5e5dSvi 	 */
36840cb5e5dSvi 	rset_len += strlen(SIP_ROUTE) + SIP_SPACE_LEN + sizeof (char) +
36940cb5e5dSvi 	    SIP_SPACE_LEN + rcnt - 1;
37040cb5e5dSvi 	rset = malloc(rset_len + 1);
37140cb5e5dSvi 	if (rset == NULL) {
37240cb5e5dSvi 		free(dialog->sip_dlg_rset.sip_str_ptr);
37340cb5e5dSvi 		dialog->sip_dlg_rset.sip_str_len = 0;
37440cb5e5dSvi 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
37540cb5e5dSvi 		return (ENOMEM);
37640cb5e5dSvi 	}
37740cb5e5dSvi 	rhdr = sip_new_header(rset_len + strlen(SIP_CRLF));
37840cb5e5dSvi 	if (rhdr == NULL) {
37940cb5e5dSvi 		free(rset);
38040cb5e5dSvi 		free(dialog->sip_dlg_rset.sip_str_ptr);
38140cb5e5dSvi 		dialog->sip_dlg_rset.sip_str_len = 0;
38240cb5e5dSvi 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
38340cb5e5dSvi 		return (ENOMEM);
38440cb5e5dSvi 	}
38540cb5e5dSvi 
38640cb5e5dSvi 	rp = rset;
38740cb5e5dSvi 	rpl = rset_len + 1;
38840cb5e5dSvi 	count = snprintf(rp, rpl, "%s %c ", SIP_ROUTE, SIP_HCOLON);
38940cb5e5dSvi 	rp += count;
39040cb5e5dSvi 	rpl -= count;
39140cb5e5dSvi 
39240cb5e5dSvi 	while (route != NULL) {
39340cb5e5dSvi 		if (first) {
39440cb5e5dSvi 			count = snprintf(rp, rpl, "%s", route->sip_dlg_route);
39540cb5e5dSvi 			rp += count;
39640cb5e5dSvi 			rpl -= count;
39740cb5e5dSvi 			first = B_FALSE;
39840cb5e5dSvi 			if (uri != NULL) {
39940cb5e5dSvi 				count = snprintf(rsp, rspl, "%c%s",
40040cb5e5dSvi 				    SIP_COMMA, route->sip_dlg_route);
40140cb5e5dSvi 			} else {
40240cb5e5dSvi 				count = snprintf(rsp, rspl, "%s",
40340cb5e5dSvi 				    route->sip_dlg_route);
40440cb5e5dSvi 			}
40540cb5e5dSvi 			rsp += count;
40640cb5e5dSvi 			rspl -= count;
40740cb5e5dSvi 		} else {
40840cb5e5dSvi 			count = snprintf(rp, rpl, "%c%s", SIP_COMMA,
40940cb5e5dSvi 			    route->sip_dlg_route);
41040cb5e5dSvi 			rp += count;
41140cb5e5dSvi 			rpl -= count;
41240cb5e5dSvi 			count = snprintf(rsp, rspl, "%c%s", SIP_COMMA,
41340cb5e5dSvi 			    route->sip_dlg_route);
41440cb5e5dSvi 			rsp += count;
41540cb5e5dSvi 			rspl -= count;
41640cb5e5dSvi 		}
41740cb5e5dSvi 		route = route->sip_dlg_route_next;
41840cb5e5dSvi 	}
41940cb5e5dSvi 	assert(rsp <= dialog->sip_dlg_rset.sip_str_ptr +
42040cb5e5dSvi 	    dialog->sip_dlg_rset.sip_str_len);
42140cb5e5dSvi 	dialog->sip_dlg_rset.sip_str_ptr[dialog->sip_dlg_rset.sip_str_len] =
42240cb5e5dSvi 	    '\0';
42340cb5e5dSvi 	if (uri != NULL) {
42440cb5e5dSvi 		if (first) {
42540cb5e5dSvi 			count = snprintf(rp, rpl, "%c %s %c", SIP_LAQUOT,
42640cb5e5dSvi 			    uri, SIP_RAQUOT);
42740cb5e5dSvi 		} else {
42840cb5e5dSvi 			count = snprintf(rp, rpl, "%c%c %s %c", SIP_COMMA,
42940cb5e5dSvi 			    SIP_LAQUOT, uri, SIP_RAQUOT);
43040cb5e5dSvi 		}
43140cb5e5dSvi 		rp += count;
43240cb5e5dSvi 		rpl -= count;
43340cb5e5dSvi 		free(uri);
43440cb5e5dSvi 	}
43540cb5e5dSvi 	assert(rp <= rset + rset_len);
43640cb5e5dSvi 	(void) snprintf(rhdr->sip_hdr_start, rset_len + strlen(SIP_CRLF) + 1,
43740cb5e5dSvi 	    "%s%s", rset, SIP_CRLF);
43840cb5e5dSvi 	free(rset);
43940cb5e5dSvi 	dialog->sip_dlg_route_set = (sip_header_t)rhdr;
44040cb5e5dSvi 	sip_dialog_free_rset(rset_head);
44140cb5e5dSvi 	return (0);
44240cb5e5dSvi }
44340cb5e5dSvi 
44440cb5e5dSvi /*
44540cb5e5dSvi  * UAC Behavior
44640cb5e5dSvi  * The route set MUST be set to the list of URIs in the Record-Route
44740cb5e5dSvi  * header field from the response, taken in reverse order and preserving
44840cb5e5dSvi  * all URI parameters.
44940cb5e5dSvi  *
45040cb5e5dSvi  * UAS behavior
45140cb5e5dSvi  * The route set MUST be set to the list of URIs in the Record-Route
45240cb5e5dSvi  * header field from the request, taken in order and preserving all URI
45340cb5e5dSvi  * parameters.
45440cb5e5dSvi  */
45540cb5e5dSvi static int
45640cb5e5dSvi sip_dialog_get_route_set(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what)
45740cb5e5dSvi {
45840cb5e5dSvi 	sip_header_t		rrhdr;
45940cb5e5dSvi 	sip_hdr_value_t		*value;
46040cb5e5dSvi 	int			error;
46140cb5e5dSvi 	sip_dlg_route_set_t	*rset_head = NULL;
46240cb5e5dSvi 	sip_dlg_route_set_t	*rset_tail = NULL;
46340cb5e5dSvi 	sip_dlg_route_set_t	*rset;
46440cb5e5dSvi 	int			rset_cnt = 0;
46540cb5e5dSvi 	int			rset_len = 0;
46640cb5e5dSvi 
46740cb5e5dSvi 	(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
46840cb5e5dSvi 	rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, NULL);
46940cb5e5dSvi 	while (rrhdr != NULL) {
47040cb5e5dSvi 		(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
47140cb5e5dSvi 		value = (sip_hdr_value_t *)sip_get_header_value(rrhdr, &error);
47240cb5e5dSvi 		while (value != NULL && error == 0) {
47340cb5e5dSvi 			char	*crlf;
47440cb5e5dSvi 
47540cb5e5dSvi 			if (value->sip_value_state == SIP_VALUE_BAD) {
47640cb5e5dSvi 				value = (sip_hdr_value_t *)sip_get_next_value(
47740cb5e5dSvi 				    (sip_header_value_t)value, &error);
47840cb5e5dSvi 				continue;
47940cb5e5dSvi 			}
48040cb5e5dSvi 			rset = sip_add_route_to_set(value);
48140cb5e5dSvi 			if (rset == NULL)
48240cb5e5dSvi 				goto r_error;
48340cb5e5dSvi 			/*
48440cb5e5dSvi 			 * Add one for COMMA
48540cb5e5dSvi 			 */
48640cb5e5dSvi 			rset_cnt++;
48740cb5e5dSvi 			rset_len += (value->sip_value_end -
48840cb5e5dSvi 			    value->sip_value_start);
48940cb5e5dSvi 			/*
49040cb5e5dSvi 			 * Check for CRLF
49140cb5e5dSvi 			 */
49240cb5e5dSvi 			crlf = value->sip_value_end - strlen(SIP_CRLF);
49340cb5e5dSvi 			while (crlf != NULL &&
49440cb5e5dSvi 			    strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) {
49540cb5e5dSvi 				rset_len -= strlen(SIP_CRLF);
49640cb5e5dSvi 				crlf -= strlen(SIP_CRLF);
49740cb5e5dSvi 			}
49840cb5e5dSvi 			if (rset_head == NULL) {
49940cb5e5dSvi 				assert(rset_tail == NULL);
50040cb5e5dSvi 				rset_head = rset_tail = rset;
50140cb5e5dSvi 			} else if (what == SIP_UAS_DIALOG) {
50240cb5e5dSvi 				rset_tail->sip_dlg_route_next = rset;
50340cb5e5dSvi 				rset_tail = rset;
50440cb5e5dSvi 			} else if (what == SIP_UAC_DIALOG) {
50540cb5e5dSvi 				rset->sip_dlg_route_next = rset_head;
50640cb5e5dSvi 				rset_head = rset;
50740cb5e5dSvi 			} else {
50840cb5e5dSvi 				assert(0);
50940cb5e5dSvi 			}
51040cb5e5dSvi 			value = (sip_hdr_value_t *)sip_get_next_value(
51140cb5e5dSvi 			    (sip_header_value_t)value, &error);
51240cb5e5dSvi 		}
51340cb5e5dSvi 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
51440cb5e5dSvi 		rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, rrhdr);
51540cb5e5dSvi 	}
51640cb5e5dSvi 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
51740cb5e5dSvi 	if (rset_cnt == 0)
51840cb5e5dSvi 		return (0);
51940cb5e5dSvi 	if (sip_dialog_set_route_hdr(dialog, rset_head, rset_cnt,
52040cb5e5dSvi 	    rset_len) != 0) {
52140cb5e5dSvi 		goto r_error;
52240cb5e5dSvi 	}
52340cb5e5dSvi 	return (0);
52440cb5e5dSvi r_error:
52540cb5e5dSvi 	sip_dialog_free_rset(rset_head);
52640cb5e5dSvi 	return (ENOMEM);
52740cb5e5dSvi }
52840cb5e5dSvi 
52940cb5e5dSvi /*
53040cb5e5dSvi  * UAS behavior:
53140cb5e5dSvi  * The remote sequence number MUST be set to the value of the sequence
53240cb5e5dSvi  * number in the CSeq header field of the request.  The local sequence
53340cb5e5dSvi  * number MUST be empty.  The call identifier component of the dialog ID
53440cb5e5dSvi  * MUST be set to the value of the Call-ID in the request.  The local
53540cb5e5dSvi  * tag component of the dialog ID MUST be set to the tag in the To field
53640cb5e5dSvi  * in the response to the request (which always includes a tag), and the
53740cb5e5dSvi  * remote tag component of the dialog ID MUST be set to the tag from the
53840cb5e5dSvi  * From field in the request.  A UAS MUST be prepared to receive a
53940cb5e5dSvi  * request without a tag in the From field, in which case the tag is
54040cb5e5dSvi  * considered to have a value of null.
54140cb5e5dSvi  * The remote URI MUST be set to the URI in the From field, and the
54240cb5e5dSvi  * local URI MUST be set to the URI in the To field.
54340cb5e5dSvi  * The remote target MUST be set to the URI from the Contact header field
54440cb5e5dSvi  * of the request.
54540cb5e5dSvi  *
54640cb5e5dSvi  * UAC behavior:
54740cb5e5dSvi  * The local sequence number MUST be set to the value of the sequence
54840cb5e5dSvi  * number in the CSeq header field of the request.  The remote sequence
54940cb5e5dSvi  * number MUST be empty (it is established when the remote UA sends a
55040cb5e5dSvi  * request within the dialog).  The call identifier component of the
55140cb5e5dSvi  * dialog ID MUST be set to the value of the Call-ID in the request.
55240cb5e5dSvi  * The local tag component of the dialog ID MUST be set to the tag in
55340cb5e5dSvi  * the From field in the request, and the remote tag component of the
55440cb5e5dSvi  * dialog ID MUST be set to the tag in the To field of the response.  A
55540cb5e5dSvi  * UAC MUST be prepared to receive a response without a tag in the To
55640cb5e5dSvi  * field, in which case the tag is considered to have a value of null.
55740cb5e5dSvi  * The remote URI MUST be set to the URI in the To field, and the local
55840cb5e5dSvi  * URI MUST be set to the URI in the From field.
55940cb5e5dSvi  * The remote target MUST be set to the URI from the Contact header field
56040cb5e5dSvi  * of the response.
56140cb5e5dSvi  */
56240cb5e5dSvi 
56340cb5e5dSvi 
56440cb5e5dSvi /*
56540cb5e5dSvi  * This is the routine that seeds a dialog.
56640cb5e5dSvi  */
56740cb5e5dSvi sip_dialog_t
56840cb5e5dSvi sip_seed_dialog(sip_conn_object_t obj, _sip_msg_t *sip_msg,
56940cb5e5dSvi     boolean_t dlg_on_fork, int dlg_type)
57040cb5e5dSvi {
57140cb5e5dSvi 	_sip_dialog_t		*dialog;
57240cb5e5dSvi 	int			cseq;
57340cb5e5dSvi 	sip_header_t		fhdr = NULL;
57440cb5e5dSvi 	sip_header_t		thdr = NULL;
57540cb5e5dSvi 	sip_header_t		chdr;
57640cb5e5dSvi 	sip_header_t		cihdr;
57740cb5e5dSvi 	sip_header_t		evhdr = NULL;
57840cb5e5dSvi 	const struct sip_value	*value;
57940cb5e5dSvi 	sip_dialog_timer_obj_t	*tim_obj = NULL;
58040cb5e5dSvi 	const sip_str_t		*callid;
58140cb5e5dSvi 	sip_method_t		method;
58240cb5e5dSvi 	int			timer1 = sip_timer_T1;
58340cb5e5dSvi 	int			error;
58440cb5e5dSvi 
58540cb5e5dSvi 	if (!sip_msg_is_request((sip_msg_t)sip_msg, &error))
58640cb5e5dSvi 		return (NULL);
58740cb5e5dSvi 
58840cb5e5dSvi 	method = sip_get_request_method((sip_msg_t)sip_msg, &error);
58940cb5e5dSvi 	/*
59040cb5e5dSvi 	 * Only INVITE and SUBSCRIBE supported
59140cb5e5dSvi 	 */
59240cb5e5dSvi 	if (error != 0 || (method != INVITE && method != SUBSCRIBE))
59340cb5e5dSvi 		return (NULL);
59440cb5e5dSvi 
59540cb5e5dSvi 	/*
59640cb5e5dSvi 	 * A request outside of a dialog MUST NOT contain a To tag
59740cb5e5dSvi 	 */
59840cb5e5dSvi 	if (sip_get_to_tag((sip_msg_t)sip_msg, NULL) != NULL)
59940cb5e5dSvi 		return (NULL);
60040cb5e5dSvi 
60140cb5e5dSvi 	if (dlg_type == SIP_UAS_DIALOG) {
60240cb5e5dSvi 		thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg,
60340cb5e5dSvi 		    SIP_DLG_XCHG_FROM);
60440cb5e5dSvi 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
60540cb5e5dSvi 	} else {
60640cb5e5dSvi 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
60740cb5e5dSvi 		fhdr = sip_search_for_header(sip_msg, SIP_FROM, NULL);
60840cb5e5dSvi 	}
60940cb5e5dSvi 	cihdr = sip_search_for_header(sip_msg, SIP_CALL_ID, NULL);
61040cb5e5dSvi 	chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
61140cb5e5dSvi 	if (method == SUBSCRIBE)
61240cb5e5dSvi 		evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL);
61340cb5e5dSvi 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
61440cb5e5dSvi 	if ((fhdr == NULL && thdr == NULL) || cihdr == NULL || chdr == NULL ||
61540cb5e5dSvi 	    (method == SUBSCRIBE && evhdr == NULL)) {
61640cb5e5dSvi 		if (thdr != NULL)
61740cb5e5dSvi 			sip_free_header(thdr);
61840cb5e5dSvi 		return (NULL);
61940cb5e5dSvi 	}
62040cb5e5dSvi 
62140cb5e5dSvi 	/*
62240cb5e5dSvi 	 * Sanity check since we just store the headers in the dialog
62340cb5e5dSvi 	 */
62440cb5e5dSvi 	if (sip_get_from_tag((sip_msg_t)sip_msg, NULL) == NULL ||
62540cb5e5dSvi 	    sip_get_from_uri_str((sip_msg_t)sip_msg, NULL) == NULL ||
62640cb5e5dSvi 	    ((cseq = sip_get_callseq_num((sip_msg_t)sip_msg, NULL)) == -1) ||
62740cb5e5dSvi 	    (callid = sip_get_callid((sip_msg_t)sip_msg, NULL)) == NULL ||
62840cb5e5dSvi 	    sip_get_to_uri_str((sip_msg_t)sip_msg, NULL) == NULL ||
62940cb5e5dSvi 	    ((value = sip_get_header_value(chdr, NULL)) == NULL) ||
63040cb5e5dSvi 	    sip_get_contact_uri_str((sip_header_value_t)value, NULL) == NULL) {
63140cb5e5dSvi 		if (thdr != NULL)
63240cb5e5dSvi 			sip_free_header(thdr);
63340cb5e5dSvi 		return (NULL);
63440cb5e5dSvi 	}
63540cb5e5dSvi 
63640cb5e5dSvi 	tim_obj = calloc(1, sizeof (sip_dialog_timer_obj_t));
63740cb5e5dSvi 	if (tim_obj == NULL) {
63840cb5e5dSvi 		if (thdr != NULL)
63940cb5e5dSvi 			sip_free_header(thdr);
64040cb5e5dSvi 		return (NULL);
64140cb5e5dSvi 	}
64240cb5e5dSvi 	dialog = calloc(1, sizeof (_sip_dialog_t));
64340cb5e5dSvi 	if (dialog == NULL) {
64440cb5e5dSvi 		if (thdr != NULL)
64540cb5e5dSvi 			sip_free_header(thdr);
64640cb5e5dSvi 		return (NULL);
64740cb5e5dSvi 	}
64840cb5e5dSvi 	/*
64940cb5e5dSvi 	 * We will take the TO header with the tag when we complete this
65040cb5e5dSvi 	 * dialog
65140cb5e5dSvi 	 */
65240cb5e5dSvi 	if (dlg_type == SIP_UAS_DIALOG) {
65340cb5e5dSvi 		dialog->sip_dlg_remote_uri_tag = thdr;
65440cb5e5dSvi 		/*
65540cb5e5dSvi 		 * We take the remote target from the incoming request on the
65640cb5e5dSvi 		 * UAS. For the UAC, we will take it from the response.
65740cb5e5dSvi 		 */
65840cb5e5dSvi 		if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) ==
65940cb5e5dSvi 		    NULL) {
66040cb5e5dSvi 			goto dia_err;
66140cb5e5dSvi 		}
66240cb5e5dSvi 	} else {
66340cb5e5dSvi 		if ((dialog->sip_dlg_local_uri_tag = sip_dup_header(fhdr)) ==
66440cb5e5dSvi 		    NULL) {
66540cb5e5dSvi 			goto dia_err;
66640cb5e5dSvi 		}
667*d8a40387Sgm 		/*
668*d8a40387Sgm 		 * We take the local contact from the originating request on
669*d8a40387Sgm 		 * UAC. For the UAS, we will take it from the response.
670*d8a40387Sgm 		 */
671*d8a40387Sgm 		if ((dialog->sip_dlg_local_contact = sip_dup_header(chdr)) ==
672*d8a40387Sgm 		    NULL) {
673*d8a40387Sgm 			goto dia_err;
674*d8a40387Sgm 		} else {
675*d8a40387Sgm 			dialog->sip_dlg_new_local_contact = NULL;
676*d8a40387Sgm 		}
67740cb5e5dSvi 	}
67840cb5e5dSvi 	if ((dialog->sip_dlg_call_id = sip_dup_header(cihdr)) == NULL)
67940cb5e5dSvi 		goto dia_err;
68040cb5e5dSvi 	if (method == SUBSCRIBE) {
68140cb5e5dSvi 		dialog->sip_dlg_event = sip_dup_header(evhdr);
68240cb5e5dSvi 		if (dialog->sip_dlg_event == NULL) {
68340cb5e5dSvi 			goto dia_err;
68440cb5e5dSvi 		}
68540cb5e5dSvi 	}
68640cb5e5dSvi 	dialog->sip_dlg_rset.sip_str_ptr = NULL;
68740cb5e5dSvi 	dialog->sip_dlg_rset.sip_str_len = 0;
68840cb5e5dSvi 	dialog->sip_dlg_req_uri.sip_str_ptr = NULL;
68940cb5e5dSvi 	dialog->sip_dlg_req_uri.sip_str_len = 0;
69040cb5e5dSvi 	/*
69140cb5e5dSvi 	 * Get the route set from the request, if present
69240cb5e5dSvi 	 */
69340cb5e5dSvi 	if (dlg_type == SIP_UAS_DIALOG &&
69440cb5e5dSvi 	    sip_dialog_get_route_set(dialog, sip_msg, dlg_type) != 0) {
69540cb5e5dSvi 		goto dia_err;
69640cb5e5dSvi 	}
69740cb5e5dSvi 	if (dlg_type == SIP_UAC_DIALOG)
69840cb5e5dSvi 		dialog->sip_dlg_local_cseq = cseq;
69940cb5e5dSvi 	else
70040cb5e5dSvi 		dialog->sip_dlg_remote_cseq = cseq;
70140cb5e5dSvi 	dialog->sip_dlg_type = dlg_type;
70240cb5e5dSvi 	dialog->sip_dlg_on_fork = dlg_on_fork;
70340cb5e5dSvi 	dialog->sip_dlg_method = method;
70440cb5e5dSvi 	/*
70540cb5e5dSvi 	 * Set the partial dialog timer with the INVITE timeout val
70640cb5e5dSvi 	 */
70740cb5e5dSvi 	if (sip_conn_timer1 != NULL)
70840cb5e5dSvi 		timer1 = sip_conn_timer1(obj);
70940cb5e5dSvi 	SIP_INIT_TIMER(dialog->sip_dlg_timer, 64 * timer1);
71040cb5e5dSvi 	tim_obj->dialog = dialog;
71140cb5e5dSvi 	/*
71240cb5e5dSvi 	 * Since at the client we never pass the partial dialog, we need not
71340cb5e5dSvi 	 * invoke the callback when the partial dialog self-destructs.
71440cb5e5dSvi 	 */
71540cb5e5dSvi 	if (dlg_type == SIP_UAS_DIALOG)
71640cb5e5dSvi 		tim_obj->func = sip_ulp_dlg_del_cb;
71740cb5e5dSvi 	SIP_SCHED_TIMER(dialog->sip_dlg_timer, (void *)tim_obj,
71840cb5e5dSvi 	    sip_dlg_self_destruct);
71940cb5e5dSvi 	if (!SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
72040cb5e5dSvi 		goto dia_err;
72140cb5e5dSvi 	(void) pthread_mutex_init(&dialog->sip_dlg_mutex, NULL);
72240cb5e5dSvi 
72340cb5e5dSvi 	if (dlg_type == SIP_UAC_DIALOG) {
72440cb5e5dSvi 		const sip_str_t	*local_tag;
72540cb5e5dSvi 
72640cb5e5dSvi 		local_tag = sip_get_from_tag((sip_msg_t)sip_msg, NULL);
72740cb5e5dSvi 		assert(local_tag != NULL);
72840cb5e5dSvi 		sip_md5_hash(local_tag->sip_str_ptr, local_tag->sip_str_len,
72940cb5e5dSvi 		    callid->sip_str_ptr, callid->sip_str_len,
73040cb5e5dSvi 		    NULL, 0, NULL, 0, NULL, 0, NULL, 0,
73140cb5e5dSvi 		    (uchar_t *)dialog->sip_dlg_id);
73240cb5e5dSvi 
73340cb5e5dSvi 
73440cb5e5dSvi 		/*
73540cb5e5dSvi 		 * Add it to the partial hash table
73640cb5e5dSvi 		 */
73740cb5e5dSvi 		if (sip_hash_add(sip_dialog_phash, (void *)dialog,
73840cb5e5dSvi 		    SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) {
73940cb5e5dSvi 			goto dia_err;
74040cb5e5dSvi 		}
74140cb5e5dSvi 	}
74240cb5e5dSvi 	SIP_DLG_REFCNT_INCR(dialog);
74340cb5e5dSvi 	return ((sip_dialog_t)dialog);
74440cb5e5dSvi dia_err:
74540cb5e5dSvi 	sip_release_dialog_res(dialog);
74640cb5e5dSvi 	if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
74740cb5e5dSvi 		SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
74840cb5e5dSvi 	if (tim_obj != NULL)
74940cb5e5dSvi 		free(tim_obj);
75040cb5e5dSvi 	return (NULL);
75140cb5e5dSvi }
75240cb5e5dSvi 
75340cb5e5dSvi /*
75440cb5e5dSvi  * When creating a dialog from a NOTIFY request, we need to get the FROM
75540cb5e5dSvi  * header for the dialog from the TO header of the NOTIFY.
75640cb5e5dSvi  */
75740cb5e5dSvi _sip_header_t *
75840cb5e5dSvi sip_dlg_xchg_from_to(sip_msg_t sip_msg, int what)
75940cb5e5dSvi {
76040cb5e5dSvi 	int			len;
76140cb5e5dSvi 	_sip_header_t		*newhdr;
76240cb5e5dSvi 	int			cnt;
76340cb5e5dSvi 	const struct sip_header	*hdr;
76440cb5e5dSvi 	int			hdrsize;
76540cb5e5dSvi 	int			error;
76640cb5e5dSvi 
76740cb5e5dSvi 	hdr = sip_get_header(sip_msg, what == SIP_DLG_XCHG_FROM ? SIP_FROM :
76840cb5e5dSvi 	    SIP_TO, NULL, &error);
76940cb5e5dSvi 	if (error != 0 || hdr == NULL)
77040cb5e5dSvi 		return (NULL);
77140cb5e5dSvi 	if (sip_parse_goto_values((_sip_header_t *)hdr) != 0)
77240cb5e5dSvi 		return (NULL);
77340cb5e5dSvi 	len = hdr->sip_hdr_end - hdr->sip_hdr_current;
77440cb5e5dSvi 	if (what == SIP_DLG_XCHG_FROM) {
77540cb5e5dSvi 		hdrsize = len + strlen(SIP_TO) + SIP_SPACE_LEN + sizeof (char) +
77640cb5e5dSvi 		    SIP_SPACE_LEN;
77740cb5e5dSvi 	} else {
77840cb5e5dSvi 		hdrsize = len + strlen(SIP_FROM) + SIP_SPACE_LEN +
77940cb5e5dSvi 		    sizeof (char) + SIP_SPACE_LEN;
78040cb5e5dSvi 	}
78140cb5e5dSvi 	newhdr = sip_new_header(hdrsize);
78240cb5e5dSvi 	if (newhdr == NULL)
78340cb5e5dSvi 		return (NULL);
78440cb5e5dSvi 	if (what == SIP_DLG_XCHG_FROM) {
78540cb5e5dSvi 		cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1,
78640cb5e5dSvi 		    "%s %c ", SIP_TO, SIP_HCOLON);
78740cb5e5dSvi 	} else {
78840cb5e5dSvi 		cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1,
78940cb5e5dSvi 		    "%s %c ", SIP_FROM, SIP_HCOLON);
79040cb5e5dSvi 	}
79140cb5e5dSvi 	newhdr->sip_hdr_current += cnt;
79240cb5e5dSvi 	(void) strncpy(newhdr->sip_hdr_current, hdr->sip_hdr_current, len);
79340cb5e5dSvi 	newhdr->sip_hdr_current += len;
79440cb5e5dSvi 	assert(newhdr->sip_hdr_current == newhdr->sip_hdr_end);
79540cb5e5dSvi 	assert(hdr->sip_header_functions != NULL);
79640cb5e5dSvi 
79740cb5e5dSvi 	/*
79840cb5e5dSvi 	 * FROM and TO have common parsing functions
79940cb5e5dSvi 	 */
80040cb5e5dSvi 	newhdr->sip_header_functions = hdr->sip_header_functions;
80140cb5e5dSvi 	newhdr->sip_hdr_current = newhdr->sip_hdr_start;
80240cb5e5dSvi 
80340cb5e5dSvi 	return (newhdr);
80440cb5e5dSvi }
80540cb5e5dSvi 
80640cb5e5dSvi /*
80740cb5e5dSvi  * This is the response that completes the dialog that was created
80840cb5e5dSvi  * in sip_seed_dialog().
80940cb5e5dSvi  */
81040cb5e5dSvi sip_dialog_t
81140cb5e5dSvi sip_complete_dialog(_sip_msg_t *sip_msg, _sip_dialog_t *dialog)
81240cb5e5dSvi {
81340cb5e5dSvi 	_sip_header_t		*thdr;
81440cb5e5dSvi 	_sip_header_t		*evhdr = NULL;
81540cb5e5dSvi 	_sip_header_t		*substate = NULL;
81640cb5e5dSvi 	sip_header_t		chdr = NULL;
81740cb5e5dSvi 	int			resp_code;
81840cb5e5dSvi 	const sip_str_t		*ttag;
81940cb5e5dSvi 	const sip_str_t		*remtag;
82040cb5e5dSvi 	const sip_str_t		*callid;
82140cb5e5dSvi 	const struct sip_value 	*val;
82240cb5e5dSvi 	sip_method_t		method;
82340cb5e5dSvi 	int			error = 0;
82440cb5e5dSvi 	int			prev_state;
82540cb5e5dSvi 	boolean_t		alloc_thdr = B_FALSE;
82640cb5e5dSvi 
82740cb5e5dSvi 	if (sip_msg_is_request((sip_msg_t)sip_msg, &error) && error == 0)
82840cb5e5dSvi 		method = sip_get_request_method((sip_msg_t)sip_msg, &error);
82940cb5e5dSvi 	else
83040cb5e5dSvi 		method = sip_get_callseq_method((sip_msg_t)sip_msg, &error);
83140cb5e5dSvi 	if (error != 0 || dialog == NULL ||
83240cb5e5dSvi 	    (sip_msg_is_request((sip_msg_t)sip_msg, &error) &&
83340cb5e5dSvi 	    (dialog->sip_dlg_method == INVITE || method != NOTIFY))) {
83440cb5e5dSvi 		return (NULL);
83540cb5e5dSvi 	}
83640cb5e5dSvi 	if ((dialog->sip_dlg_type == SIP_UAC_DIALOG && method != NOTIFY &&
83740cb5e5dSvi 	    sip_get_callseq_num((sip_msg_t)sip_msg, NULL) !=
83840cb5e5dSvi 	    dialog->sip_dlg_local_cseq) ||
83940cb5e5dSvi 	    (dialog->sip_dlg_type == SIP_UAS_DIALOG && method != NOTIFY &&
84040cb5e5dSvi 	    sip_get_callseq_num((sip_msg_t)sip_msg, NULL) !=
84140cb5e5dSvi 	    dialog->sip_dlg_remote_cseq)) {
84240cb5e5dSvi 		return (NULL);
84340cb5e5dSvi 	}
84440cb5e5dSvi 	if (method == NOTIFY) {
84540cb5e5dSvi 		const sip_str_t	*sstate;
84640cb5e5dSvi 
84740cb5e5dSvi 		thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg,
84840cb5e5dSvi 		    SIP_DLG_XCHG_FROM);
84940cb5e5dSvi 		if (thdr == NULL)
85040cb5e5dSvi 			return (NULL);
85140cb5e5dSvi 		alloc_thdr = B_TRUE;
85240cb5e5dSvi 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
85340cb5e5dSvi 		chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
85440cb5e5dSvi 		if (chdr == NULL) {
85540cb5e5dSvi 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
85640cb5e5dSvi 			sip_free_header(thdr);
85740cb5e5dSvi 			return (NULL);
85840cb5e5dSvi 		}
85940cb5e5dSvi 		evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL);
86040cb5e5dSvi 		if (evhdr == NULL) {
86140cb5e5dSvi 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
86240cb5e5dSvi 			sip_free_header(thdr);
86340cb5e5dSvi 			return (NULL);
86440cb5e5dSvi 		}
86540cb5e5dSvi 		substate = sip_search_for_header(sip_msg,
86640cb5e5dSvi 		    SIP_SUBSCRIPTION_STATE, NULL);
86740cb5e5dSvi 		if (substate == NULL) {
86840cb5e5dSvi 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
86940cb5e5dSvi 			sip_free_header(thdr);
87040cb5e5dSvi 			return (NULL);
87140cb5e5dSvi 		}
87240cb5e5dSvi 		(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
87340cb5e5dSvi 		sstate = sip_get_substate((sip_msg_t)sip_msg, &error);
87440cb5e5dSvi 		if (sstate == NULL || error != 0) {
87540cb5e5dSvi 			sip_free_header(thdr);
87640cb5e5dSvi 			return (NULL);
87740cb5e5dSvi 		}
87840cb5e5dSvi 		if ((sstate->sip_str_len != strlen("pending") &&
87940cb5e5dSvi 		    sstate->sip_str_len != strlen("active")) ||
88040cb5e5dSvi 		    ((sstate->sip_str_len == strlen("pending") &&
88140cb5e5dSvi 		    strncasecmp(sstate->sip_str_ptr, "pending",
88240cb5e5dSvi 		    strlen("pending")) != 0) ||
88340cb5e5dSvi 		    (sstate->sip_str_len == strlen("active") &&
88440cb5e5dSvi 		    strncasecmp(sstate->sip_str_ptr, "active",
88540cb5e5dSvi 		    strlen("active")) != 0))) {
88640cb5e5dSvi 			sip_free_header(thdr);
88740cb5e5dSvi 			return (NULL);
88840cb5e5dSvi 		}
88940cb5e5dSvi 		ttag = sip_get_from_tag((sip_msg_t)sip_msg, NULL);
89040cb5e5dSvi 	} else {
89140cb5e5dSvi 		if (dialog->sip_dlg_type == SIP_UAS_DIALOG) {
89240cb5e5dSvi 			thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg,
89340cb5e5dSvi 			    SIP_DLG_XCHG_TO);
89440cb5e5dSvi 			alloc_thdr = B_TRUE;
89540cb5e5dSvi 		} else {
89640cb5e5dSvi 			(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
89740cb5e5dSvi 			thdr = sip_search_for_header(sip_msg, SIP_TO, NULL);
89840cb5e5dSvi 			if (dialog->sip_dlg_remote_target == NULL) {
89940cb5e5dSvi 				chdr = sip_search_for_header(sip_msg,
90040cb5e5dSvi 				    SIP_CONTACT, NULL);
90140cb5e5dSvi 			}
90240cb5e5dSvi 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
90340cb5e5dSvi 		}
90440cb5e5dSvi 		if (thdr == NULL) {
90540cb5e5dSvi 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
90640cb5e5dSvi 			return (NULL);
90740cb5e5dSvi 		}
90840cb5e5dSvi 		ttag = sip_get_to_tag((sip_msg_t)sip_msg, NULL);
90940cb5e5dSvi 	}
91040cb5e5dSvi 	if (ttag == NULL) {
91140cb5e5dSvi 		if (alloc_thdr)
91240cb5e5dSvi 			sip_free_header(thdr);
91340cb5e5dSvi 		return (NULL);
91440cb5e5dSvi 	}
91540cb5e5dSvi 	prev_state = dialog->sip_dlg_state;
91640cb5e5dSvi 
91740cb5e5dSvi 	if (method == NOTIFY) {
91840cb5e5dSvi 		int			error;
91940cb5e5dSvi 		const sip_str_t		*dlg_id_val = NULL;
92040cb5e5dSvi 		const sip_str_t		*event;
92140cb5e5dSvi 		const sip_str_t		*id_val = NULL;
92240cb5e5dSvi 		sip_header_value_t	ev_val;
92340cb5e5dSvi 		sip_hdr_value_t		*dlg_ev_val = NULL;
92440cb5e5dSvi 
92540cb5e5dSvi 		event = sip_get_event((sip_msg_t)sip_msg, &error);
92640cb5e5dSvi 		if (event == NULL || error != 0) {
92740cb5e5dSvi 			sip_free_header(thdr);
92840cb5e5dSvi 			return (NULL);
92940cb5e5dSvi 		}
93040cb5e5dSvi 		ev_val = (sip_header_value_t)sip_get_header_value(evhdr,
93140cb5e5dSvi 		    &error);
93240cb5e5dSvi 		if (ev_val != NULL)
93340cb5e5dSvi 			id_val = sip_get_param_value(ev_val, "id", &error);
93440cb5e5dSvi 		if (error == 0) {
93540cb5e5dSvi 			dlg_ev_val = (sip_hdr_value_t *)sip_get_header_value(
93640cb5e5dSvi 			    dialog->sip_dlg_event, &error);
93740cb5e5dSvi 		}
93840cb5e5dSvi 		if (dlg_ev_val == NULL || error != 0) {
93940cb5e5dSvi 			sip_free_header(thdr);
94040cb5e5dSvi 			return (NULL);
94140cb5e5dSvi 		}
94240cb5e5dSvi 		dlg_id_val = sip_get_param_value((sip_header_value_t)dlg_ev_val,
94340cb5e5dSvi 		    "id", &error);
94440cb5e5dSvi 		if (error != 0 ||
94540cb5e5dSvi 		    dlg_ev_val->str_val_len != event->sip_str_len ||
94640cb5e5dSvi 		    strncmp(dlg_ev_val->str_val_ptr, event->sip_str_ptr,
94740cb5e5dSvi 		    event->sip_str_len != 0)) {
94840cb5e5dSvi 			sip_free_header(thdr);
94940cb5e5dSvi 			return (NULL);
95040cb5e5dSvi 		}
95140cb5e5dSvi 		if ((dlg_id_val == NULL && id_val != NULL) ||
95240cb5e5dSvi 		    (dlg_id_val != NULL && id_val == NULL)) {
95340cb5e5dSvi 			sip_free_header(thdr);
95440cb5e5dSvi 			return (NULL);
95540cb5e5dSvi 		} else if (dlg_id_val != NULL && id_val != NULL) {
95640cb5e5dSvi 			if (dlg_id_val->sip_str_len != id_val->sip_str_len ||
95740cb5e5dSvi 			    strncasecmp(dlg_id_val->sip_str_ptr,
95840cb5e5dSvi 			    id_val->sip_str_ptr, dlg_id_val->sip_str_len) !=
95940cb5e5dSvi 			    0) {
96040cb5e5dSvi 				sip_free_header(thdr);
96140cb5e5dSvi 				return (NULL);
96240cb5e5dSvi 			}
96340cb5e5dSvi 		}
96440cb5e5dSvi 		if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
96540cb5e5dSvi 			dialog->sip_dlg_remote_uri_tag = thdr;
96640cb5e5dSvi 			if ((dialog->sip_dlg_remote_target =
96740cb5e5dSvi 			    sip_dup_header(chdr)) == NULL) {
96840cb5e5dSvi 				sip_free_header(thdr);
96940cb5e5dSvi 				return (NULL);
97040cb5e5dSvi 			}
97140cb5e5dSvi 		} else {
97240cb5e5dSvi 			dialog->sip_dlg_local_uri_tag = thdr;
97340cb5e5dSvi 		}
97440cb5e5dSvi 		dialog->sip_dlg_state = SIP_DLG_CONFIRMED;
97540cb5e5dSvi 	} else {
97640cb5e5dSvi 		resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
97740cb5e5dSvi 		(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
97840cb5e5dSvi 		assert(dialog->sip_dlg_state == SIP_DLG_NEW);
97940cb5e5dSvi 		if (dialog->sip_dlg_remote_target == NULL && chdr != NULL) {
98040cb5e5dSvi 			assert(dialog->sip_dlg_type == SIP_UAC_DIALOG);
98140cb5e5dSvi 			if ((dialog->sip_dlg_remote_target =
98240cb5e5dSvi 			    sip_dup_header(chdr)) == NULL) {
98340cb5e5dSvi 				(void) pthread_mutex_unlock(
98440cb5e5dSvi 				    &dialog->sip_dlg_mutex);
98540cb5e5dSvi 				if (alloc_thdr)
98640cb5e5dSvi 					sip_free_header(thdr);
9872c2c4183Svi 				goto terminate_new_dlg;
98840cb5e5dSvi 			}
98940cb5e5dSvi 			if (sip_dialog_get_route_set(dialog, sip_msg,
99040cb5e5dSvi 			    dialog->sip_dlg_type) != 0) {
99140cb5e5dSvi 				(void) pthread_mutex_unlock(
99240cb5e5dSvi 				    &dialog->sip_dlg_mutex);
99340cb5e5dSvi 				if (alloc_thdr)
99440cb5e5dSvi 					sip_free_header(thdr);
9952c2c4183Svi 				goto terminate_new_dlg;
99640cb5e5dSvi 			}
99740cb5e5dSvi 		}
99840cb5e5dSvi 		if (SIP_PROVISIONAL_RESP(resp_code)) {
99940cb5e5dSvi 			dialog->sip_dlg_state = SIP_DLG_EARLY;
100040cb5e5dSvi 		} else if (SIP_OK_RESP(resp_code)) {
100140cb5e5dSvi 			/*
100240cb5e5dSvi 			 * Per 12.1 the UAS must include the contact header
100340cb5e5dSvi 			 * for a dialog establishing response, so if we
100440cb5e5dSvi 			 * don't find one, we terminate it.
100540cb5e5dSvi 			 */
100640cb5e5dSvi 			if (dialog->sip_dlg_remote_target == NULL) {
100740cb5e5dSvi 				(void) pthread_mutex_unlock(
100840cb5e5dSvi 				    &dialog->sip_dlg_mutex);
100940cb5e5dSvi 				if (sip_ulp_dlg_del_cb != NULL) {
101040cb5e5dSvi 					sip_ulp_dlg_del_cb(dialog,
101140cb5e5dSvi 					    (sip_msg_t)sip_msg, NULL);
101240cb5e5dSvi 				}
101340cb5e5dSvi 				if (alloc_thdr)
101440cb5e5dSvi 					sip_free_header(thdr);
10152c2c4183Svi 				goto terminate_new_dlg;
101640cb5e5dSvi 			}
101740cb5e5dSvi 			dialog->sip_dlg_state = SIP_DLG_CONFIRMED;
101840cb5e5dSvi 		} else {
101940cb5e5dSvi 			(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
102040cb5e5dSvi 			if (sip_ulp_dlg_del_cb != NULL) {
102140cb5e5dSvi 				sip_ulp_dlg_del_cb(dialog, (sip_msg_t)sip_msg,
102240cb5e5dSvi 				    NULL);
102340cb5e5dSvi 			}
102440cb5e5dSvi 			if (alloc_thdr)
102540cb5e5dSvi 				sip_free_header(thdr);
10262c2c4183Svi 			goto terminate_new_dlg;
102740cb5e5dSvi 		}
102840cb5e5dSvi 		if (dialog->sip_dlg_type == SIP_UAS_DIALOG) {
102940cb5e5dSvi 			dialog->sip_dlg_local_uri_tag = thdr;
103040cb5e5dSvi 		} else {
103140cb5e5dSvi 			if ((dialog->sip_dlg_remote_uri_tag =
103240cb5e5dSvi 			    sip_dup_header(thdr)) == NULL) {
103340cb5e5dSvi 				(void) pthread_mutex_unlock(
103440cb5e5dSvi 				    &dialog->sip_dlg_mutex);
10352c2c4183Svi 				goto terminate_new_dlg;
103640cb5e5dSvi 			}
103740cb5e5dSvi 		}
103840cb5e5dSvi 	}
103940cb5e5dSvi 
1040*d8a40387Sgm 	/*
1041*d8a40387Sgm 	 * We take the local contact for UAS Dialog from the response (either
1042*d8a40387Sgm 	 * NOTIFY for SUBSCRIBE request or from final response 2xx to INVITE
1043*d8a40387Sgm 	 * request)
1044*d8a40387Sgm 	 */
1045*d8a40387Sgm 	if ((dialog->sip_dlg_type == SIP_UAS_DIALOG) && (dialog->sip_dlg_state
1046*d8a40387Sgm 	    == SIP_DLG_CONFIRMED)) {
1047*d8a40387Sgm 		if (chdr == NULL) {
1048*d8a40387Sgm 			(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
1049*d8a40387Sgm 			chdr = sip_search_for_header(sip_msg, SIP_CONTACT,
1050*d8a40387Sgm 			    NULL);
1051*d8a40387Sgm 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
1052*d8a40387Sgm 		}
1053*d8a40387Sgm 		if ((chdr == NULL) || ((dialog->sip_dlg_local_contact =
1054*d8a40387Sgm 		    sip_dup_header(chdr)) == NULL)) {
1055*d8a40387Sgm 			(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1056*d8a40387Sgm 			if (alloc_thdr)
1057*d8a40387Sgm 				sip_free_header(thdr);
1058*d8a40387Sgm 			goto terminate_new_dlg;
1059*d8a40387Sgm 		}
1060*d8a40387Sgm 	}
1061*d8a40387Sgm 
106240cb5e5dSvi 	/*
106340cb5e5dSvi 	 * Cancel the partial dialog timer
106440cb5e5dSvi 	 */
106540cb5e5dSvi 	if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
106640cb5e5dSvi 		SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
106740cb5e5dSvi 
106840cb5e5dSvi 	if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
106940cb5e5dSvi 		val =  sip_get_header_value(dialog->sip_dlg_local_uri_tag,
107040cb5e5dSvi 		    &error);
107140cb5e5dSvi 	} else {
107240cb5e5dSvi 		val =  sip_get_header_value(dialog->sip_dlg_remote_uri_tag,
107340cb5e5dSvi 		    &error);
107440cb5e5dSvi 	}
107540cb5e5dSvi 	assert(val != NULL && error == 0);
107640cb5e5dSvi 	remtag = sip_get_param_value((sip_header_value_t)val, "tag", &error);
107740cb5e5dSvi 
107840cb5e5dSvi 	val = sip_get_header_value(dialog->sip_dlg_call_id, &error);
107940cb5e5dSvi 	callid = &((sip_hdr_value_t *)val)->str_val;
108040cb5e5dSvi 
108140cb5e5dSvi 	/*
108240cb5e5dSvi 	 * Get an ID for this dialog
108340cb5e5dSvi 	 */
108440cb5e5dSvi 	if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
108540cb5e5dSvi 		sip_md5_hash(remtag->sip_str_ptr, remtag->sip_str_len,
108640cb5e5dSvi 		    ttag->sip_str_ptr, ttag->sip_str_len,
108740cb5e5dSvi 		    callid->sip_str_ptr, callid->sip_str_len,
108840cb5e5dSvi 		    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id);
108940cb5e5dSvi 	} else {
109040cb5e5dSvi 		sip_md5_hash(ttag->sip_str_ptr, ttag->sip_str_len,
109140cb5e5dSvi 		    remtag->sip_str_ptr, remtag->sip_str_len,
109240cb5e5dSvi 		    callid->sip_str_ptr, callid->sip_str_len,
109340cb5e5dSvi 		    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id);
109440cb5e5dSvi 	}
109540cb5e5dSvi 
109640cb5e5dSvi 	SIP_DLG_REFCNT_INCR(dialog);
109740cb5e5dSvi 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
109840cb5e5dSvi 
109940cb5e5dSvi 	/*
110040cb5e5dSvi 	 * Add it to the hash table
110140cb5e5dSvi 	 */
110240cb5e5dSvi 	if (sip_hash_add(sip_dialog_hash, (void *)dialog,
110340cb5e5dSvi 	    SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) {
11042c2c4183Svi 	terminate_new_dlg:
110540cb5e5dSvi 		/*
110640cb5e5dSvi 		 * So that sip_dialog_delete() does not try to remove
110740cb5e5dSvi 		 * this from the hash table.
110840cb5e5dSvi 		 */
110940cb5e5dSvi 		(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
111040cb5e5dSvi 		if (dialog->sip_dlg_type == SIP_UAS_DIALOG) {
11112c2c4183Svi 			if (dialog->sip_dlg_local_uri_tag != NULL) {
11122c2c4183Svi 				sip_free_header(dialog->sip_dlg_local_uri_tag);
11132c2c4183Svi 				dialog->sip_dlg_local_uri_tag = NULL;
11142c2c4183Svi 			}
111540cb5e5dSvi 		} else {
11162c2c4183Svi 			if (dialog->sip_dlg_remote_uri_tag != NULL) {
11172c2c4183Svi 				sip_free_header(dialog->sip_dlg_remote_uri_tag);
11182c2c4183Svi 				dialog->sip_dlg_remote_uri_tag = NULL;
11192c2c4183Svi 			}
112040cb5e5dSvi 		}
112140cb5e5dSvi 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
112240cb5e5dSvi 		sip_dialog_terminate(dialog, (sip_msg_t)sip_msg);
112340cb5e5dSvi 		return (NULL);
112440cb5e5dSvi 	}
112540cb5e5dSvi 	if (sip_dlg_ulp_state_cb != NULL) {
112640cb5e5dSvi 		sip_dlg_ulp_state_cb((sip_dialog_t)dialog,
112740cb5e5dSvi 		    (sip_msg_t)sip_msg, prev_state, dialog->sip_dlg_state);
112840cb5e5dSvi 	}
112940cb5e5dSvi 	return ((sip_dialog_t)dialog);
113040cb5e5dSvi }
113140cb5e5dSvi 
113240cb5e5dSvi /*
113340cb5e5dSvi  * Check if this dialog is a match.
113440cb5e5dSvi  */
113540cb5e5dSvi boolean_t
113640cb5e5dSvi sip_dialog_match(void *obj, void *hindex)
113740cb5e5dSvi {
113840cb5e5dSvi 	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
113940cb5e5dSvi 
114040cb5e5dSvi 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
114140cb5e5dSvi 	if (dialog->sip_dlg_state == SIP_DLG_DESTROYED) {
114240cb5e5dSvi 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
114340cb5e5dSvi 		return (B_FALSE);
114440cb5e5dSvi 	}
114540cb5e5dSvi 	if (bcmp(dialog->sip_dlg_id, hindex,
114640cb5e5dSvi 	    sizeof (dialog->sip_dlg_id)) == 0) {
114740cb5e5dSvi 		SIP_DLG_REFCNT_INCR(dialog);
114840cb5e5dSvi 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
114940cb5e5dSvi 		return (B_TRUE);
115040cb5e5dSvi 	}
115140cb5e5dSvi 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
115240cb5e5dSvi 	return (B_FALSE);
115340cb5e5dSvi }
115440cb5e5dSvi 
115540cb5e5dSvi /*
115640cb5e5dSvi  * Don't delete, just take it out of the hash
115740cb5e5dSvi  */
115840cb5e5dSvi boolean_t
115940cb5e5dSvi sip_dialog_dontfree(void *obj, void *hindex, int *found)
116040cb5e5dSvi {
116140cb5e5dSvi 	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
116240cb5e5dSvi 
116340cb5e5dSvi 	*found = 0;
116440cb5e5dSvi 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
116540cb5e5dSvi 	if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id))
116640cb5e5dSvi 	    == 0) {
116740cb5e5dSvi 		*found = 1;
116840cb5e5dSvi 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
116940cb5e5dSvi 		return (B_TRUE);
117040cb5e5dSvi 	}
117140cb5e5dSvi 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
117240cb5e5dSvi 	return (B_FALSE);
117340cb5e5dSvi }
117440cb5e5dSvi 
117540cb5e5dSvi /*
117640cb5e5dSvi  * Free resources associated with the dialog, the object will be removed
117740cb5e5dSvi  * from the hash list by sip_hash_delete.
117840cb5e5dSvi  */
117940cb5e5dSvi boolean_t
118040cb5e5dSvi sip_dialog_free(void *obj, void *hindex, int *found)
118140cb5e5dSvi {
118240cb5e5dSvi 	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
118340cb5e5dSvi 
118440cb5e5dSvi 	*found = 0;
118540cb5e5dSvi 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
118640cb5e5dSvi 	if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id))
118740cb5e5dSvi 	    == 0) {
118840cb5e5dSvi 		*found = 1;
118940cb5e5dSvi 		assert(dialog->sip_dlg_state == SIP_DLG_DESTROYED);
119040cb5e5dSvi 		if (dialog->sip_dlg_ref_cnt != 0) {
119140cb5e5dSvi 			(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
119240cb5e5dSvi 			return (B_FALSE);
119340cb5e5dSvi 		}
119440cb5e5dSvi 		sip_release_dialog_res(dialog);
119540cb5e5dSvi 		return (B_TRUE);
119640cb5e5dSvi 	}
119740cb5e5dSvi 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
119840cb5e5dSvi 	return (B_FALSE);
119940cb5e5dSvi }
120040cb5e5dSvi 
120140cb5e5dSvi /*
120240cb5e5dSvi  * The UAS will receive the request from the transaction layer.  If the
120340cb5e5dSvi  * request has a tag in the To header field, the UAS core computes the
120440cb5e5dSvi  * dialog identifier corresponding to the request and compares it with
120540cb5e5dSvi  * existing dialogs.  If there is a match, this is a mid-dialog request.
120640cb5e5dSvi  */
120740cb5e5dSvi sip_dialog_t
120840cb5e5dSvi sip_dialog_find(_sip_msg_t *sip_msg)
120940cb5e5dSvi {
121040cb5e5dSvi 	const sip_str_t	*localtag;
121140cb5e5dSvi 	const sip_str_t	*remtag;
121240cb5e5dSvi 	const sip_str_t	*callid;
121340cb5e5dSvi 	uint16_t	digest[8];
121440cb5e5dSvi 	_sip_dialog_t	*dialog;
121540cb5e5dSvi 	boolean_t	is_request;
121640cb5e5dSvi 	int		error;
121740cb5e5dSvi 
121840cb5e5dSvi 	is_request = sip_msg_is_request((sip_msg_t)sip_msg, &error);
121940cb5e5dSvi 	if (error != 0)
122040cb5e5dSvi 		return (NULL);
122140cb5e5dSvi 	if (is_request) {
122240cb5e5dSvi 		localtag = sip_get_to_tag((sip_msg_t)sip_msg, &error);
122340cb5e5dSvi 		if (error == 0)
122440cb5e5dSvi 			remtag = sip_get_from_tag((sip_msg_t)sip_msg, &error);
122540cb5e5dSvi 	} else {
122640cb5e5dSvi 		remtag = sip_get_to_tag((sip_msg_t)sip_msg, &error);
122740cb5e5dSvi 		if (error == 0)
122840cb5e5dSvi 			localtag = sip_get_from_tag((sip_msg_t)sip_msg, &error);
122940cb5e5dSvi 	}
123040cb5e5dSvi 	if (error != 0)
123140cb5e5dSvi 		return (NULL);
123240cb5e5dSvi 	callid = sip_get_callid((sip_msg_t)sip_msg, &error);
123340cb5e5dSvi 	if (error != 0 || remtag == NULL || localtag == NULL ||
123440cb5e5dSvi 	    callid == NULL) {
123540cb5e5dSvi 		return (NULL);
123640cb5e5dSvi 	}
123740cb5e5dSvi 	sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len,
123840cb5e5dSvi 	    remtag->sip_str_ptr, remtag->sip_str_len,
123940cb5e5dSvi 	    callid->sip_str_ptr, callid->sip_str_len,
124040cb5e5dSvi 	    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest);
124140cb5e5dSvi 
124240cb5e5dSvi 	dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_hash,
124340cb5e5dSvi 	    (void *)digest, SIP_DIGEST_TO_HASH(digest), sip_dialog_match);
124440cb5e5dSvi 	if (dialog == NULL) {
124540cb5e5dSvi 		sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len,
124640cb5e5dSvi 		    NULL, 0, callid->sip_str_ptr, callid->sip_str_len,
124740cb5e5dSvi 		    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest);
124840cb5e5dSvi 		dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_phash,
124940cb5e5dSvi 		    (void *)digest, SIP_DIGEST_TO_HASH(digest),
125040cb5e5dSvi 		    sip_dialog_match);
125140cb5e5dSvi 	}
125240cb5e5dSvi 	return ((sip_dialog_t)dialog);
125340cb5e5dSvi }
125440cb5e5dSvi 
125540cb5e5dSvi /*
125640cb5e5dSvi  * We keep this partial dialog for the duration of the INVITE
125740cb5e5dSvi  * transaction timeout duration, i.e. Timer B.
125840cb5e5dSvi  */
125940cb5e5dSvi void
126040cb5e5dSvi sip_dlg_self_destruct(void *args)
126140cb5e5dSvi {
126240cb5e5dSvi 	sip_dialog_timer_obj_t	*tim_obj = (sip_dialog_timer_obj_t *)args;
126340cb5e5dSvi 	_sip_dialog_t		*dialog = (_sip_dialog_t *)tim_obj->dialog;
126440cb5e5dSvi 	int			index;
126540cb5e5dSvi 
126640cb5e5dSvi 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
126740cb5e5dSvi 	assert(dialog->sip_dlg_state == SIP_DLG_NEW);
126840cb5e5dSvi 	dialog->sip_dlg_state = SIP_DLG_DESTROYED;
126940cb5e5dSvi 	if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
127040cb5e5dSvi 		index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id);
127140cb5e5dSvi 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
127240cb5e5dSvi 		sip_hash_delete(sip_dialog_phash, (void *)dialog->sip_dlg_id,
127340cb5e5dSvi 		    index, sip_dialog_dontfree);
127440cb5e5dSvi 	} else {
127540cb5e5dSvi 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
127640cb5e5dSvi 	}
127740cb5e5dSvi 	if (tim_obj->func != NULL)
127840cb5e5dSvi 		tim_obj->func(dialog, NULL, NULL);
127940cb5e5dSvi 	free(tim_obj);
128040cb5e5dSvi 	SIP_DLG_REFCNT_DECR(dialog);
128140cb5e5dSvi }
128240cb5e5dSvi 
128340cb5e5dSvi /*
128440cb5e5dSvi  * Terminate a dialog
128540cb5e5dSvi  */
128640cb5e5dSvi void
128740cb5e5dSvi sip_dialog_terminate(_sip_dialog_t *dialog, sip_msg_t sip_msg)
128840cb5e5dSvi {
128940cb5e5dSvi 	int	prev_state;
129040cb5e5dSvi 
129140cb5e5dSvi 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
129240cb5e5dSvi 	prev_state = dialog->sip_dlg_state;
129340cb5e5dSvi 	dialog->sip_dlg_state = SIP_DLG_DESTROYED;
129440cb5e5dSvi 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
129540cb5e5dSvi 	if (sip_dlg_ulp_state_cb != NULL) {
129640cb5e5dSvi 		sip_dlg_ulp_state_cb((sip_dialog_t)dialog, sip_msg, prev_state,
129740cb5e5dSvi 		    dialog->sip_dlg_state);
129840cb5e5dSvi 	}
129940cb5e5dSvi 	SIP_DLG_REFCNT_DECR(dialog);
130040cb5e5dSvi }
130140cb5e5dSvi 
130240cb5e5dSvi /*
130340cb5e5dSvi  * Delete a dialog
130440cb5e5dSvi  */
130540cb5e5dSvi void
130640cb5e5dSvi sip_dialog_delete(_sip_dialog_t *dialog)
130740cb5e5dSvi {
130840cb5e5dSvi 	int	index;
130940cb5e5dSvi 
131040cb5e5dSvi 	/*
131140cb5e5dSvi 	 * partial dialog, not in the hash table
131240cb5e5dSvi 	 */
131340cb5e5dSvi 	if (dialog->sip_dlg_local_uri_tag == NULL ||
131440cb5e5dSvi 	    dialog->sip_dlg_remote_uri_tag == NULL) {
131540cb5e5dSvi 		/*
131640cb5e5dSvi 		 * Cancel the partial dialog timer
131740cb5e5dSvi 		 */
131840cb5e5dSvi 		if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
131940cb5e5dSvi 			SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
132040cb5e5dSvi 		sip_release_dialog_res(dialog);
132140cb5e5dSvi 		return;
132240cb5e5dSvi 	}
132340cb5e5dSvi 	index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id);
132440cb5e5dSvi 	sip_hash_delete(sip_dialog_hash, (void *)dialog->sip_dlg_id, index,
132540cb5e5dSvi 	    sip_dialog_free);
132640cb5e5dSvi }
132740cb5e5dSvi 
132840cb5e5dSvi /*
132940cb5e5dSvi  * Get the remote target from the CONTACT header from the 200 OK response
133040cb5e5dSvi  */
133140cb5e5dSvi static boolean_t
133240cb5e5dSvi sip_get_rtarg(_sip_dialog_t *dialog, _sip_msg_t *sip_msg)
133340cb5e5dSvi {
133440cb5e5dSvi 	sip_header_t	chdr;
133540cb5e5dSvi 
133640cb5e5dSvi 	if (dialog->sip_dlg_remote_target != NULL)
133740cb5e5dSvi 		return (B_TRUE);
133840cb5e5dSvi 
133940cb5e5dSvi 	(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
134040cb5e5dSvi 	chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
134140cb5e5dSvi 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
134240cb5e5dSvi 	if (chdr == NULL)
134340cb5e5dSvi 		return (B_FALSE);
134440cb5e5dSvi 	if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) == NULL)
134540cb5e5dSvi 		return (B_FALSE);
134640cb5e5dSvi 
134740cb5e5dSvi 	return (B_TRUE);
134840cb5e5dSvi }
134940cb5e5dSvi 
135040cb5e5dSvi /*
135140cb5e5dSvi  * Process an incoming request/response
135240cb5e5dSvi  */
135340cb5e5dSvi /* ARGSUSED */
135440cb5e5dSvi int
135540cb5e5dSvi sip_dialog_process(_sip_msg_t *sip_msg, sip_dialog_t *sip_dialog)
135640cb5e5dSvi {
135740cb5e5dSvi 	boolean_t	request;
135840cb5e5dSvi 	_sip_dialog_t	*_dialog;
135940cb5e5dSvi 	int		error;
136040cb5e5dSvi 
136140cb5e5dSvi 	request = sip_msg_is_request((sip_msg_t)sip_msg, &error);
136240cb5e5dSvi 	if (error != 0)
136340cb5e5dSvi 		return (EINVAL);
136440cb5e5dSvi 	_dialog = (_sip_dialog_t *)*sip_dialog;
136540cb5e5dSvi 	if (request) {
136640cb5e5dSvi 		uint32_t	cseq;
136740cb5e5dSvi 		sip_method_t	method;
136840cb5e5dSvi 
136940cb5e5dSvi 		cseq = sip_get_callseq_num((sip_msg_t)sip_msg, &error);
137040cb5e5dSvi 		if (error != 0)
137140cb5e5dSvi 			return (EINVAL);
137240cb5e5dSvi 		method = sip_get_callseq_method((sip_msg_t)sip_msg, &error);
137340cb5e5dSvi 		if (error != 0)
137440cb5e5dSvi 			return (EINVAL);
137540cb5e5dSvi 		if (sip_get_request_method((sip_msg_t)sip_msg, &error) !=
137640cb5e5dSvi 		    method) {
137740cb5e5dSvi 			return (EINVAL);
137840cb5e5dSvi 		}
137940cb5e5dSvi 		(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
138040cb5e5dSvi 		/*
138140cb5e5dSvi 		 * Requests that do not change in any way the state
138240cb5e5dSvi 		 * of a dialog may be received within a dialog.
138340cb5e5dSvi 		 * They are processed as if they had been received
138440cb5e5dSvi 		 * outside the dialog.
138540cb5e5dSvi 		 * For dialogs that have been established with an
138640cb5e5dSvi 		 * INVITE, the only target refresh request defined is
138740cb5e5dSvi 		 * re-INVITE.
138840cb5e5dSvi 		 */
138940cb5e5dSvi 		if (_dialog->sip_dlg_method == INVITE &&
139040cb5e5dSvi 		    method == INVITE && _dialog->sip_dlg_remote_cseq != 0 &&
139140cb5e5dSvi 		    SIP_CSEQ_LT(cseq, _dialog->sip_dlg_remote_cseq)) {
139240cb5e5dSvi 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
139340cb5e5dSvi 			return (EPROTO);
139440cb5e5dSvi 		}
139540cb5e5dSvi 		/*
139640cb5e5dSvi 		 * Target-Refresh request
139740cb5e5dSvi 		 */
139840cb5e5dSvi 		if (_dialog->sip_dlg_method == INVITE && method == INVITE) {
139940cb5e5dSvi 			sip_header_t	chdr;
140040cb5e5dSvi 			sip_header_t	nchdr;
140140cb5e5dSvi 
140240cb5e5dSvi 			(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
140340cb5e5dSvi 			chdr = sip_search_for_header(sip_msg, SIP_CONTACT,
140440cb5e5dSvi 			    NULL);
140540cb5e5dSvi 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
140640cb5e5dSvi 			if (chdr != NULL &&
140740cb5e5dSvi 			    (nchdr = sip_dup_header(chdr)) != NULL) {
140840cb5e5dSvi 				if (_dialog->sip_dlg_remote_target != NULL) {
140940cb5e5dSvi 					sip_free_header(
141040cb5e5dSvi 					    _dialog->sip_dlg_remote_target);
141140cb5e5dSvi 				}
141240cb5e5dSvi 				_dialog->sip_dlg_remote_target = nchdr;
141340cb5e5dSvi 			}
141440cb5e5dSvi 		}
141540cb5e5dSvi 		_dialog->sip_dlg_remote_cseq = cseq;
141640cb5e5dSvi 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
141740cb5e5dSvi 	} else {
141840cb5e5dSvi 		int		resp_code;
141940cb5e5dSvi 		sip_method_t	method;
142040cb5e5dSvi 		int		error;
142140cb5e5dSvi 
142240cb5e5dSvi 		resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
142340cb5e5dSvi 		if (error == 0) {
142440cb5e5dSvi 			method = sip_get_callseq_method((sip_msg_t)sip_msg,
142540cb5e5dSvi 			    &error);
142640cb5e5dSvi 		}
142740cb5e5dSvi 		if (error != 0)
142840cb5e5dSvi 			return (error);
142940cb5e5dSvi 
143040cb5e5dSvi 		(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
14315878c602Sgm 		if (_dialog->sip_dlg_state == SIP_DLG_DESTROYED) {
14325878c602Sgm 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
14335878c602Sgm 			return (0);
14345878c602Sgm 		}
143540cb5e5dSvi 		assert(_dialog->sip_dlg_state == SIP_DLG_EARLY ||
143640cb5e5dSvi 		    _dialog->sip_dlg_state == SIP_DLG_CONFIRMED);
143740cb5e5dSvi 		/*
143840cb5e5dSvi 		 * Let the user delete the dialog if it is not a 1XX/2XX resp
143940cb5e5dSvi 		 * for an early INVITE dialog.
144040cb5e5dSvi 		 */
144140cb5e5dSvi 		if (SIP_OK_RESP(resp_code)) {
144240cb5e5dSvi 			if (method == INVITE) {
144340cb5e5dSvi 				if (!sip_get_rtarg(_dialog, sip_msg)) {
144440cb5e5dSvi 					(void) pthread_mutex_unlock(
144540cb5e5dSvi 					    &_dialog->sip_dlg_mutex);
144640cb5e5dSvi 					if (sip_ulp_dlg_del_cb != NULL) {
144740cb5e5dSvi 						sip_ulp_dlg_del_cb(
144840cb5e5dSvi 						    (sip_dialog_t)_dialog,
144940cb5e5dSvi 						    (sip_msg_t)sip_msg, NULL);
145040cb5e5dSvi 					}
145140cb5e5dSvi 					sip_dialog_terminate(_dialog,
145240cb5e5dSvi 					    (sip_msg_t)sip_msg);
145340cb5e5dSvi 					return (0);
145440cb5e5dSvi 				}
145540cb5e5dSvi 				if (_dialog->sip_dlg_state == SIP_DLG_EARLY) {
145640cb5e5dSvi 					_dialog->sip_dlg_state =
145740cb5e5dSvi 					    SIP_DLG_CONFIRMED;
145840cb5e5dSvi 					(void) pthread_mutex_unlock(
145940cb5e5dSvi 					    &_dialog->sip_dlg_mutex);
146040cb5e5dSvi 					(void) sip_dlg_recompute_rset(_dialog,
146140cb5e5dSvi 					    sip_msg, SIP_UAC_DIALOG);
146240cb5e5dSvi 					if (sip_dlg_ulp_state_cb != NULL) {
146340cb5e5dSvi 						sip_dlg_ulp_state_cb(
146440cb5e5dSvi 						    (sip_dialog_t)_dialog,
146540cb5e5dSvi 						    sip_msg, SIP_DLG_EARLY,
146640cb5e5dSvi 						    _dialog->sip_dlg_state);
146740cb5e5dSvi 					}
146840cb5e5dSvi 					return (0);
1469*d8a40387Sgm 				} else if (_dialog->sip_dlg_new_local_contact
1470*d8a40387Sgm 				    != NULL) {
1471*d8a40387Sgm 					assert(_dialog->sip_dlg_local_contact
1472*d8a40387Sgm 					    != NULL);
1473*d8a40387Sgm 					sip_free_header(_dialog->
1474*d8a40387Sgm 						    sip_dlg_local_contact);
1475*d8a40387Sgm 					_dialog->sip_dlg_local_contact =
1476*d8a40387Sgm 					    _dialog->sip_dlg_new_local_contact;
1477*d8a40387Sgm 					_dialog->sip_dlg_new_local_contact =
1478*d8a40387Sgm 					    NULL;
147940cb5e5dSvi 				}
148040cb5e5dSvi 			}
148140cb5e5dSvi 		}
148240cb5e5dSvi 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
148340cb5e5dSvi 	}
148440cb5e5dSvi 	return (0);
148540cb5e5dSvi }
148640cb5e5dSvi 
148740cb5e5dSvi /*
148840cb5e5dSvi  * Copy partial dialog to create a complete dialog
148940cb5e5dSvi  */
149040cb5e5dSvi _sip_dialog_t *
149140cb5e5dSvi sip_copy_partial_dialog(_sip_dialog_t *dialog)
149240cb5e5dSvi {
149340cb5e5dSvi 	_sip_dialog_t	*new_dlg;
149440cb5e5dSvi 
149540cb5e5dSvi 	new_dlg =  calloc(1, sizeof (_sip_dialog_t));
149640cb5e5dSvi 	if (new_dlg == NULL)
149740cb5e5dSvi 		return (NULL);
149840cb5e5dSvi 	if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) {
149940cb5e5dSvi 		new_dlg->sip_dlg_req_uri.sip_str_ptr =
150040cb5e5dSvi 		    malloc(dialog->sip_dlg_req_uri.sip_str_len + 1);
150140cb5e5dSvi 		if (new_dlg->sip_dlg_req_uri.sip_str_ptr == NULL) {
150240cb5e5dSvi 			free(new_dlg);
150340cb5e5dSvi 			return (NULL);
150440cb5e5dSvi 		}
150540cb5e5dSvi 		(void) strncpy(new_dlg->sip_dlg_req_uri.sip_str_ptr,
150640cb5e5dSvi 		    dialog->sip_dlg_req_uri.sip_str_ptr,
150740cb5e5dSvi 		    dialog->sip_dlg_req_uri.sip_str_len);
150840cb5e5dSvi 		new_dlg->sip_dlg_req_uri.sip_str_ptr[
150940cb5e5dSvi 		    dialog->sip_dlg_req_uri.sip_str_len] = '\0';
151040cb5e5dSvi 		new_dlg->sip_dlg_req_uri.sip_str_len =
151140cb5e5dSvi 		    dialog->sip_dlg_req_uri.sip_str_len;
151240cb5e5dSvi 	}
151340cb5e5dSvi 	if (dialog->sip_dlg_route_set != NULL) {
151440cb5e5dSvi 		assert(dialog->sip_dlg_rset.sip_str_ptr != NULL);
151540cb5e5dSvi 		new_dlg->sip_dlg_rset.sip_str_ptr =
151640cb5e5dSvi 		    malloc(dialog->sip_dlg_rset.sip_str_len + 1);
151740cb5e5dSvi 		if (new_dlg->sip_dlg_rset.sip_str_ptr == NULL) {
151840cb5e5dSvi 			if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL)
151940cb5e5dSvi 				free(new_dlg->sip_dlg_req_uri.sip_str_ptr);
152040cb5e5dSvi 			free(new_dlg);
152140cb5e5dSvi 			return (NULL);
152240cb5e5dSvi 		}
152340cb5e5dSvi 		(void) strncpy(new_dlg->sip_dlg_rset.sip_str_ptr,
152440cb5e5dSvi 		    dialog->sip_dlg_rset.sip_str_ptr,
152540cb5e5dSvi 		    dialog->sip_dlg_rset.sip_str_len);
152640cb5e5dSvi 		new_dlg->sip_dlg_rset.sip_str_ptr[
152740cb5e5dSvi 		    dialog->sip_dlg_rset.sip_str_len] = '\0';
152840cb5e5dSvi 		new_dlg->sip_dlg_rset.sip_str_len =
152940cb5e5dSvi 		    dialog->sip_dlg_rset.sip_str_len;
153040cb5e5dSvi 
153140cb5e5dSvi 		new_dlg->sip_dlg_route_set =
153240cb5e5dSvi 		    sip_dup_header(dialog->sip_dlg_route_set);
153340cb5e5dSvi 		if (new_dlg->sip_dlg_route_set == NULL) {
153440cb5e5dSvi 			free(new_dlg->sip_dlg_rset.sip_str_ptr);
153540cb5e5dSvi 			if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL)
153640cb5e5dSvi 				free(new_dlg->sip_dlg_req_uri.sip_str_ptr);
153740cb5e5dSvi 			free(new_dlg);
153840cb5e5dSvi 			return (NULL);
153940cb5e5dSvi 		}
154040cb5e5dSvi 	}
154140cb5e5dSvi 	if ((new_dlg->sip_dlg_local_uri_tag =
154240cb5e5dSvi 	    sip_dup_header(dialog->sip_dlg_local_uri_tag)) == NULL ||
154340cb5e5dSvi 	    (new_dlg->sip_dlg_remote_target =
154440cb5e5dSvi 	    sip_dup_header(dialog->sip_dlg_remote_target)) == NULL ||
1545*d8a40387Sgm 	    (new_dlg->sip_dlg_local_contact =
1546*d8a40387Sgm 	    sip_dup_header(dialog->sip_dlg_local_contact)) == NULL ||
154740cb5e5dSvi 	    (new_dlg->sip_dlg_call_id =
154840cb5e5dSvi 	    sip_dup_header(dialog->sip_dlg_call_id)) == NULL) {
154940cb5e5dSvi 		sip_release_dialog_res(new_dlg);
155040cb5e5dSvi 		return (NULL);
155140cb5e5dSvi 	}
155240cb5e5dSvi 	if (dialog->sip_dlg_event != NULL) {
155340cb5e5dSvi 		new_dlg->sip_dlg_event = sip_dup_header(dialog->sip_dlg_event);
155440cb5e5dSvi 		if (new_dlg->sip_dlg_event == NULL) {
155540cb5e5dSvi 			sip_release_dialog_res(new_dlg);
155640cb5e5dSvi 			return (NULL);
155740cb5e5dSvi 		}
155840cb5e5dSvi 	}
155940cb5e5dSvi 	new_dlg->sip_dlg_local_cseq = dialog->sip_dlg_local_cseq;
156040cb5e5dSvi 	new_dlg->sip_dlg_type = dialog->sip_dlg_type;
156140cb5e5dSvi 	new_dlg->sip_dlg_on_fork = B_FALSE;
156240cb5e5dSvi 	(void) pthread_mutex_init(&new_dlg->sip_dlg_mutex, NULL);
156340cb5e5dSvi 
156440cb5e5dSvi 	return (new_dlg);
156540cb5e5dSvi }
156640cb5e5dSvi 
156740cb5e5dSvi /*
156840cb5e5dSvi  * Update the dialog using the response
156940cb5e5dSvi  */
157040cb5e5dSvi sip_dialog_t
157140cb5e5dSvi sip_update_dialog(sip_dialog_t dialog, _sip_msg_t *sip_msg)
157240cb5e5dSvi {
157340cb5e5dSvi 	_sip_dialog_t	*_dialog;
157440cb5e5dSvi 	boolean_t	isreq;
157540cb5e5dSvi 	sip_method_t	method;
157640cb5e5dSvi 	int		resp_code = 0;
157740cb5e5dSvi 	int		prev_state;
157840cb5e5dSvi 	boolean_t	decr_ref = B_FALSE;
157940cb5e5dSvi 	int		error;
158040cb5e5dSvi 
158140cb5e5dSvi 	isreq = sip_msg_is_request((sip_msg_t)sip_msg, &error);
158240cb5e5dSvi 	if (error != 0)
158340cb5e5dSvi 		return (dialog);
158440cb5e5dSvi 	_dialog = (_sip_dialog_t *)dialog;
158540cb5e5dSvi 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
158640cb5e5dSvi 	if (isreq) {
158740cb5e5dSvi 		method = sip_get_request_method((sip_msg_t)sip_msg, &error);
158840cb5e5dSvi 		if (error != 0 || _dialog->sip_dlg_method != SUBSCRIBE ||
158940cb5e5dSvi 		    method != NOTIFY) {
159040cb5e5dSvi 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
159140cb5e5dSvi 			return (dialog);
159240cb5e5dSvi 		}
159340cb5e5dSvi 	} else {
159440cb5e5dSvi 		resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
159540cb5e5dSvi 		if (error != 0) {
159640cb5e5dSvi 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
159740cb5e5dSvi 			return (dialog);
159840cb5e5dSvi 		}
1599*d8a40387Sgm 		method = sip_get_callseq_method((sip_msg_t)sip_msg, &error);
1600*d8a40387Sgm 		if (error != 0) {
1601*d8a40387Sgm 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
1602*d8a40387Sgm 			return (dialog);
1603*d8a40387Sgm 		}
160440cb5e5dSvi 	}
160540cb5e5dSvi 	prev_state = _dialog->sip_dlg_state;
160640cb5e5dSvi 	if (_dialog->sip_dlg_state == SIP_DLG_CONFIRMED) {
160740cb5e5dSvi 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
160840cb5e5dSvi 	} else if (_dialog->sip_dlg_state == SIP_DLG_EARLY) {
160940cb5e5dSvi 		/*
161040cb5e5dSvi 		 * Let the user delete the dialog if it is not a 1XX/2XX resp
161140cb5e5dSvi 		 * for an early dialog.
161240cb5e5dSvi 		 */
161340cb5e5dSvi 		assert(!isreq);
161440cb5e5dSvi 		if (SIP_OK_RESP(resp_code)) {
161540cb5e5dSvi 			_dialog->sip_dlg_state = SIP_DLG_CONFIRMED;
1616*d8a40387Sgm 			/*
1617*d8a40387Sgm 			 * If we recieved provisional response before we would
1618*d8a40387Sgm 			 * not have captured local contact. So store it now.
1619*d8a40387Sgm 			 */
1620*d8a40387Sgm 			if (_dialog->sip_dlg_type == SIP_UAS_DIALOG && _dialog->
1621*d8a40387Sgm 			    sip_dlg_method == INVITE && method == INVITE) {
1622*d8a40387Sgm 				sip_header_t chdr;
1623*d8a40387Sgm 				(void) pthread_mutex_lock(&sip_msg->
1624*d8a40387Sgm 				    sip_msg_mutex);
1625*d8a40387Sgm 				chdr = sip_search_for_header(sip_msg,
1626*d8a40387Sgm 				    SIP_CONTACT, NULL);
1627*d8a40387Sgm 				(void) pthread_mutex_unlock(&sip_msg->
1628*d8a40387Sgm 				    sip_msg_mutex);
1629*d8a40387Sgm 				if (chdr != NULL) {
1630*d8a40387Sgm 					_dialog->sip_dlg_local_contact
1631*d8a40387Sgm 					    = sip_dup_header(chdr);
1632*d8a40387Sgm 					_dialog->sip_dlg_new_local_contact =
1633*d8a40387Sgm 					    NULL;
1634*d8a40387Sgm 				}
1635*d8a40387Sgm 			}
163640cb5e5dSvi 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
163740cb5e5dSvi 			(void) sip_dlg_recompute_rset(_dialog, sip_msg,
163840cb5e5dSvi 			    SIP_UAS_DIALOG);
163940cb5e5dSvi 			if (sip_dlg_ulp_state_cb != NULL) {
164040cb5e5dSvi 				sip_dlg_ulp_state_cb(dialog, (sip_msg_t)sip_msg,
164140cb5e5dSvi 				    prev_state, dialog->sip_dlg_state);
164240cb5e5dSvi 			}
164340cb5e5dSvi 		} else {
164440cb5e5dSvi 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
164540cb5e5dSvi 		}
164640cb5e5dSvi 	} else if (_dialog->sip_dlg_state == SIP_DLG_NEW) {
164740cb5e5dSvi 		if (!isreq && _dialog->sip_dlg_method == SUBSCRIBE &&
164840cb5e5dSvi 		    SIP_PROVISIONAL_RESP(resp_code)) {
164940cb5e5dSvi 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
165040cb5e5dSvi 			return (dialog);
165140cb5e5dSvi 		}
165240cb5e5dSvi 		if (_dialog->sip_dlg_type == SIP_UAC_DIALOG) {
165340cb5e5dSvi 			_sip_dialog_t	*new_dlg;
165440cb5e5dSvi 
165540cb5e5dSvi 			if (_dialog->sip_dlg_on_fork) {
165640cb5e5dSvi 				new_dlg = sip_copy_partial_dialog(_dialog);
165740cb5e5dSvi 				if (new_dlg == NULL) {
165840cb5e5dSvi 					(void) pthread_mutex_unlock(
165940cb5e5dSvi 					    &_dialog->sip_dlg_mutex);
166040cb5e5dSvi 					return (dialog);
166140cb5e5dSvi 				}
166240cb5e5dSvi 				/*
166340cb5e5dSvi 				 * This decr/incr dance is because the caller
166440cb5e5dSvi 				 * has incremented the ref on the partial
166540cb5e5dSvi 				 * dialog, we release it here and incr the
166640cb5e5dSvi 				 * ref on the new dialog which will be
166740cb5e5dSvi 				 * released by the caller.
166840cb5e5dSvi 				 */
166940cb5e5dSvi 				(void) pthread_mutex_unlock(
167040cb5e5dSvi 				    &_dialog->sip_dlg_mutex);
167140cb5e5dSvi 				SIP_DLG_REFCNT_DECR(_dialog);
167240cb5e5dSvi 				_dialog = new_dlg;
167340cb5e5dSvi 				(void) pthread_mutex_lock(
167440cb5e5dSvi 				    &_dialog->sip_dlg_mutex);
167540cb5e5dSvi 				SIP_DLG_REFCNT_INCR(_dialog);
167640cb5e5dSvi 			} else {
167740cb5e5dSvi 				int	index;
167840cb5e5dSvi 
167940cb5e5dSvi 				/*
168040cb5e5dSvi 				 * take it out of the list so that further
168140cb5e5dSvi 				 * responses will not result in a dialog.
168240cb5e5dSvi 				 * We will have an extra refcount when we
168340cb5e5dSvi 				 * come back from sip_complete_dialog(), i.e.
168440cb5e5dSvi 				 * one when the partial dialog was created -
168540cb5e5dSvi 				 * in sip_seed_dialog(), one held by the caller
168640cb5e5dSvi 				 * and one that will be added by
168740cb5e5dSvi 				 * sip_complete_dialog(). We need to release
168840cb5e5dSvi 				 * the one added by the sip_seed_dialog(),
168940cb5e5dSvi 				 * since the one in sip_complete_dialog()
169040cb5e5dSvi 				 * is for the same purpose.
169140cb5e5dSvi 				 */
169240cb5e5dSvi 				if (SIP_IS_TIMER_RUNNING(
169340cb5e5dSvi 				    _dialog->sip_dlg_timer)) {
169440cb5e5dSvi 					SIP_CANCEL_TIMER(
169540cb5e5dSvi 					    _dialog->sip_dlg_timer);
169640cb5e5dSvi 				}
169740cb5e5dSvi 				index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id);
169840cb5e5dSvi 				(void) pthread_mutex_unlock(
169940cb5e5dSvi 				    &_dialog->sip_dlg_mutex);
170040cb5e5dSvi 				sip_hash_delete(sip_dialog_phash,
170140cb5e5dSvi 				    (void *)_dialog->sip_dlg_id,
170240cb5e5dSvi 				    index, sip_dialog_dontfree);
170340cb5e5dSvi 				(void) pthread_mutex_lock(
170440cb5e5dSvi 				    &_dialog->sip_dlg_mutex);
170540cb5e5dSvi 				decr_ref = B_TRUE;
170640cb5e5dSvi 			}
170740cb5e5dSvi 		} else {
170840cb5e5dSvi 			decr_ref = B_TRUE;
170940cb5e5dSvi 		}
171040cb5e5dSvi 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
171140cb5e5dSvi 		if ((dialog = sip_complete_dialog(sip_msg, _dialog)) ==
171240cb5e5dSvi 		    NULL) {
17132c2c4183Svi 			if (_dialog->sip_dlg_type == SIP_UAC_DIALOG && decr_ref)
17142c2c4183Svi 				SIP_DLG_REFCNT_DECR(_dialog);
171540cb5e5dSvi 			return (NULL);
171640cb5e5dSvi 		}
171740cb5e5dSvi 		if (decr_ref)
171840cb5e5dSvi 			SIP_DLG_REFCNT_DECR(_dialog);
171940cb5e5dSvi 	} else {
172040cb5e5dSvi 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
172140cb5e5dSvi 	}
172240cb5e5dSvi 	return (dialog);
172340cb5e5dSvi }
172440cb5e5dSvi 
172540cb5e5dSvi /*
172640cb5e5dSvi  * Initialize the hash table
172740cb5e5dSvi  */
172840cb5e5dSvi void
172940cb5e5dSvi sip_dialog_init(void (*ulp_dlg_del) (sip_dialog_t, sip_msg_t, void *),
173040cb5e5dSvi     void (*ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int))
173140cb5e5dSvi {
173240cb5e5dSvi 	int	cnt;
173340cb5e5dSvi 
173440cb5e5dSvi 	for (cnt = 0; cnt < SIP_HASH_SZ; cnt++) {
173540cb5e5dSvi 		sip_dialog_hash[cnt].hash_count = 0;
173640cb5e5dSvi 		sip_dialog_hash[cnt].hash_head = NULL;
173740cb5e5dSvi 		sip_dialog_hash[cnt].hash_tail = NULL;
173840cb5e5dSvi 		(void) pthread_mutex_init(
173940cb5e5dSvi 		    &sip_dialog_hash[cnt].sip_hash_mutex, NULL);
174040cb5e5dSvi 		sip_dialog_phash[cnt].hash_count = 0;
174140cb5e5dSvi 		sip_dialog_phash[cnt].hash_head = NULL;
174240cb5e5dSvi 		sip_dialog_phash[cnt].hash_tail = NULL;
174340cb5e5dSvi 		(void) pthread_mutex_init(
174440cb5e5dSvi 		    &sip_dialog_phash[cnt].sip_hash_mutex, NULL);
174540cb5e5dSvi 	}
174640cb5e5dSvi 	if (ulp_dlg_del != NULL)
174740cb5e5dSvi 		sip_ulp_dlg_del_cb = ulp_dlg_del;
174840cb5e5dSvi 
174940cb5e5dSvi 	if (ulp_state_cb != NULL)
175040cb5e5dSvi 		sip_dlg_ulp_state_cb = ulp_state_cb;
175140cb5e5dSvi }
1752*d8a40387Sgm 
1753*d8a40387Sgm /*
1754*d8a40387Sgm  * Copy the new contact header of re-INVITE
1755*d8a40387Sgm  */
1756*d8a40387Sgm void
1757*d8a40387Sgm sip_dialog_add_new_contact(sip_dialog_t dialog, _sip_msg_t *sip_msg)
1758*d8a40387Sgm {
1759*d8a40387Sgm 	sip_header_t chdr = NULL;
1760*d8a40387Sgm 	sip_header_t nhdr = NULL;
1761*d8a40387Sgm 
1762*d8a40387Sgm 	(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
1763*d8a40387Sgm 	chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
1764*d8a40387Sgm 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
1765*d8a40387Sgm 
1766*d8a40387Sgm 	if (chdr == NULL)
1767*d8a40387Sgm 		return;
1768*d8a40387Sgm 
1769*d8a40387Sgm 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
1770*d8a40387Sgm 	if (dialog->sip_dlg_method != INVITE || dialog->sip_dlg_state
1771*d8a40387Sgm 	    != SIP_DLG_CONFIRMED) {
1772*d8a40387Sgm 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1773*d8a40387Sgm 		return;
1774*d8a40387Sgm 	}
1775*d8a40387Sgm 
1776*d8a40387Sgm 	if (((nhdr = sip_dup_header(chdr)) != NULL)) {
1777*d8a40387Sgm 		if (dialog->sip_dlg_new_local_contact != NULL)
1778*d8a40387Sgm 			sip_free_header(dialog->sip_dlg_new_local_contact);
1779*d8a40387Sgm 		dialog->sip_dlg_new_local_contact = nhdr;
1780*d8a40387Sgm 	}
1781*d8a40387Sgm 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1782*d8a40387Sgm }
1783