1*2882Svi117747 /*
2*2882Svi117747  * CDDL HEADER START
3*2882Svi117747  *
4*2882Svi117747  * The contents of this file are subject to the terms of the
5*2882Svi117747  * Common Development and Distribution License (the "License").
6*2882Svi117747  * You may not use this file except in compliance with the License.
7*2882Svi117747  *
8*2882Svi117747  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*2882Svi117747  * or http://www.opensolaris.org/os/licensing.
10*2882Svi117747  * See the License for the specific language governing permissions
11*2882Svi117747  * and limitations under the License.
12*2882Svi117747  *
13*2882Svi117747  * When distributing Covered Code, include this CDDL HEADER in each
14*2882Svi117747  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*2882Svi117747  * If applicable, add the following below this CDDL HEADER, with the
16*2882Svi117747  * fields enclosed by brackets "[]" replaced with your own identifying
17*2882Svi117747  * information: Portions Copyright [yyyy] [name of copyright owner]
18*2882Svi117747  *
19*2882Svi117747  * CDDL HEADER END
20*2882Svi117747  */
21*2882Svi117747 
22*2882Svi117747 /*
23*2882Svi117747  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*2882Svi117747  * Use is subject to license terms.
25*2882Svi117747  */
26*2882Svi117747 
27*2882Svi117747 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*2882Svi117747 
29*2882Svi117747 #include "sip_parse_uri.h"
30*2882Svi117747 #include "sip_msg.h"
31*2882Svi117747 #include "sip_hash.h"
32*2882Svi117747 #include "sip_miscdefs.h"
33*2882Svi117747 #include "sip_dialog.h"
34*2882Svi117747 #include "sip_parse_generic.h"
35*2882Svi117747 
36*2882Svi117747 #define	SIP_DLG_XCHG_FROM	0
37*2882Svi117747 #define	SIP_DLG_XCHG_TO		1
38*2882Svi117747 
39*2882Svi117747 /*
40*2882Svi117747  * Dialog state change callback function
41*2882Svi117747  */
42*2882Svi117747 void (*sip_dlg_ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int) = NULL;
43*2882Svi117747 void (*sip_ulp_dlg_del_cb)(sip_dialog_t, sip_msg_t, void *) = NULL;
44*2882Svi117747 
45*2882Svi117747 boolean_t	sip_incomplete_dialog(sip_dialog_t);
46*2882Svi117747 
47*2882Svi117747 /*
48*2882Svi117747  * Exchange From/To header
49*2882Svi117747  */
50*2882Svi117747 _sip_header_t *sip_dlg_xchg_from_to(sip_msg_t, int);
51*2882Svi117747 
52*2882Svi117747 /*
53*2882Svi117747  * Complete dialog hash table
54*2882Svi117747  */
55*2882Svi117747 sip_hash_t sip_dialog_hash[SIP_HASH_SZ];
56*2882Svi117747 
57*2882Svi117747 /*
58*2882Svi117747  * Partial dialog hash table
59*2882Svi117747  */
60*2882Svi117747 sip_hash_t sip_dialog_phash[SIP_HASH_SZ];
61*2882Svi117747 
62*2882Svi117747 /*
63*2882Svi117747  * Route set structure
64*2882Svi117747  */
65*2882Svi117747 typedef struct sip_dlg_route_set_s  {
66*2882Svi117747 	char		*sip_dlg_route;
67*2882Svi117747 	sip_str_t	sip_dlg_ruri;
68*2882Svi117747 	boolean_t	sip_dlg_route_lr;
69*2882Svi117747 	struct sip_dlg_route_set_s *sip_dlg_route_next;
70*2882Svi117747 }sip_dlg_route_set_t;
71*2882Svi117747 
72*2882Svi117747 sip_dialog_t		sip_seed_dialog(sip_conn_object_t, _sip_msg_t *,
73*2882Svi117747 			    boolean_t, int);
74*2882Svi117747 sip_dialog_t		sip_complete_dialog(_sip_msg_t *, _sip_dialog_t *);
75*2882Svi117747 int			sip_dialog_process(_sip_msg_t *, sip_dialog_t *);
76*2882Svi117747 void			sip_dialog_delete(_sip_dialog_t *);
77*2882Svi117747 void			sip_dialog_init();
78*2882Svi117747 sip_dialog_t		sip_dialog_find(_sip_msg_t *);
79*2882Svi117747 boolean_t		sip_dialog_match(void *, void *);
80*2882Svi117747 boolean_t		sip_dialog_free(void *, void *, int *);
81*2882Svi117747 sip_dialog_t		sip_update_dialog(sip_dialog_t, _sip_msg_t *);
82*2882Svi117747 char			*sip_dialog_req_uri(sip_dialog_t);
83*2882Svi117747 
84*2882Svi117747 static void		sip_release_dialog_res(_sip_dialog_t *);
85*2882Svi117747 void			sip_dlg_self_destruct(void *);
86*2882Svi117747 static int		sip_dialog_get_route_set(_sip_dialog_t *, _sip_msg_t *,
87*2882Svi117747 			    int);
88*2882Svi117747 static void		sip_dialog_free_rset(sip_dlg_route_set_t *);
89*2882Svi117747 
90*2882Svi117747 /*
91*2882Svi117747  * Timer object for partial dialogs
92*2882Svi117747  */
93*2882Svi117747 typedef struct sip_dialog_timer_obj_s {
94*2882Svi117747 	_sip_dialog_t	*dialog;
95*2882Svi117747 	void		(*func)(sip_dialog_t, sip_msg_t, void *);
96*2882Svi117747 } sip_dialog_timer_obj_t;
97*2882Svi117747 
98*2882Svi117747 /*
99*2882Svi117747  * To avoid duplication all over the place
100*2882Svi117747  */
101*2882Svi117747 static void
102*2882Svi117747 sip_release_dialog_res(_sip_dialog_t *dialog)
103*2882Svi117747 {
104*2882Svi117747 
105*2882Svi117747 	assert(dialog->sip_dlg_ref_cnt == 0);
106*2882Svi117747 	if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
107*2882Svi117747 		SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
108*2882Svi117747 	if (dialog->sip_dlg_call_id != NULL)
109*2882Svi117747 		sip_free_header(dialog->sip_dlg_call_id);
110*2882Svi117747 	if (dialog->sip_dlg_local_uri_tag != NULL)
111*2882Svi117747 		sip_free_header(dialog->sip_dlg_local_uri_tag);
112*2882Svi117747 	if (dialog->sip_dlg_remote_uri_tag != NULL)
113*2882Svi117747 		sip_free_header(dialog->sip_dlg_remote_uri_tag);
114*2882Svi117747 	if (dialog->sip_dlg_remote_target != NULL)
115*2882Svi117747 		sip_free_header(dialog->sip_dlg_remote_target);
116*2882Svi117747 	if (dialog->sip_dlg_route_set != NULL)
117*2882Svi117747 		sip_free_header(dialog->sip_dlg_route_set);
118*2882Svi117747 	if (dialog->sip_dlg_event != NULL)
119*2882Svi117747 		sip_free_header(dialog->sip_dlg_event);
120*2882Svi117747 	if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) {
121*2882Svi117747 		free(dialog->sip_dlg_req_uri.sip_str_ptr);
122*2882Svi117747 		dialog->sip_dlg_req_uri.sip_str_ptr = NULL;
123*2882Svi117747 		dialog->sip_dlg_req_uri.sip_str_len = 0;
124*2882Svi117747 	}
125*2882Svi117747 	if (dialog->sip_dlg_rset.sip_str_ptr != NULL) {
126*2882Svi117747 		free(dialog->sip_dlg_rset.sip_str_ptr);
127*2882Svi117747 		dialog->sip_dlg_rset.sip_str_len = 0;
128*2882Svi117747 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
129*2882Svi117747 	}
130*2882Svi117747 	(void) pthread_mutex_destroy(&dialog->sip_dlg_mutex);
131*2882Svi117747 	free(dialog);
132*2882Svi117747 }
133*2882Svi117747 
134*2882Svi117747 /*
135*2882Svi117747  * Get the route information from the 'value' and add it to the route
136*2882Svi117747  * set.
137*2882Svi117747  */
138*2882Svi117747 static sip_dlg_route_set_t *
139*2882Svi117747 sip_add_route_to_set(sip_hdr_value_t *value)
140*2882Svi117747 {
141*2882Svi117747 	int			vlen = 0;
142*2882Svi117747 	sip_dlg_route_set_t	*rset;
143*2882Svi117747 	char			*crlf;
144*2882Svi117747 	const sip_param_t	*uri_param;
145*2882Svi117747 	int			error;
146*2882Svi117747 
147*2882Svi117747 	rset = calloc(1, sizeof (*rset));
148*2882Svi117747 	if (rset == NULL)
149*2882Svi117747 		return (NULL);
150*2882Svi117747 	rset->sip_dlg_route_next = NULL;
151*2882Svi117747 	vlen = value->sip_value_end - value->sip_value_start;
152*2882Svi117747 
153*2882Svi117747 	/*
154*2882Svi117747 	 * check for CRLF
155*2882Svi117747 	 */
156*2882Svi117747 	crlf = value->sip_value_end - strlen(SIP_CRLF);
157*2882Svi117747 	while (crlf != NULL && strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) {
158*2882Svi117747 		vlen -= strlen(SIP_CRLF);
159*2882Svi117747 		crlf -= strlen(SIP_CRLF);
160*2882Svi117747 	}
161*2882Svi117747 	rset->sip_dlg_route = calloc(1, vlen + 1);
162*2882Svi117747 	if (rset->sip_dlg_route == NULL) {
163*2882Svi117747 		free(rset);
164*2882Svi117747 		return (NULL);
165*2882Svi117747 	}
166*2882Svi117747 	/*
167*2882Svi117747 	 * loose routing
168*2882Svi117747 	 */
169*2882Svi117747 	rset->sip_dlg_route_lr = B_FALSE;
170*2882Svi117747 	(void) strncpy(rset->sip_dlg_route, value->sip_value_start, vlen);
171*2882Svi117747 	rset->sip_dlg_ruri.sip_str_ptr = rset->sip_dlg_route +
172*2882Svi117747 	    (value->cftr_uri.sip_str_ptr - value->sip_value_start);
173*2882Svi117747 	rset->sip_dlg_ruri.sip_str_len = value->cftr_uri.sip_str_len;
174*2882Svi117747 	rset->sip_dlg_route[vlen] = '\0';
175*2882Svi117747 
176*2882Svi117747 	assert(value->sip_value_parsed_uri != NULL);
177*2882Svi117747 	/*
178*2882Svi117747 	 * Check if the 'lr' param is present for this route.
179*2882Svi117747 	 */
180*2882Svi117747 	uri_param = sip_get_uri_params(value->sip_value_parsed_uri, &error);
181*2882Svi117747 	if (error != 0) {
182*2882Svi117747 		free(rset->sip_dlg_route);
183*2882Svi117747 		free(rset);
184*2882Svi117747 		return (NULL);
185*2882Svi117747 	}
186*2882Svi117747 	if (uri_param != NULL) {
187*2882Svi117747 		rset->sip_dlg_route_lr = sip_is_param_present(uri_param, "lr",
188*2882Svi117747 		    strlen("lr"));
189*2882Svi117747 	}
190*2882Svi117747 	return (rset);
191*2882Svi117747 }
192*2882Svi117747 
193*2882Svi117747 /*
194*2882Svi117747  * Depending on the route-set, determine the request URI.
195*2882Svi117747  */
196*2882Svi117747 char *
197*2882Svi117747 sip_dialog_req_uri(sip_dialog_t dialog)
198*2882Svi117747 {
199*2882Svi117747 	const sip_str_t		*req_uri;
200*2882Svi117747 	char			*uri;
201*2882Svi117747 	_sip_dialog_t		*_dialog;
202*2882Svi117747 
203*2882Svi117747 	_dialog = (_sip_dialog_t *)dialog;
204*2882Svi117747 	if (_dialog->sip_dlg_route_set == NULL ||
205*2882Svi117747 	    _dialog->sip_dlg_req_uri.sip_str_ptr == NULL) {
206*2882Svi117747 		const struct sip_value	*val;
207*2882Svi117747 
208*2882Svi117747 		val = sip_get_header_value(_dialog->sip_dlg_remote_target,
209*2882Svi117747 		    NULL);
210*2882Svi117747 		if (val == NULL)
211*2882Svi117747 			return (NULL);
212*2882Svi117747 		req_uri = &((sip_hdr_value_t *)val)->cftr_uri;
213*2882Svi117747 	} else {
214*2882Svi117747 		req_uri = &_dialog->sip_dlg_req_uri;
215*2882Svi117747 	}
216*2882Svi117747 	uri = (char *)malloc(req_uri->sip_str_len + 1);
217*2882Svi117747 	if (uri == NULL)
218*2882Svi117747 		return (NULL);
219*2882Svi117747 	(void) strncpy(uri, req_uri->sip_str_ptr, req_uri->sip_str_len);
220*2882Svi117747 	uri[req_uri->sip_str_len] = '\0';
221*2882Svi117747 
222*2882Svi117747 	return (uri);
223*2882Svi117747 }
224*2882Svi117747 
225*2882Svi117747 /*
226*2882Svi117747  * Free the route set.
227*2882Svi117747  */
228*2882Svi117747 void
229*2882Svi117747 sip_dialog_free_rset(sip_dlg_route_set_t *rset)
230*2882Svi117747 {
231*2882Svi117747 	sip_dlg_route_set_t	*next;
232*2882Svi117747 
233*2882Svi117747 	while (rset != NULL) {
234*2882Svi117747 		next = rset->sip_dlg_route_next;
235*2882Svi117747 		rset->sip_dlg_route_next = NULL;
236*2882Svi117747 		free(rset->sip_dlg_route);
237*2882Svi117747 		free(rset);
238*2882Svi117747 		rset = next;
239*2882Svi117747 	}
240*2882Svi117747 }
241*2882Svi117747 
242*2882Svi117747 /*
243*2882Svi117747  * Recompute route-set
244*2882Svi117747  */
245*2882Svi117747 static int
246*2882Svi117747 sip_dlg_recompute_rset(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what)
247*2882Svi117747 {
248*2882Svi117747 	int ret;
249*2882Svi117747 
250*2882Svi117747 	if (dialog->sip_dlg_route_set != NULL) {
251*2882Svi117747 		sip_free_header(dialog->sip_dlg_route_set);
252*2882Svi117747 		dialog->sip_dlg_route_set = NULL;
253*2882Svi117747 	}
254*2882Svi117747 	if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) {
255*2882Svi117747 		free(dialog->sip_dlg_req_uri.sip_str_ptr);
256*2882Svi117747 		dialog->sip_dlg_req_uri.sip_str_ptr = NULL;
257*2882Svi117747 		dialog->sip_dlg_req_uri.sip_str_len = 0;
258*2882Svi117747 	}
259*2882Svi117747 	if (dialog->sip_dlg_rset.sip_str_ptr != NULL) {
260*2882Svi117747 		free(dialog->sip_dlg_rset.sip_str_ptr);
261*2882Svi117747 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
262*2882Svi117747 		dialog->sip_dlg_rset.sip_str_len = 0;
263*2882Svi117747 	}
264*2882Svi117747 	ret = sip_dialog_get_route_set(dialog, sip_msg, what);
265*2882Svi117747 	return (ret);
266*2882Svi117747 }
267*2882Svi117747 
268*2882Svi117747 /*
269*2882Svi117747  * If the route set is empty, the UAC MUST place the remote target URI
270*2882Svi117747  * into the Request-URI.  The UAC MUST NOT add a Route header field to
271*2882Svi117747  * the request.
272*2882Svi117747  *
273*2882Svi117747  * If the route set is not empty, and the first URI in the route set
274*2882Svi117747  * contains the lr parameter (see Section 19.1.1), the UAC MUST place
275*2882Svi117747  * the remote target URI into the Request-URI and MUST include a Route
276*2882Svi117747  * header field containing the route set values in order, including all
277*2882Svi117747  * parameters.
278*2882Svi117747  *
279*2882Svi117747  * If the route set is not empty, and its first URI does not contain the
280*2882Svi117747  * lr parameter, the UAC MUST place the first URI from the route set
281*2882Svi117747  * into the Request-URI, stripping any parameters that are not allowed
282*2882Svi117747  * in a Request-URI.  The UAC MUST add a Route header field containing
283*2882Svi117747  * the remainder of the route set values in order, including all
284*2882Svi117747  * parameters.  The UAC MUST then place the remote target URI into the
285*2882Svi117747  * Route header field as the last value.
286*2882Svi117747  */
287*2882Svi117747 int
288*2882Svi117747 sip_dialog_set_route_hdr(_sip_dialog_t *dialog, sip_dlg_route_set_t *rset_head,
289*2882Svi117747     int rcnt, int rlen)
290*2882Svi117747 {
291*2882Svi117747 	size_t			rset_len;
292*2882Svi117747 	_sip_header_t		*rhdr;
293*2882Svi117747 	char			*rset;
294*2882Svi117747 	char			*rp;
295*2882Svi117747 	char			*rsp;
296*2882Svi117747 	int			count;
297*2882Svi117747 	sip_dlg_route_set_t	*route;
298*2882Svi117747 	boolean_t		first = B_TRUE;
299*2882Svi117747 	const sip_str_t		*to_uri;
300*2882Svi117747 	char			*uri = NULL;
301*2882Svi117747 	int			rspl;
302*2882Svi117747 	int			rpl;
303*2882Svi117747 
304*2882Svi117747 	assert(rcnt > 0);
305*2882Svi117747 
306*2882Svi117747 	dialog->sip_dlg_rset.sip_str_len = rlen + rcnt - 1;
307*2882Svi117747 	dialog->sip_dlg_rset.sip_str_ptr = malloc(rlen + rcnt);
308*2882Svi117747 	if (dialog->sip_dlg_rset.sip_str_ptr == NULL)
309*2882Svi117747 		return (ENOMEM);
310*2882Svi117747 	rsp = dialog->sip_dlg_rset.sip_str_ptr;
311*2882Svi117747 	rspl = rlen + rcnt;
312*2882Svi117747 	route = rset_head;
313*2882Svi117747 	rset_len = rlen;
314*2882Svi117747 	if (!route->sip_dlg_route_lr) {
315*2882Svi117747 		const struct sip_value	*val;
316*2882Svi117747 
317*2882Svi117747 		val = sip_get_header_value(dialog->sip_dlg_remote_target, NULL);
318*2882Svi117747 		to_uri = &((sip_hdr_value_t *)val)->cftr_uri;
319*2882Svi117747 		uri = (char *)malloc(to_uri->sip_str_len + 1);
320*2882Svi117747 		if (uri == NULL) {
321*2882Svi117747 			free(dialog->sip_dlg_rset.sip_str_ptr);
322*2882Svi117747 			dialog->sip_dlg_rset.sip_str_len = 0;
323*2882Svi117747 			dialog->sip_dlg_rset.sip_str_ptr = NULL;
324*2882Svi117747 			return (ENOMEM);
325*2882Svi117747 		}
326*2882Svi117747 		(void) strncpy(uri, to_uri->sip_str_ptr, to_uri->sip_str_len);
327*2882Svi117747 		uri[to_uri->sip_str_len] = '\0';
328*2882Svi117747 		rset_len = rlen - strlen(route->sip_dlg_route) + strlen(uri) +
329*2882Svi117747 		    SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN +
330*2882Svi117747 		    sizeof (char);
331*2882Svi117747 		count = snprintf(rsp, rspl, "%s", route->sip_dlg_route);
332*2882Svi117747 		dialog->sip_dlg_req_uri.sip_str_ptr = malloc(
333*2882Svi117747 		    route->sip_dlg_ruri.sip_str_len + 1);
334*2882Svi117747 		if (dialog->sip_dlg_req_uri.sip_str_ptr == NULL) {
335*2882Svi117747 			free(uri);
336*2882Svi117747 			free(dialog->sip_dlg_rset.sip_str_ptr);
337*2882Svi117747 			dialog->sip_dlg_rset.sip_str_len = 0;
338*2882Svi117747 			dialog->sip_dlg_rset.sip_str_ptr = NULL;
339*2882Svi117747 			return (ENOMEM);
340*2882Svi117747 		}
341*2882Svi117747 		(void) strncpy(dialog->sip_dlg_req_uri.sip_str_ptr, rsp +
342*2882Svi117747 		    (route->sip_dlg_ruri.sip_str_ptr - route->sip_dlg_route),
343*2882Svi117747 		    route->sip_dlg_ruri.sip_str_len);
344*2882Svi117747 		dialog->sip_dlg_req_uri.sip_str_ptr[
345*2882Svi117747 		    route->sip_dlg_ruri.sip_str_len] = '\0';
346*2882Svi117747 		dialog->sip_dlg_req_uri.sip_str_len =
347*2882Svi117747 		    route->sip_dlg_ruri.sip_str_len;
348*2882Svi117747 
349*2882Svi117747 		rsp += count;
350*2882Svi117747 		rspl -= count;
351*2882Svi117747 		route = route->sip_dlg_route_next;
352*2882Svi117747 	}
353*2882Svi117747 
354*2882Svi117747 	/*
355*2882Svi117747 	 * rcnt - 1 is for the number of COMMAs
356*2882Svi117747 	 */
357*2882Svi117747 	rset_len += strlen(SIP_ROUTE) + SIP_SPACE_LEN + sizeof (char) +
358*2882Svi117747 	    SIP_SPACE_LEN + rcnt - 1;
359*2882Svi117747 	rset = malloc(rset_len + 1);
360*2882Svi117747 	if (rset == NULL) {
361*2882Svi117747 		free(dialog->sip_dlg_rset.sip_str_ptr);
362*2882Svi117747 		dialog->sip_dlg_rset.sip_str_len = 0;
363*2882Svi117747 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
364*2882Svi117747 		return (ENOMEM);
365*2882Svi117747 	}
366*2882Svi117747 	rhdr = sip_new_header(rset_len + strlen(SIP_CRLF));
367*2882Svi117747 	if (rhdr == NULL) {
368*2882Svi117747 		free(rset);
369*2882Svi117747 		free(dialog->sip_dlg_rset.sip_str_ptr);
370*2882Svi117747 		dialog->sip_dlg_rset.sip_str_len = 0;
371*2882Svi117747 		dialog->sip_dlg_rset.sip_str_ptr = NULL;
372*2882Svi117747 		return (ENOMEM);
373*2882Svi117747 	}
374*2882Svi117747 
375*2882Svi117747 	rp = rset;
376*2882Svi117747 	rpl = rset_len + 1;
377*2882Svi117747 	count = snprintf(rp, rpl, "%s %c ", SIP_ROUTE, SIP_HCOLON);
378*2882Svi117747 	rp += count;
379*2882Svi117747 	rpl -= count;
380*2882Svi117747 
381*2882Svi117747 	while (route != NULL) {
382*2882Svi117747 		if (first) {
383*2882Svi117747 			count = snprintf(rp, rpl, "%s", route->sip_dlg_route);
384*2882Svi117747 			rp += count;
385*2882Svi117747 			rpl -= count;
386*2882Svi117747 			first = B_FALSE;
387*2882Svi117747 			if (uri != NULL) {
388*2882Svi117747 				count = snprintf(rsp, rspl, "%c%s",
389*2882Svi117747 				    SIP_COMMA, route->sip_dlg_route);
390*2882Svi117747 			} else {
391*2882Svi117747 				count = snprintf(rsp, rspl, "%s",
392*2882Svi117747 				    route->sip_dlg_route);
393*2882Svi117747 			}
394*2882Svi117747 			rsp += count;
395*2882Svi117747 			rspl -= count;
396*2882Svi117747 		} else {
397*2882Svi117747 			count = snprintf(rp, rpl, "%c%s", SIP_COMMA,
398*2882Svi117747 			    route->sip_dlg_route);
399*2882Svi117747 			rp += count;
400*2882Svi117747 			rpl -= count;
401*2882Svi117747 			count = snprintf(rsp, rspl, "%c%s", SIP_COMMA,
402*2882Svi117747 			    route->sip_dlg_route);
403*2882Svi117747 			rsp += count;
404*2882Svi117747 			rspl -= count;
405*2882Svi117747 		}
406*2882Svi117747 		route = route->sip_dlg_route_next;
407*2882Svi117747 	}
408*2882Svi117747 	assert(rsp <= dialog->sip_dlg_rset.sip_str_ptr +
409*2882Svi117747 	    dialog->sip_dlg_rset.sip_str_len);
410*2882Svi117747 	dialog->sip_dlg_rset.sip_str_ptr[dialog->sip_dlg_rset.sip_str_len] =
411*2882Svi117747 	    '\0';
412*2882Svi117747 	if (uri != NULL) {
413*2882Svi117747 		if (first) {
414*2882Svi117747 			count = snprintf(rp, rpl, "%c %s %c", SIP_LAQUOT,
415*2882Svi117747 			    uri, SIP_RAQUOT);
416*2882Svi117747 		} else {
417*2882Svi117747 			count = snprintf(rp, rpl, "%c%c %s %c", SIP_COMMA,
418*2882Svi117747 			    SIP_LAQUOT, uri, SIP_RAQUOT);
419*2882Svi117747 		}
420*2882Svi117747 		rp += count;
421*2882Svi117747 		rpl -= count;
422*2882Svi117747 		free(uri);
423*2882Svi117747 	}
424*2882Svi117747 	assert(rp <= rset + rset_len);
425*2882Svi117747 	(void) snprintf(rhdr->sip_hdr_start, rset_len + strlen(SIP_CRLF) + 1,
426*2882Svi117747 	    "%s%s", rset, SIP_CRLF);
427*2882Svi117747 	free(rset);
428*2882Svi117747 	dialog->sip_dlg_route_set = (sip_header_t)rhdr;
429*2882Svi117747 	sip_dialog_free_rset(rset_head);
430*2882Svi117747 	return (0);
431*2882Svi117747 }
432*2882Svi117747 
433*2882Svi117747 /*
434*2882Svi117747  * UAC Behavior
435*2882Svi117747  * The route set MUST be set to the list of URIs in the Record-Route
436*2882Svi117747  * header field from the response, taken in reverse order and preserving
437*2882Svi117747  * all URI parameters.
438*2882Svi117747  *
439*2882Svi117747  * UAS behavior
440*2882Svi117747  * The route set MUST be set to the list of URIs in the Record-Route
441*2882Svi117747  * header field from the request, taken in order and preserving all URI
442*2882Svi117747  * parameters.
443*2882Svi117747  */
444*2882Svi117747 static int
445*2882Svi117747 sip_dialog_get_route_set(_sip_dialog_t *dialog, _sip_msg_t *sip_msg, int what)
446*2882Svi117747 {
447*2882Svi117747 	sip_header_t		rrhdr;
448*2882Svi117747 	sip_hdr_value_t		*value;
449*2882Svi117747 	int			error;
450*2882Svi117747 	sip_dlg_route_set_t	*rset_head = NULL;
451*2882Svi117747 	sip_dlg_route_set_t	*rset_tail = NULL;
452*2882Svi117747 	sip_dlg_route_set_t	*rset;
453*2882Svi117747 	int			rset_cnt = 0;
454*2882Svi117747 	int			rset_len = 0;
455*2882Svi117747 
456*2882Svi117747 	(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
457*2882Svi117747 	rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, NULL);
458*2882Svi117747 	while (rrhdr != NULL) {
459*2882Svi117747 		(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
460*2882Svi117747 		value = (sip_hdr_value_t *)sip_get_header_value(rrhdr, &error);
461*2882Svi117747 		while (value != NULL && error == 0) {
462*2882Svi117747 			char	*crlf;
463*2882Svi117747 
464*2882Svi117747 			if (value->sip_value_state == SIP_VALUE_BAD) {
465*2882Svi117747 				value = (sip_hdr_value_t *)sip_get_next_value(
466*2882Svi117747 				    (sip_header_value_t)value, &error);
467*2882Svi117747 				continue;
468*2882Svi117747 			}
469*2882Svi117747 			rset = sip_add_route_to_set(value);
470*2882Svi117747 			if (rset == NULL)
471*2882Svi117747 				goto r_error;
472*2882Svi117747 			/*
473*2882Svi117747 			 * Add one for COMMA
474*2882Svi117747 			 */
475*2882Svi117747 			rset_cnt++;
476*2882Svi117747 			rset_len += (value->sip_value_end -
477*2882Svi117747 			    value->sip_value_start);
478*2882Svi117747 			/*
479*2882Svi117747 			 * Check for CRLF
480*2882Svi117747 			 */
481*2882Svi117747 			crlf = value->sip_value_end - strlen(SIP_CRLF);
482*2882Svi117747 			while (crlf != NULL &&
483*2882Svi117747 			    strncmp(crlf, SIP_CRLF, strlen(SIP_CRLF)) == 0) {
484*2882Svi117747 				rset_len -= strlen(SIP_CRLF);
485*2882Svi117747 				crlf -= strlen(SIP_CRLF);
486*2882Svi117747 			}
487*2882Svi117747 			if (rset_head == NULL) {
488*2882Svi117747 				assert(rset_tail == NULL);
489*2882Svi117747 				rset_head = rset_tail = rset;
490*2882Svi117747 			} else if (what == SIP_UAS_DIALOG) {
491*2882Svi117747 				rset_tail->sip_dlg_route_next = rset;
492*2882Svi117747 				rset_tail = rset;
493*2882Svi117747 			} else if (what == SIP_UAC_DIALOG) {
494*2882Svi117747 				rset->sip_dlg_route_next = rset_head;
495*2882Svi117747 				rset_head = rset;
496*2882Svi117747 			} else {
497*2882Svi117747 				assert(0);
498*2882Svi117747 			}
499*2882Svi117747 			value = (sip_hdr_value_t *)sip_get_next_value(
500*2882Svi117747 			    (sip_header_value_t)value, &error);
501*2882Svi117747 		}
502*2882Svi117747 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
503*2882Svi117747 		rrhdr = sip_search_for_header(sip_msg, SIP_RECORD_ROUTE, rrhdr);
504*2882Svi117747 	}
505*2882Svi117747 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
506*2882Svi117747 	if (rset_cnt == 0)
507*2882Svi117747 		return (0);
508*2882Svi117747 	if (sip_dialog_set_route_hdr(dialog, rset_head, rset_cnt,
509*2882Svi117747 	    rset_len) != 0) {
510*2882Svi117747 		goto r_error;
511*2882Svi117747 	}
512*2882Svi117747 	return (0);
513*2882Svi117747 r_error:
514*2882Svi117747 	sip_dialog_free_rset(rset_head);
515*2882Svi117747 	return (ENOMEM);
516*2882Svi117747 }
517*2882Svi117747 
518*2882Svi117747 /*
519*2882Svi117747  * UAS behavior:
520*2882Svi117747  * The remote sequence number MUST be set to the value of the sequence
521*2882Svi117747  * number in the CSeq header field of the request.  The local sequence
522*2882Svi117747  * number MUST be empty.  The call identifier component of the dialog ID
523*2882Svi117747  * MUST be set to the value of the Call-ID in the request.  The local
524*2882Svi117747  * tag component of the dialog ID MUST be set to the tag in the To field
525*2882Svi117747  * in the response to the request (which always includes a tag), and the
526*2882Svi117747  * remote tag component of the dialog ID MUST be set to the tag from the
527*2882Svi117747  * From field in the request.  A UAS MUST be prepared to receive a
528*2882Svi117747  * request without a tag in the From field, in which case the tag is
529*2882Svi117747  * considered to have a value of null.
530*2882Svi117747  * The remote URI MUST be set to the URI in the From field, and the
531*2882Svi117747  * local URI MUST be set to the URI in the To field.
532*2882Svi117747  * The remote target MUST be set to the URI from the Contact header field
533*2882Svi117747  * of the request.
534*2882Svi117747  *
535*2882Svi117747  * UAC behavior:
536*2882Svi117747  * The local sequence number MUST be set to the value of the sequence
537*2882Svi117747  * number in the CSeq header field of the request.  The remote sequence
538*2882Svi117747  * number MUST be empty (it is established when the remote UA sends a
539*2882Svi117747  * request within the dialog).  The call identifier component of the
540*2882Svi117747  * dialog ID MUST be set to the value of the Call-ID in the request.
541*2882Svi117747  * The local tag component of the dialog ID MUST be set to the tag in
542*2882Svi117747  * the From field in the request, and the remote tag component of the
543*2882Svi117747  * dialog ID MUST be set to the tag in the To field of the response.  A
544*2882Svi117747  * UAC MUST be prepared to receive a response without a tag in the To
545*2882Svi117747  * field, in which case the tag is considered to have a value of null.
546*2882Svi117747  * The remote URI MUST be set to the URI in the To field, and the local
547*2882Svi117747  * URI MUST be set to the URI in the From field.
548*2882Svi117747  * The remote target MUST be set to the URI from the Contact header field
549*2882Svi117747  * of the response.
550*2882Svi117747  */
551*2882Svi117747 
552*2882Svi117747 
553*2882Svi117747 /*
554*2882Svi117747  * This is the routine that seeds a dialog.
555*2882Svi117747  */
556*2882Svi117747 sip_dialog_t
557*2882Svi117747 sip_seed_dialog(sip_conn_object_t obj, _sip_msg_t *sip_msg,
558*2882Svi117747     boolean_t dlg_on_fork, int dlg_type)
559*2882Svi117747 {
560*2882Svi117747 	_sip_dialog_t		*dialog;
561*2882Svi117747 	int			cseq;
562*2882Svi117747 	sip_header_t		fhdr = NULL;
563*2882Svi117747 	sip_header_t		thdr = NULL;
564*2882Svi117747 	sip_header_t		chdr;
565*2882Svi117747 	sip_header_t		cihdr;
566*2882Svi117747 	sip_header_t		evhdr = NULL;
567*2882Svi117747 	const struct sip_value	*value;
568*2882Svi117747 	sip_dialog_timer_obj_t	*tim_obj = NULL;
569*2882Svi117747 	const sip_str_t		*callid;
570*2882Svi117747 	sip_method_t		method;
571*2882Svi117747 	int			timer1 = sip_timer_T1;
572*2882Svi117747 	int			error;
573*2882Svi117747 
574*2882Svi117747 	if (!sip_msg_is_request((sip_msg_t)sip_msg, &error))
575*2882Svi117747 		return (NULL);
576*2882Svi117747 
577*2882Svi117747 	method = sip_get_request_method((sip_msg_t)sip_msg, &error);
578*2882Svi117747 	/*
579*2882Svi117747 	 * Only INVITE and SUBSCRIBE supported
580*2882Svi117747 	 */
581*2882Svi117747 	if (error != 0 || (method != INVITE && method != SUBSCRIBE))
582*2882Svi117747 		return (NULL);
583*2882Svi117747 
584*2882Svi117747 	/*
585*2882Svi117747 	 * A request outside of a dialog MUST NOT contain a To tag
586*2882Svi117747 	 */
587*2882Svi117747 	if (sip_get_to_tag((sip_msg_t)sip_msg, NULL) != NULL)
588*2882Svi117747 		return (NULL);
589*2882Svi117747 
590*2882Svi117747 	if (dlg_type == SIP_UAS_DIALOG) {
591*2882Svi117747 		thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg,
592*2882Svi117747 		    SIP_DLG_XCHG_FROM);
593*2882Svi117747 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
594*2882Svi117747 	} else {
595*2882Svi117747 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
596*2882Svi117747 		fhdr = sip_search_for_header(sip_msg, SIP_FROM, NULL);
597*2882Svi117747 	}
598*2882Svi117747 	cihdr = sip_search_for_header(sip_msg, SIP_CALL_ID, NULL);
599*2882Svi117747 	chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
600*2882Svi117747 	if (method == SUBSCRIBE)
601*2882Svi117747 		evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL);
602*2882Svi117747 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
603*2882Svi117747 	if ((fhdr == NULL && thdr == NULL) || cihdr == NULL || chdr == NULL ||
604*2882Svi117747 	    (method == SUBSCRIBE && evhdr == NULL)) {
605*2882Svi117747 		if (thdr != NULL)
606*2882Svi117747 			sip_free_header(thdr);
607*2882Svi117747 		return (NULL);
608*2882Svi117747 	}
609*2882Svi117747 
610*2882Svi117747 	/*
611*2882Svi117747 	 * Sanity check since we just store the headers in the dialog
612*2882Svi117747 	 */
613*2882Svi117747 	if (sip_get_from_tag((sip_msg_t)sip_msg, NULL) == NULL ||
614*2882Svi117747 	    sip_get_from_uri_str((sip_msg_t)sip_msg, NULL) == NULL ||
615*2882Svi117747 	    ((cseq = sip_get_callseq_num((sip_msg_t)sip_msg, NULL)) == -1) ||
616*2882Svi117747 	    (callid = sip_get_callid((sip_msg_t)sip_msg, NULL)) == NULL ||
617*2882Svi117747 	    sip_get_to_uri_str((sip_msg_t)sip_msg, NULL) == NULL ||
618*2882Svi117747 	    ((value = sip_get_header_value(chdr, NULL)) == NULL) ||
619*2882Svi117747 	    sip_get_contact_uri_str((sip_header_value_t)value, NULL) == NULL) {
620*2882Svi117747 		if (thdr != NULL)
621*2882Svi117747 			sip_free_header(thdr);
622*2882Svi117747 		return (NULL);
623*2882Svi117747 	}
624*2882Svi117747 
625*2882Svi117747 	tim_obj = calloc(1, sizeof (sip_dialog_timer_obj_t));
626*2882Svi117747 	if (tim_obj == NULL) {
627*2882Svi117747 		if (thdr != NULL)
628*2882Svi117747 			sip_free_header(thdr);
629*2882Svi117747 		return (NULL);
630*2882Svi117747 	}
631*2882Svi117747 	dialog = calloc(1, sizeof (_sip_dialog_t));
632*2882Svi117747 	if (dialog == NULL) {
633*2882Svi117747 		if (thdr != NULL)
634*2882Svi117747 			sip_free_header(thdr);
635*2882Svi117747 		return (NULL);
636*2882Svi117747 	}
637*2882Svi117747 	/*
638*2882Svi117747 	 * We will take the TO header with the tag when we complete this
639*2882Svi117747 	 * dialog
640*2882Svi117747 	 */
641*2882Svi117747 	if (dlg_type == SIP_UAS_DIALOG) {
642*2882Svi117747 		dialog->sip_dlg_remote_uri_tag = thdr;
643*2882Svi117747 		/*
644*2882Svi117747 		 * We take the remote target from the incoming request on the
645*2882Svi117747 		 * UAS. For the UAC, we will take it from the response.
646*2882Svi117747 		 */
647*2882Svi117747 		if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) ==
648*2882Svi117747 		    NULL) {
649*2882Svi117747 			goto dia_err;
650*2882Svi117747 		}
651*2882Svi117747 	} else {
652*2882Svi117747 		if ((dialog->sip_dlg_local_uri_tag = sip_dup_header(fhdr)) ==
653*2882Svi117747 		    NULL) {
654*2882Svi117747 			goto dia_err;
655*2882Svi117747 		}
656*2882Svi117747 	}
657*2882Svi117747 	if ((dialog->sip_dlg_call_id = sip_dup_header(cihdr)) == NULL)
658*2882Svi117747 		goto dia_err;
659*2882Svi117747 	if (method == SUBSCRIBE) {
660*2882Svi117747 		dialog->sip_dlg_event = sip_dup_header(evhdr);
661*2882Svi117747 		if (dialog->sip_dlg_event == NULL) {
662*2882Svi117747 			goto dia_err;
663*2882Svi117747 		}
664*2882Svi117747 	}
665*2882Svi117747 	dialog->sip_dlg_rset.sip_str_ptr = NULL;
666*2882Svi117747 	dialog->sip_dlg_rset.sip_str_len = 0;
667*2882Svi117747 	dialog->sip_dlg_req_uri.sip_str_ptr = NULL;
668*2882Svi117747 	dialog->sip_dlg_req_uri.sip_str_len = 0;
669*2882Svi117747 	/*
670*2882Svi117747 	 * Get the route set from the request, if present
671*2882Svi117747 	 */
672*2882Svi117747 	if (dlg_type == SIP_UAS_DIALOG &&
673*2882Svi117747 	    sip_dialog_get_route_set(dialog, sip_msg, dlg_type) != 0) {
674*2882Svi117747 		goto dia_err;
675*2882Svi117747 	}
676*2882Svi117747 	if (dlg_type == SIP_UAC_DIALOG)
677*2882Svi117747 		dialog->sip_dlg_local_cseq = cseq;
678*2882Svi117747 	else
679*2882Svi117747 		dialog->sip_dlg_remote_cseq = cseq;
680*2882Svi117747 	dialog->sip_dlg_type = dlg_type;
681*2882Svi117747 	dialog->sip_dlg_on_fork = dlg_on_fork;
682*2882Svi117747 	dialog->sip_dlg_method = method;
683*2882Svi117747 	/*
684*2882Svi117747 	 * Set the partial dialog timer with the INVITE timeout val
685*2882Svi117747 	 */
686*2882Svi117747 	if (sip_conn_timer1 != NULL)
687*2882Svi117747 		timer1 = sip_conn_timer1(obj);
688*2882Svi117747 	SIP_INIT_TIMER(dialog->sip_dlg_timer, 64 * timer1);
689*2882Svi117747 	tim_obj->dialog = dialog;
690*2882Svi117747 	/*
691*2882Svi117747 	 * Since at the client we never pass the partial dialog, we need not
692*2882Svi117747 	 * invoke the callback when the partial dialog self-destructs.
693*2882Svi117747 	 */
694*2882Svi117747 	if (dlg_type == SIP_UAS_DIALOG)
695*2882Svi117747 		tim_obj->func = sip_ulp_dlg_del_cb;
696*2882Svi117747 	SIP_SCHED_TIMER(dialog->sip_dlg_timer, (void *)tim_obj,
697*2882Svi117747 	    sip_dlg_self_destruct);
698*2882Svi117747 	if (!SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
699*2882Svi117747 		goto dia_err;
700*2882Svi117747 	(void) pthread_mutex_init(&dialog->sip_dlg_mutex, NULL);
701*2882Svi117747 
702*2882Svi117747 	if (dlg_type == SIP_UAC_DIALOG) {
703*2882Svi117747 		const sip_str_t	*local_tag;
704*2882Svi117747 
705*2882Svi117747 		local_tag = sip_get_from_tag((sip_msg_t)sip_msg, NULL);
706*2882Svi117747 		assert(local_tag != NULL);
707*2882Svi117747 		sip_md5_hash(local_tag->sip_str_ptr, local_tag->sip_str_len,
708*2882Svi117747 		    callid->sip_str_ptr, callid->sip_str_len,
709*2882Svi117747 		    NULL, 0, NULL, 0, NULL, 0, NULL, 0,
710*2882Svi117747 		    (uchar_t *)dialog->sip_dlg_id);
711*2882Svi117747 
712*2882Svi117747 
713*2882Svi117747 		/*
714*2882Svi117747 		 * Add it to the partial hash table
715*2882Svi117747 		 */
716*2882Svi117747 		if (sip_hash_add(sip_dialog_phash, (void *)dialog,
717*2882Svi117747 		    SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) {
718*2882Svi117747 			goto dia_err;
719*2882Svi117747 		}
720*2882Svi117747 	}
721*2882Svi117747 	SIP_DLG_REFCNT_INCR(dialog);
722*2882Svi117747 	return ((sip_dialog_t)dialog);
723*2882Svi117747 dia_err:
724*2882Svi117747 	sip_release_dialog_res(dialog);
725*2882Svi117747 	if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
726*2882Svi117747 		SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
727*2882Svi117747 	if (tim_obj != NULL)
728*2882Svi117747 		free(tim_obj);
729*2882Svi117747 	return (NULL);
730*2882Svi117747 }
731*2882Svi117747 
732*2882Svi117747 /*
733*2882Svi117747  * When creating a dialog from a NOTIFY request, we need to get the FROM
734*2882Svi117747  * header for the dialog from the TO header of the NOTIFY.
735*2882Svi117747  */
736*2882Svi117747 _sip_header_t *
737*2882Svi117747 sip_dlg_xchg_from_to(sip_msg_t sip_msg, int what)
738*2882Svi117747 {
739*2882Svi117747 	int			len;
740*2882Svi117747 	_sip_header_t		*newhdr;
741*2882Svi117747 	int			cnt;
742*2882Svi117747 	const struct sip_header	*hdr;
743*2882Svi117747 	int			hdrsize;
744*2882Svi117747 	int			error;
745*2882Svi117747 
746*2882Svi117747 	hdr = sip_get_header(sip_msg, what == SIP_DLG_XCHG_FROM ? SIP_FROM :
747*2882Svi117747 	    SIP_TO, NULL, &error);
748*2882Svi117747 	if (error != 0 || hdr == NULL)
749*2882Svi117747 		return (NULL);
750*2882Svi117747 	if (sip_parse_goto_values((_sip_header_t *)hdr) != 0)
751*2882Svi117747 		return (NULL);
752*2882Svi117747 	len = hdr->sip_hdr_end - hdr->sip_hdr_current;
753*2882Svi117747 	if (what == SIP_DLG_XCHG_FROM) {
754*2882Svi117747 		hdrsize = len + strlen(SIP_TO) + SIP_SPACE_LEN + sizeof (char) +
755*2882Svi117747 		    SIP_SPACE_LEN;
756*2882Svi117747 	} else {
757*2882Svi117747 		hdrsize = len + strlen(SIP_FROM) + SIP_SPACE_LEN +
758*2882Svi117747 		    sizeof (char) + SIP_SPACE_LEN;
759*2882Svi117747 	}
760*2882Svi117747 	newhdr = sip_new_header(hdrsize);
761*2882Svi117747 	if (newhdr == NULL)
762*2882Svi117747 		return (NULL);
763*2882Svi117747 	if (what == SIP_DLG_XCHG_FROM) {
764*2882Svi117747 		cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1,
765*2882Svi117747 		    "%s %c ", SIP_TO, SIP_HCOLON);
766*2882Svi117747 	} else {
767*2882Svi117747 		cnt = snprintf(newhdr->sip_hdr_current, hdrsize + 1,
768*2882Svi117747 		    "%s %c ", SIP_FROM, SIP_HCOLON);
769*2882Svi117747 	}
770*2882Svi117747 	newhdr->sip_hdr_current += cnt;
771*2882Svi117747 	(void) strncpy(newhdr->sip_hdr_current, hdr->sip_hdr_current, len);
772*2882Svi117747 	newhdr->sip_hdr_current += len;
773*2882Svi117747 	assert(newhdr->sip_hdr_current == newhdr->sip_hdr_end);
774*2882Svi117747 	assert(hdr->sip_header_functions != NULL);
775*2882Svi117747 
776*2882Svi117747 	/*
777*2882Svi117747 	 * FROM and TO have common parsing functions
778*2882Svi117747 	 */
779*2882Svi117747 	newhdr->sip_header_functions = hdr->sip_header_functions;
780*2882Svi117747 	newhdr->sip_hdr_current = newhdr->sip_hdr_start;
781*2882Svi117747 
782*2882Svi117747 	return (newhdr);
783*2882Svi117747 }
784*2882Svi117747 
785*2882Svi117747 /*
786*2882Svi117747  * This is the response that completes the dialog that was created
787*2882Svi117747  * in sip_seed_dialog().
788*2882Svi117747  */
789*2882Svi117747 sip_dialog_t
790*2882Svi117747 sip_complete_dialog(_sip_msg_t *sip_msg, _sip_dialog_t *dialog)
791*2882Svi117747 {
792*2882Svi117747 	_sip_header_t		*thdr;
793*2882Svi117747 	_sip_header_t		*evhdr = NULL;
794*2882Svi117747 	_sip_header_t		*substate = NULL;
795*2882Svi117747 	sip_header_t		chdr = NULL;
796*2882Svi117747 	int			resp_code;
797*2882Svi117747 	const sip_str_t		*ttag;
798*2882Svi117747 	const sip_str_t		*remtag;
799*2882Svi117747 	const sip_str_t		*callid;
800*2882Svi117747 	const struct sip_value 	*val;
801*2882Svi117747 	sip_method_t		method;
802*2882Svi117747 	int			error = 0;
803*2882Svi117747 	int			prev_state;
804*2882Svi117747 	boolean_t		alloc_thdr = B_FALSE;
805*2882Svi117747 
806*2882Svi117747 	if (sip_msg_is_request((sip_msg_t)sip_msg, &error) && error == 0)
807*2882Svi117747 		method = sip_get_request_method((sip_msg_t)sip_msg, &error);
808*2882Svi117747 	else
809*2882Svi117747 		method = sip_get_callseq_method((sip_msg_t)sip_msg, &error);
810*2882Svi117747 	if (error != 0 || dialog == NULL ||
811*2882Svi117747 	    (sip_msg_is_request((sip_msg_t)sip_msg, &error) &&
812*2882Svi117747 	    (dialog->sip_dlg_method == INVITE || method != NOTIFY))) {
813*2882Svi117747 		return (NULL);
814*2882Svi117747 	}
815*2882Svi117747 	if ((dialog->sip_dlg_type == SIP_UAC_DIALOG && method != NOTIFY &&
816*2882Svi117747 	    sip_get_callseq_num((sip_msg_t)sip_msg, NULL) !=
817*2882Svi117747 	    dialog->sip_dlg_local_cseq) ||
818*2882Svi117747 	    (dialog->sip_dlg_type == SIP_UAS_DIALOG && method != NOTIFY &&
819*2882Svi117747 	    sip_get_callseq_num((sip_msg_t)sip_msg, NULL) !=
820*2882Svi117747 	    dialog->sip_dlg_remote_cseq)) {
821*2882Svi117747 		return (NULL);
822*2882Svi117747 	}
823*2882Svi117747 	if (method == NOTIFY) {
824*2882Svi117747 		const sip_str_t	*sstate;
825*2882Svi117747 
826*2882Svi117747 		thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg,
827*2882Svi117747 		    SIP_DLG_XCHG_FROM);
828*2882Svi117747 		if (thdr == NULL)
829*2882Svi117747 			return (NULL);
830*2882Svi117747 		alloc_thdr = B_TRUE;
831*2882Svi117747 		(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
832*2882Svi117747 		chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
833*2882Svi117747 		if (chdr == NULL) {
834*2882Svi117747 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
835*2882Svi117747 			sip_free_header(thdr);
836*2882Svi117747 			return (NULL);
837*2882Svi117747 		}
838*2882Svi117747 		evhdr = sip_search_for_header(sip_msg, SIP_EVENT, NULL);
839*2882Svi117747 		if (evhdr == NULL) {
840*2882Svi117747 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
841*2882Svi117747 			sip_free_header(thdr);
842*2882Svi117747 			return (NULL);
843*2882Svi117747 		}
844*2882Svi117747 		substate = sip_search_for_header(sip_msg,
845*2882Svi117747 		    SIP_SUBSCRIPTION_STATE, NULL);
846*2882Svi117747 		if (substate == NULL) {
847*2882Svi117747 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
848*2882Svi117747 			sip_free_header(thdr);
849*2882Svi117747 			return (NULL);
850*2882Svi117747 		}
851*2882Svi117747 		(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
852*2882Svi117747 		sstate = sip_get_substate((sip_msg_t)sip_msg, &error);
853*2882Svi117747 		if (sstate == NULL || error != 0) {
854*2882Svi117747 			sip_free_header(thdr);
855*2882Svi117747 			return (NULL);
856*2882Svi117747 		}
857*2882Svi117747 		if ((sstate->sip_str_len != strlen("pending") &&
858*2882Svi117747 		    sstate->sip_str_len != strlen("active")) ||
859*2882Svi117747 		    ((sstate->sip_str_len == strlen("pending") &&
860*2882Svi117747 		    strncasecmp(sstate->sip_str_ptr, "pending",
861*2882Svi117747 		    strlen("pending")) != 0) ||
862*2882Svi117747 		    (sstate->sip_str_len == strlen("active") &&
863*2882Svi117747 		    strncasecmp(sstate->sip_str_ptr, "active",
864*2882Svi117747 		    strlen("active")) != 0))) {
865*2882Svi117747 			sip_free_header(thdr);
866*2882Svi117747 			return (NULL);
867*2882Svi117747 		}
868*2882Svi117747 		ttag = sip_get_from_tag((sip_msg_t)sip_msg, NULL);
869*2882Svi117747 	} else {
870*2882Svi117747 		if (dialog->sip_dlg_type == SIP_UAS_DIALOG) {
871*2882Svi117747 			thdr = sip_dlg_xchg_from_to((sip_msg_t)sip_msg,
872*2882Svi117747 			    SIP_DLG_XCHG_TO);
873*2882Svi117747 			alloc_thdr = B_TRUE;
874*2882Svi117747 		} else {
875*2882Svi117747 			(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
876*2882Svi117747 			thdr = sip_search_for_header(sip_msg, SIP_TO, NULL);
877*2882Svi117747 			if (dialog->sip_dlg_remote_target == NULL) {
878*2882Svi117747 				chdr = sip_search_for_header(sip_msg,
879*2882Svi117747 				    SIP_CONTACT, NULL);
880*2882Svi117747 			}
881*2882Svi117747 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
882*2882Svi117747 		}
883*2882Svi117747 		if (thdr == NULL) {
884*2882Svi117747 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
885*2882Svi117747 			return (NULL);
886*2882Svi117747 		}
887*2882Svi117747 		ttag = sip_get_to_tag((sip_msg_t)sip_msg, NULL);
888*2882Svi117747 	}
889*2882Svi117747 	if (ttag == NULL) {
890*2882Svi117747 		if (alloc_thdr)
891*2882Svi117747 			sip_free_header(thdr);
892*2882Svi117747 		return (NULL);
893*2882Svi117747 	}
894*2882Svi117747 	prev_state = dialog->sip_dlg_state;
895*2882Svi117747 
896*2882Svi117747 	if (method == NOTIFY) {
897*2882Svi117747 		int			error;
898*2882Svi117747 		const sip_str_t		*dlg_id_val = NULL;
899*2882Svi117747 		const sip_str_t		*event;
900*2882Svi117747 		const sip_str_t		*id_val = NULL;
901*2882Svi117747 		sip_header_value_t	ev_val;
902*2882Svi117747 		sip_hdr_value_t		*dlg_ev_val = NULL;
903*2882Svi117747 
904*2882Svi117747 		event = sip_get_event((sip_msg_t)sip_msg, &error);
905*2882Svi117747 		if (event == NULL || error != 0) {
906*2882Svi117747 			sip_free_header(thdr);
907*2882Svi117747 			return (NULL);
908*2882Svi117747 		}
909*2882Svi117747 		ev_val = (sip_header_value_t)sip_get_header_value(evhdr,
910*2882Svi117747 		    &error);
911*2882Svi117747 		if (ev_val != NULL)
912*2882Svi117747 			id_val = sip_get_param_value(ev_val, "id", &error);
913*2882Svi117747 		if (error == 0) {
914*2882Svi117747 			dlg_ev_val = (sip_hdr_value_t *)sip_get_header_value(
915*2882Svi117747 			    dialog->sip_dlg_event, &error);
916*2882Svi117747 		}
917*2882Svi117747 		if (dlg_ev_val == NULL || error != 0) {
918*2882Svi117747 			sip_free_header(thdr);
919*2882Svi117747 			return (NULL);
920*2882Svi117747 		}
921*2882Svi117747 		dlg_id_val = sip_get_param_value((sip_header_value_t)dlg_ev_val,
922*2882Svi117747 		    "id", &error);
923*2882Svi117747 		if (error != 0 ||
924*2882Svi117747 		    dlg_ev_val->str_val_len != event->sip_str_len ||
925*2882Svi117747 		    strncmp(dlg_ev_val->str_val_ptr, event->sip_str_ptr,
926*2882Svi117747 		    event->sip_str_len != 0)) {
927*2882Svi117747 			sip_free_header(thdr);
928*2882Svi117747 			return (NULL);
929*2882Svi117747 		}
930*2882Svi117747 		if ((dlg_id_val == NULL && id_val != NULL) ||
931*2882Svi117747 		    (dlg_id_val != NULL && id_val == NULL)) {
932*2882Svi117747 			sip_free_header(thdr);
933*2882Svi117747 			return (NULL);
934*2882Svi117747 		} else if (dlg_id_val != NULL && id_val != NULL) {
935*2882Svi117747 			if (dlg_id_val->sip_str_len != id_val->sip_str_len ||
936*2882Svi117747 			    strncasecmp(dlg_id_val->sip_str_ptr,
937*2882Svi117747 			    id_val->sip_str_ptr, dlg_id_val->sip_str_len) !=
938*2882Svi117747 			    0) {
939*2882Svi117747 				sip_free_header(thdr);
940*2882Svi117747 				return (NULL);
941*2882Svi117747 			}
942*2882Svi117747 		}
943*2882Svi117747 		if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
944*2882Svi117747 			dialog->sip_dlg_remote_uri_tag = thdr;
945*2882Svi117747 			if ((dialog->sip_dlg_remote_target =
946*2882Svi117747 			    sip_dup_header(chdr)) == NULL) {
947*2882Svi117747 				sip_free_header(thdr);
948*2882Svi117747 				return (NULL);
949*2882Svi117747 			}
950*2882Svi117747 		} else {
951*2882Svi117747 			dialog->sip_dlg_local_uri_tag = thdr;
952*2882Svi117747 		}
953*2882Svi117747 		dialog->sip_dlg_state = SIP_DLG_CONFIRMED;
954*2882Svi117747 	} else {
955*2882Svi117747 		resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
956*2882Svi117747 		(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
957*2882Svi117747 		assert(dialog->sip_dlg_state == SIP_DLG_NEW);
958*2882Svi117747 		if (dialog->sip_dlg_remote_target == NULL && chdr != NULL) {
959*2882Svi117747 			assert(dialog->sip_dlg_type == SIP_UAC_DIALOG);
960*2882Svi117747 			if ((dialog->sip_dlg_remote_target =
961*2882Svi117747 			    sip_dup_header(chdr)) == NULL) {
962*2882Svi117747 				(void) pthread_mutex_unlock(
963*2882Svi117747 				    &dialog->sip_dlg_mutex);
964*2882Svi117747 				sip_dialog_terminate(dialog,
965*2882Svi117747 				    (sip_msg_t)sip_msg);
966*2882Svi117747 				if (alloc_thdr)
967*2882Svi117747 					sip_free_header(thdr);
968*2882Svi117747 				return (NULL);
969*2882Svi117747 			}
970*2882Svi117747 			if (sip_dialog_get_route_set(dialog, sip_msg,
971*2882Svi117747 			    dialog->sip_dlg_type) != 0) {
972*2882Svi117747 				(void) pthread_mutex_unlock(
973*2882Svi117747 				    &dialog->sip_dlg_mutex);
974*2882Svi117747 				sip_dialog_terminate(dialog,
975*2882Svi117747 				    (sip_msg_t)sip_msg);
976*2882Svi117747 				if (alloc_thdr)
977*2882Svi117747 					sip_free_header(thdr);
978*2882Svi117747 				return (NULL);
979*2882Svi117747 			}
980*2882Svi117747 		}
981*2882Svi117747 		if (SIP_PROVISIONAL_RESP(resp_code)) {
982*2882Svi117747 			dialog->sip_dlg_state = SIP_DLG_EARLY;
983*2882Svi117747 		} else if (SIP_OK_RESP(resp_code)) {
984*2882Svi117747 			/*
985*2882Svi117747 			 * Per 12.1 the UAS must include the contact header
986*2882Svi117747 			 * for a dialog establishing response, so if we
987*2882Svi117747 			 * don't find one, we terminate it.
988*2882Svi117747 			 */
989*2882Svi117747 			if (dialog->sip_dlg_remote_target == NULL) {
990*2882Svi117747 				(void) pthread_mutex_unlock(
991*2882Svi117747 				    &dialog->sip_dlg_mutex);
992*2882Svi117747 				if (sip_ulp_dlg_del_cb != NULL) {
993*2882Svi117747 					sip_ulp_dlg_del_cb(dialog,
994*2882Svi117747 					    (sip_msg_t)sip_msg, NULL);
995*2882Svi117747 				}
996*2882Svi117747 				sip_dialog_terminate(dialog,
997*2882Svi117747 				    (sip_msg_t)sip_msg);
998*2882Svi117747 				if (alloc_thdr)
999*2882Svi117747 					sip_free_header(thdr);
1000*2882Svi117747 				return (NULL);
1001*2882Svi117747 			}
1002*2882Svi117747 			dialog->sip_dlg_state = SIP_DLG_CONFIRMED;
1003*2882Svi117747 		} else {
1004*2882Svi117747 			(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1005*2882Svi117747 			if (sip_ulp_dlg_del_cb != NULL) {
1006*2882Svi117747 				sip_ulp_dlg_del_cb(dialog, (sip_msg_t)sip_msg,
1007*2882Svi117747 				    NULL);
1008*2882Svi117747 			}
1009*2882Svi117747 			sip_dialog_terminate(dialog, (sip_msg_t)sip_msg);
1010*2882Svi117747 			if (alloc_thdr)
1011*2882Svi117747 				sip_free_header(thdr);
1012*2882Svi117747 			return (NULL);
1013*2882Svi117747 		}
1014*2882Svi117747 		if (dialog->sip_dlg_type == SIP_UAS_DIALOG) {
1015*2882Svi117747 			dialog->sip_dlg_local_uri_tag = thdr;
1016*2882Svi117747 		} else {
1017*2882Svi117747 			if ((dialog->sip_dlg_remote_uri_tag =
1018*2882Svi117747 			    sip_dup_header(thdr)) == NULL) {
1019*2882Svi117747 				(void) pthread_mutex_unlock(
1020*2882Svi117747 				    &dialog->sip_dlg_mutex);
1021*2882Svi117747 				sip_dialog_terminate(dialog,
1022*2882Svi117747 				    (sip_msg_t)sip_msg);
1023*2882Svi117747 				return (NULL);
1024*2882Svi117747 			}
1025*2882Svi117747 		}
1026*2882Svi117747 	}
1027*2882Svi117747 
1028*2882Svi117747 	/*
1029*2882Svi117747 	 * Cancel the partial dialog timer
1030*2882Svi117747 	 */
1031*2882Svi117747 	if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
1032*2882Svi117747 		SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
1033*2882Svi117747 
1034*2882Svi117747 	if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
1035*2882Svi117747 		val =  sip_get_header_value(dialog->sip_dlg_local_uri_tag,
1036*2882Svi117747 		    &error);
1037*2882Svi117747 	} else {
1038*2882Svi117747 		val =  sip_get_header_value(dialog->sip_dlg_remote_uri_tag,
1039*2882Svi117747 		    &error);
1040*2882Svi117747 	}
1041*2882Svi117747 	assert(val != NULL && error == 0);
1042*2882Svi117747 	remtag = sip_get_param_value((sip_header_value_t)val, "tag", &error);
1043*2882Svi117747 
1044*2882Svi117747 	val = sip_get_header_value(dialog->sip_dlg_call_id, &error);
1045*2882Svi117747 	callid = &((sip_hdr_value_t *)val)->str_val;
1046*2882Svi117747 
1047*2882Svi117747 	/*
1048*2882Svi117747 	 * Get an ID for this dialog
1049*2882Svi117747 	 */
1050*2882Svi117747 	if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
1051*2882Svi117747 		sip_md5_hash(remtag->sip_str_ptr, remtag->sip_str_len,
1052*2882Svi117747 		    ttag->sip_str_ptr, ttag->sip_str_len,
1053*2882Svi117747 		    callid->sip_str_ptr, callid->sip_str_len,
1054*2882Svi117747 		    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id);
1055*2882Svi117747 	} else {
1056*2882Svi117747 		sip_md5_hash(ttag->sip_str_ptr, ttag->sip_str_len,
1057*2882Svi117747 		    remtag->sip_str_ptr, remtag->sip_str_len,
1058*2882Svi117747 		    callid->sip_str_ptr, callid->sip_str_len,
1059*2882Svi117747 		    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)dialog->sip_dlg_id);
1060*2882Svi117747 	}
1061*2882Svi117747 
1062*2882Svi117747 	SIP_DLG_REFCNT_INCR(dialog);
1063*2882Svi117747 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1064*2882Svi117747 
1065*2882Svi117747 	/*
1066*2882Svi117747 	 * Add it to the hash table
1067*2882Svi117747 	 */
1068*2882Svi117747 	if (sip_hash_add(sip_dialog_hash, (void *)dialog,
1069*2882Svi117747 	    SIP_DIGEST_TO_HASH(dialog->sip_dlg_id)) != 0) {
1070*2882Svi117747 		/*
1071*2882Svi117747 		 * So that sip_dialog_delete() does not try to remove
1072*2882Svi117747 		 * this from the hash table.
1073*2882Svi117747 		 */
1074*2882Svi117747 		(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
1075*2882Svi117747 		if (dialog->sip_dlg_type == SIP_UAS_DIALOG) {
1076*2882Svi117747 			sip_free_header(dialog->sip_dlg_local_uri_tag);
1077*2882Svi117747 			dialog->sip_dlg_local_uri_tag = NULL;
1078*2882Svi117747 		} else {
1079*2882Svi117747 			sip_free_header(dialog->sip_dlg_remote_uri_tag);
1080*2882Svi117747 			dialog->sip_dlg_remote_uri_tag = NULL;
1081*2882Svi117747 		}
1082*2882Svi117747 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1083*2882Svi117747 		sip_dialog_terminate(dialog, (sip_msg_t)sip_msg);
1084*2882Svi117747 		return (NULL);
1085*2882Svi117747 	}
1086*2882Svi117747 	if (sip_dlg_ulp_state_cb != NULL) {
1087*2882Svi117747 		sip_dlg_ulp_state_cb((sip_dialog_t)dialog,
1088*2882Svi117747 		    (sip_msg_t)sip_msg, prev_state, dialog->sip_dlg_state);
1089*2882Svi117747 	}
1090*2882Svi117747 	return ((sip_dialog_t)dialog);
1091*2882Svi117747 }
1092*2882Svi117747 
1093*2882Svi117747 /*
1094*2882Svi117747  * Check if this dialog is a match.
1095*2882Svi117747  */
1096*2882Svi117747 boolean_t
1097*2882Svi117747 sip_dialog_match(void *obj, void *hindex)
1098*2882Svi117747 {
1099*2882Svi117747 	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
1100*2882Svi117747 
1101*2882Svi117747 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
1102*2882Svi117747 	if (dialog->sip_dlg_state == SIP_DLG_DESTROYED) {
1103*2882Svi117747 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1104*2882Svi117747 		return (B_FALSE);
1105*2882Svi117747 	}
1106*2882Svi117747 	if (bcmp(dialog->sip_dlg_id, hindex,
1107*2882Svi117747 	    sizeof (dialog->sip_dlg_id)) == 0) {
1108*2882Svi117747 		SIP_DLG_REFCNT_INCR(dialog);
1109*2882Svi117747 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1110*2882Svi117747 		return (B_TRUE);
1111*2882Svi117747 	}
1112*2882Svi117747 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1113*2882Svi117747 	return (B_FALSE);
1114*2882Svi117747 }
1115*2882Svi117747 
1116*2882Svi117747 /*
1117*2882Svi117747  * Don't delete, just take it out of the hash
1118*2882Svi117747  */
1119*2882Svi117747 boolean_t
1120*2882Svi117747 sip_dialog_dontfree(void *obj, void *hindex, int *found)
1121*2882Svi117747 {
1122*2882Svi117747 	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
1123*2882Svi117747 
1124*2882Svi117747 	*found = 0;
1125*2882Svi117747 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
1126*2882Svi117747 	if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id))
1127*2882Svi117747 	    == 0) {
1128*2882Svi117747 		*found = 1;
1129*2882Svi117747 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1130*2882Svi117747 		return (B_TRUE);
1131*2882Svi117747 	}
1132*2882Svi117747 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1133*2882Svi117747 	return (B_FALSE);
1134*2882Svi117747 }
1135*2882Svi117747 
1136*2882Svi117747 /*
1137*2882Svi117747  * Free resources associated with the dialog, the object will be removed
1138*2882Svi117747  * from the hash list by sip_hash_delete.
1139*2882Svi117747  */
1140*2882Svi117747 boolean_t
1141*2882Svi117747 sip_dialog_free(void *obj, void *hindex, int *found)
1142*2882Svi117747 {
1143*2882Svi117747 	_sip_dialog_t	*dialog = (_sip_dialog_t *)obj;
1144*2882Svi117747 
1145*2882Svi117747 	*found = 0;
1146*2882Svi117747 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
1147*2882Svi117747 	if (bcmp(dialog->sip_dlg_id, hindex, sizeof (dialog->sip_dlg_id))
1148*2882Svi117747 	    == 0) {
1149*2882Svi117747 		*found = 1;
1150*2882Svi117747 		assert(dialog->sip_dlg_state == SIP_DLG_DESTROYED);
1151*2882Svi117747 		if (dialog->sip_dlg_ref_cnt != 0) {
1152*2882Svi117747 			(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1153*2882Svi117747 			return (B_FALSE);
1154*2882Svi117747 		}
1155*2882Svi117747 		sip_release_dialog_res(dialog);
1156*2882Svi117747 		return (B_TRUE);
1157*2882Svi117747 	}
1158*2882Svi117747 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1159*2882Svi117747 	return (B_FALSE);
1160*2882Svi117747 }
1161*2882Svi117747 
1162*2882Svi117747 /*
1163*2882Svi117747  * The UAS will receive the request from the transaction layer.  If the
1164*2882Svi117747  * request has a tag in the To header field, the UAS core computes the
1165*2882Svi117747  * dialog identifier corresponding to the request and compares it with
1166*2882Svi117747  * existing dialogs.  If there is a match, this is a mid-dialog request.
1167*2882Svi117747  */
1168*2882Svi117747 sip_dialog_t
1169*2882Svi117747 sip_dialog_find(_sip_msg_t *sip_msg)
1170*2882Svi117747 {
1171*2882Svi117747 	const sip_str_t	*localtag;
1172*2882Svi117747 	const sip_str_t	*remtag;
1173*2882Svi117747 	const sip_str_t	*callid;
1174*2882Svi117747 	uint16_t	digest[8];
1175*2882Svi117747 	_sip_dialog_t	*dialog;
1176*2882Svi117747 	boolean_t	is_request;
1177*2882Svi117747 	int		error;
1178*2882Svi117747 
1179*2882Svi117747 	is_request = sip_msg_is_request((sip_msg_t)sip_msg, &error);
1180*2882Svi117747 	if (error != 0)
1181*2882Svi117747 		return (NULL);
1182*2882Svi117747 	if (is_request) {
1183*2882Svi117747 		localtag = sip_get_to_tag((sip_msg_t)sip_msg, &error);
1184*2882Svi117747 		if (error == 0)
1185*2882Svi117747 			remtag = sip_get_from_tag((sip_msg_t)sip_msg, &error);
1186*2882Svi117747 	} else {
1187*2882Svi117747 		remtag = sip_get_to_tag((sip_msg_t)sip_msg, &error);
1188*2882Svi117747 		if (error == 0)
1189*2882Svi117747 			localtag = sip_get_from_tag((sip_msg_t)sip_msg, &error);
1190*2882Svi117747 	}
1191*2882Svi117747 	if (error != 0)
1192*2882Svi117747 		return (NULL);
1193*2882Svi117747 	callid = sip_get_callid((sip_msg_t)sip_msg, &error);
1194*2882Svi117747 	if (error != 0 || remtag == NULL || localtag == NULL ||
1195*2882Svi117747 	    callid == NULL) {
1196*2882Svi117747 		return (NULL);
1197*2882Svi117747 	}
1198*2882Svi117747 	sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len,
1199*2882Svi117747 	    remtag->sip_str_ptr, remtag->sip_str_len,
1200*2882Svi117747 	    callid->sip_str_ptr, callid->sip_str_len,
1201*2882Svi117747 	    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest);
1202*2882Svi117747 
1203*2882Svi117747 	dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_hash,
1204*2882Svi117747 	    (void *)digest, SIP_DIGEST_TO_HASH(digest), sip_dialog_match);
1205*2882Svi117747 	if (dialog == NULL) {
1206*2882Svi117747 		sip_md5_hash(localtag->sip_str_ptr, localtag->sip_str_len,
1207*2882Svi117747 		    NULL, 0, callid->sip_str_ptr, callid->sip_str_len,
1208*2882Svi117747 		    NULL, 0, NULL, 0, NULL, 0, (uchar_t *)digest);
1209*2882Svi117747 		dialog = (_sip_dialog_t *)sip_hash_find(sip_dialog_phash,
1210*2882Svi117747 		    (void *)digest, SIP_DIGEST_TO_HASH(digest),
1211*2882Svi117747 		    sip_dialog_match);
1212*2882Svi117747 	}
1213*2882Svi117747 	return ((sip_dialog_t)dialog);
1214*2882Svi117747 }
1215*2882Svi117747 
1216*2882Svi117747 /*
1217*2882Svi117747  * We keep this partial dialog for the duration of the INVITE
1218*2882Svi117747  * transaction timeout duration, i.e. Timer B.
1219*2882Svi117747  */
1220*2882Svi117747 void
1221*2882Svi117747 sip_dlg_self_destruct(void *args)
1222*2882Svi117747 {
1223*2882Svi117747 	sip_dialog_timer_obj_t	*tim_obj = (sip_dialog_timer_obj_t *)args;
1224*2882Svi117747 	_sip_dialog_t		*dialog = (_sip_dialog_t *)tim_obj->dialog;
1225*2882Svi117747 	int			index;
1226*2882Svi117747 
1227*2882Svi117747 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
1228*2882Svi117747 	assert(dialog->sip_dlg_state == SIP_DLG_NEW);
1229*2882Svi117747 	dialog->sip_dlg_state = SIP_DLG_DESTROYED;
1230*2882Svi117747 	if (dialog->sip_dlg_type == SIP_UAC_DIALOG) {
1231*2882Svi117747 		index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id);
1232*2882Svi117747 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1233*2882Svi117747 		sip_hash_delete(sip_dialog_phash, (void *)dialog->sip_dlg_id,
1234*2882Svi117747 		    index, sip_dialog_dontfree);
1235*2882Svi117747 	} else {
1236*2882Svi117747 		(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1237*2882Svi117747 	}
1238*2882Svi117747 	if (tim_obj->func != NULL)
1239*2882Svi117747 		tim_obj->func(dialog, NULL, NULL);
1240*2882Svi117747 	free(tim_obj);
1241*2882Svi117747 	SIP_DLG_REFCNT_DECR(dialog);
1242*2882Svi117747 }
1243*2882Svi117747 
1244*2882Svi117747 /*
1245*2882Svi117747  * Terminate a dialog
1246*2882Svi117747  */
1247*2882Svi117747 void
1248*2882Svi117747 sip_dialog_terminate(_sip_dialog_t *dialog, sip_msg_t sip_msg)
1249*2882Svi117747 {
1250*2882Svi117747 	int	prev_state;
1251*2882Svi117747 
1252*2882Svi117747 	(void) pthread_mutex_lock(&dialog->sip_dlg_mutex);
1253*2882Svi117747 	prev_state = dialog->sip_dlg_state;
1254*2882Svi117747 	dialog->sip_dlg_state = SIP_DLG_DESTROYED;
1255*2882Svi117747 	(void) pthread_mutex_unlock(&dialog->sip_dlg_mutex);
1256*2882Svi117747 	if (sip_dlg_ulp_state_cb != NULL) {
1257*2882Svi117747 		sip_dlg_ulp_state_cb((sip_dialog_t)dialog, sip_msg, prev_state,
1258*2882Svi117747 		    dialog->sip_dlg_state);
1259*2882Svi117747 	}
1260*2882Svi117747 	SIP_DLG_REFCNT_DECR(dialog);
1261*2882Svi117747 }
1262*2882Svi117747 
1263*2882Svi117747 /*
1264*2882Svi117747  * Delete a dialog
1265*2882Svi117747  */
1266*2882Svi117747 void
1267*2882Svi117747 sip_dialog_delete(_sip_dialog_t *dialog)
1268*2882Svi117747 {
1269*2882Svi117747 	int	index;
1270*2882Svi117747 
1271*2882Svi117747 	/*
1272*2882Svi117747 	 * partial dialog, not in the hash table
1273*2882Svi117747 	 */
1274*2882Svi117747 	if (dialog->sip_dlg_local_uri_tag == NULL ||
1275*2882Svi117747 	    dialog->sip_dlg_remote_uri_tag == NULL) {
1276*2882Svi117747 		/*
1277*2882Svi117747 		 * Cancel the partial dialog timer
1278*2882Svi117747 		 */
1279*2882Svi117747 		if (SIP_IS_TIMER_RUNNING(dialog->sip_dlg_timer))
1280*2882Svi117747 			SIP_CANCEL_TIMER(dialog->sip_dlg_timer);
1281*2882Svi117747 		sip_release_dialog_res(dialog);
1282*2882Svi117747 		return;
1283*2882Svi117747 	}
1284*2882Svi117747 	index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id);
1285*2882Svi117747 	sip_hash_delete(sip_dialog_hash, (void *)dialog->sip_dlg_id, index,
1286*2882Svi117747 	    sip_dialog_free);
1287*2882Svi117747 }
1288*2882Svi117747 
1289*2882Svi117747 /*
1290*2882Svi117747  * Get the remote target from the CONTACT header from the 200 OK response
1291*2882Svi117747  */
1292*2882Svi117747 static boolean_t
1293*2882Svi117747 sip_get_rtarg(_sip_dialog_t *dialog, _sip_msg_t *sip_msg)
1294*2882Svi117747 {
1295*2882Svi117747 	sip_header_t	chdr;
1296*2882Svi117747 
1297*2882Svi117747 	if (dialog->sip_dlg_remote_target != NULL)
1298*2882Svi117747 		return (B_TRUE);
1299*2882Svi117747 
1300*2882Svi117747 	(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
1301*2882Svi117747 	chdr = sip_search_for_header(sip_msg, SIP_CONTACT, NULL);
1302*2882Svi117747 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
1303*2882Svi117747 	if (chdr == NULL)
1304*2882Svi117747 		return (B_FALSE);
1305*2882Svi117747 	if ((dialog->sip_dlg_remote_target = sip_dup_header(chdr)) == NULL)
1306*2882Svi117747 		return (B_FALSE);
1307*2882Svi117747 
1308*2882Svi117747 	return (B_TRUE);
1309*2882Svi117747 }
1310*2882Svi117747 
1311*2882Svi117747 /*
1312*2882Svi117747  * Process an incoming request/response
1313*2882Svi117747  */
1314*2882Svi117747 /* ARGSUSED */
1315*2882Svi117747 int
1316*2882Svi117747 sip_dialog_process(_sip_msg_t *sip_msg, sip_dialog_t *sip_dialog)
1317*2882Svi117747 {
1318*2882Svi117747 	boolean_t	request;
1319*2882Svi117747 	_sip_dialog_t	*_dialog;
1320*2882Svi117747 	int		error;
1321*2882Svi117747 
1322*2882Svi117747 	request = sip_msg_is_request((sip_msg_t)sip_msg, &error);
1323*2882Svi117747 	if (error != 0)
1324*2882Svi117747 		return (EINVAL);
1325*2882Svi117747 	_dialog = (_sip_dialog_t *)*sip_dialog;
1326*2882Svi117747 	if (request) {
1327*2882Svi117747 		uint32_t	cseq;
1328*2882Svi117747 		sip_method_t	method;
1329*2882Svi117747 
1330*2882Svi117747 		cseq = sip_get_callseq_num((sip_msg_t)sip_msg, &error);
1331*2882Svi117747 		if (error != 0)
1332*2882Svi117747 			return (EINVAL);
1333*2882Svi117747 		method = sip_get_callseq_method((sip_msg_t)sip_msg, &error);
1334*2882Svi117747 		if (error != 0)
1335*2882Svi117747 			return (EINVAL);
1336*2882Svi117747 		if (sip_get_request_method((sip_msg_t)sip_msg, &error) !=
1337*2882Svi117747 		    method) {
1338*2882Svi117747 			return (EINVAL);
1339*2882Svi117747 		}
1340*2882Svi117747 		(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
1341*2882Svi117747 		/*
1342*2882Svi117747 		 * Requests that do not change in any way the state
1343*2882Svi117747 		 * of a dialog may be received within a dialog.
1344*2882Svi117747 		 * They are processed as if they had been received
1345*2882Svi117747 		 * outside the dialog.
1346*2882Svi117747 		 * For dialogs that have been established with an
1347*2882Svi117747 		 * INVITE, the only target refresh request defined is
1348*2882Svi117747 		 * re-INVITE.
1349*2882Svi117747 		 */
1350*2882Svi117747 		if (_dialog->sip_dlg_method == INVITE &&
1351*2882Svi117747 		    method == INVITE && _dialog->sip_dlg_remote_cseq != 0 &&
1352*2882Svi117747 		    SIP_CSEQ_LT(cseq, _dialog->sip_dlg_remote_cseq)) {
1353*2882Svi117747 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
1354*2882Svi117747 			return (EPROTO);
1355*2882Svi117747 		}
1356*2882Svi117747 		/*
1357*2882Svi117747 		 * Target-Refresh request
1358*2882Svi117747 		 */
1359*2882Svi117747 		if (_dialog->sip_dlg_method == INVITE && method == INVITE) {
1360*2882Svi117747 			sip_header_t	chdr;
1361*2882Svi117747 			sip_header_t	nchdr;
1362*2882Svi117747 
1363*2882Svi117747 			(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
1364*2882Svi117747 			chdr = sip_search_for_header(sip_msg, SIP_CONTACT,
1365*2882Svi117747 			    NULL);
1366*2882Svi117747 			(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
1367*2882Svi117747 			if (chdr != NULL &&
1368*2882Svi117747 			    (nchdr = sip_dup_header(chdr)) != NULL) {
1369*2882Svi117747 				if (_dialog->sip_dlg_remote_target != NULL) {
1370*2882Svi117747 					sip_free_header(
1371*2882Svi117747 					    _dialog->sip_dlg_remote_target);
1372*2882Svi117747 				}
1373*2882Svi117747 				_dialog->sip_dlg_remote_target = nchdr;
1374*2882Svi117747 			}
1375*2882Svi117747 		}
1376*2882Svi117747 		_dialog->sip_dlg_remote_cseq = cseq;
1377*2882Svi117747 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
1378*2882Svi117747 	} else {
1379*2882Svi117747 		int		resp_code;
1380*2882Svi117747 		sip_method_t	method;
1381*2882Svi117747 		int		error;
1382*2882Svi117747 
1383*2882Svi117747 		resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
1384*2882Svi117747 		if (error == 0) {
1385*2882Svi117747 			method = sip_get_callseq_method((sip_msg_t)sip_msg,
1386*2882Svi117747 			    &error);
1387*2882Svi117747 		}
1388*2882Svi117747 		if (error != 0)
1389*2882Svi117747 			return (error);
1390*2882Svi117747 
1391*2882Svi117747 		(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
1392*2882Svi117747 		assert(_dialog->sip_dlg_state == SIP_DLG_EARLY ||
1393*2882Svi117747 		    _dialog->sip_dlg_state == SIP_DLG_CONFIRMED);
1394*2882Svi117747 		/*
1395*2882Svi117747 		 * Let the user delete the dialog if it is not a 1XX/2XX resp
1396*2882Svi117747 		 * for an early INVITE dialog.
1397*2882Svi117747 		 */
1398*2882Svi117747 		if (SIP_OK_RESP(resp_code)) {
1399*2882Svi117747 			if (method == INVITE) {
1400*2882Svi117747 				if (!sip_get_rtarg(_dialog, sip_msg)) {
1401*2882Svi117747 					(void) pthread_mutex_unlock(
1402*2882Svi117747 					    &_dialog->sip_dlg_mutex);
1403*2882Svi117747 					if (sip_ulp_dlg_del_cb != NULL) {
1404*2882Svi117747 						sip_ulp_dlg_del_cb(
1405*2882Svi117747 						    (sip_dialog_t)_dialog,
1406*2882Svi117747 						    (sip_msg_t)sip_msg, NULL);
1407*2882Svi117747 					}
1408*2882Svi117747 					sip_dialog_terminate(_dialog,
1409*2882Svi117747 					    (sip_msg_t)sip_msg);
1410*2882Svi117747 					return (0);
1411*2882Svi117747 				}
1412*2882Svi117747 				if (_dialog->sip_dlg_state == SIP_DLG_EARLY) {
1413*2882Svi117747 					_dialog->sip_dlg_state =
1414*2882Svi117747 					    SIP_DLG_CONFIRMED;
1415*2882Svi117747 					(void) pthread_mutex_unlock(
1416*2882Svi117747 					    &_dialog->sip_dlg_mutex);
1417*2882Svi117747 					(void) sip_dlg_recompute_rset(_dialog,
1418*2882Svi117747 					    sip_msg, SIP_UAC_DIALOG);
1419*2882Svi117747 					if (sip_dlg_ulp_state_cb != NULL) {
1420*2882Svi117747 						sip_dlg_ulp_state_cb(
1421*2882Svi117747 						    (sip_dialog_t)_dialog,
1422*2882Svi117747 						    sip_msg, SIP_DLG_EARLY,
1423*2882Svi117747 						    _dialog->sip_dlg_state);
1424*2882Svi117747 					}
1425*2882Svi117747 					return (0);
1426*2882Svi117747 				}
1427*2882Svi117747 			}
1428*2882Svi117747 		}
1429*2882Svi117747 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
1430*2882Svi117747 	}
1431*2882Svi117747 	return (0);
1432*2882Svi117747 }
1433*2882Svi117747 
1434*2882Svi117747 /*
1435*2882Svi117747  * Copy partial dialog to create a complete dialog
1436*2882Svi117747  */
1437*2882Svi117747 _sip_dialog_t *
1438*2882Svi117747 sip_copy_partial_dialog(_sip_dialog_t *dialog)
1439*2882Svi117747 {
1440*2882Svi117747 	_sip_dialog_t	*new_dlg;
1441*2882Svi117747 
1442*2882Svi117747 	new_dlg =  calloc(1, sizeof (_sip_dialog_t));
1443*2882Svi117747 	if (new_dlg == NULL)
1444*2882Svi117747 		return (NULL);
1445*2882Svi117747 	if (dialog->sip_dlg_req_uri.sip_str_ptr != NULL) {
1446*2882Svi117747 		new_dlg->sip_dlg_req_uri.sip_str_ptr =
1447*2882Svi117747 		    malloc(dialog->sip_dlg_req_uri.sip_str_len + 1);
1448*2882Svi117747 		if (new_dlg->sip_dlg_req_uri.sip_str_ptr == NULL) {
1449*2882Svi117747 			free(new_dlg);
1450*2882Svi117747 			return (NULL);
1451*2882Svi117747 		}
1452*2882Svi117747 		(void) strncpy(new_dlg->sip_dlg_req_uri.sip_str_ptr,
1453*2882Svi117747 		    dialog->sip_dlg_req_uri.sip_str_ptr,
1454*2882Svi117747 		    dialog->sip_dlg_req_uri.sip_str_len);
1455*2882Svi117747 		new_dlg->sip_dlg_req_uri.sip_str_ptr[
1456*2882Svi117747 		    dialog->sip_dlg_req_uri.sip_str_len] = '\0';
1457*2882Svi117747 		new_dlg->sip_dlg_req_uri.sip_str_len =
1458*2882Svi117747 		    dialog->sip_dlg_req_uri.sip_str_len;
1459*2882Svi117747 	}
1460*2882Svi117747 	if (dialog->sip_dlg_route_set != NULL) {
1461*2882Svi117747 		assert(dialog->sip_dlg_rset.sip_str_ptr != NULL);
1462*2882Svi117747 		new_dlg->sip_dlg_rset.sip_str_ptr =
1463*2882Svi117747 		    malloc(dialog->sip_dlg_rset.sip_str_len + 1);
1464*2882Svi117747 		if (new_dlg->sip_dlg_rset.sip_str_ptr == NULL) {
1465*2882Svi117747 			if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL)
1466*2882Svi117747 				free(new_dlg->sip_dlg_req_uri.sip_str_ptr);
1467*2882Svi117747 			free(new_dlg);
1468*2882Svi117747 			return (NULL);
1469*2882Svi117747 		}
1470*2882Svi117747 		(void) strncpy(new_dlg->sip_dlg_rset.sip_str_ptr,
1471*2882Svi117747 		    dialog->sip_dlg_rset.sip_str_ptr,
1472*2882Svi117747 		    dialog->sip_dlg_rset.sip_str_len);
1473*2882Svi117747 		new_dlg->sip_dlg_rset.sip_str_ptr[
1474*2882Svi117747 		    dialog->sip_dlg_rset.sip_str_len] = '\0';
1475*2882Svi117747 		new_dlg->sip_dlg_rset.sip_str_len =
1476*2882Svi117747 		    dialog->sip_dlg_rset.sip_str_len;
1477*2882Svi117747 
1478*2882Svi117747 		new_dlg->sip_dlg_route_set =
1479*2882Svi117747 		    sip_dup_header(dialog->sip_dlg_route_set);
1480*2882Svi117747 		if (new_dlg->sip_dlg_route_set == NULL) {
1481*2882Svi117747 			free(new_dlg->sip_dlg_rset.sip_str_ptr);
1482*2882Svi117747 			if (new_dlg->sip_dlg_req_uri.sip_str_ptr != NULL)
1483*2882Svi117747 				free(new_dlg->sip_dlg_req_uri.sip_str_ptr);
1484*2882Svi117747 			free(new_dlg);
1485*2882Svi117747 			return (NULL);
1486*2882Svi117747 		}
1487*2882Svi117747 	}
1488*2882Svi117747 	if ((new_dlg->sip_dlg_local_uri_tag =
1489*2882Svi117747 	    sip_dup_header(dialog->sip_dlg_local_uri_tag)) == NULL ||
1490*2882Svi117747 	    (new_dlg->sip_dlg_remote_target =
1491*2882Svi117747 	    sip_dup_header(dialog->sip_dlg_remote_target)) == NULL ||
1492*2882Svi117747 	    (new_dlg->sip_dlg_call_id =
1493*2882Svi117747 	    sip_dup_header(dialog->sip_dlg_call_id)) == NULL) {
1494*2882Svi117747 		sip_release_dialog_res(new_dlg);
1495*2882Svi117747 		return (NULL);
1496*2882Svi117747 	}
1497*2882Svi117747 	if (dialog->sip_dlg_event != NULL) {
1498*2882Svi117747 		new_dlg->sip_dlg_event = sip_dup_header(dialog->sip_dlg_event);
1499*2882Svi117747 		if (new_dlg->sip_dlg_event == NULL) {
1500*2882Svi117747 			sip_release_dialog_res(new_dlg);
1501*2882Svi117747 			return (NULL);
1502*2882Svi117747 		}
1503*2882Svi117747 	}
1504*2882Svi117747 	new_dlg->sip_dlg_local_cseq = dialog->sip_dlg_local_cseq;
1505*2882Svi117747 	new_dlg->sip_dlg_type = dialog->sip_dlg_type;
1506*2882Svi117747 	new_dlg->sip_dlg_on_fork = B_FALSE;
1507*2882Svi117747 	(void) pthread_mutex_init(&new_dlg->sip_dlg_mutex, NULL);
1508*2882Svi117747 
1509*2882Svi117747 	return (new_dlg);
1510*2882Svi117747 }
1511*2882Svi117747 
1512*2882Svi117747 /*
1513*2882Svi117747  * Update the dialog using the response
1514*2882Svi117747  */
1515*2882Svi117747 sip_dialog_t
1516*2882Svi117747 sip_update_dialog(sip_dialog_t dialog, _sip_msg_t *sip_msg)
1517*2882Svi117747 {
1518*2882Svi117747 	_sip_dialog_t	*_dialog;
1519*2882Svi117747 	boolean_t	isreq;
1520*2882Svi117747 	sip_method_t	method;
1521*2882Svi117747 	int		resp_code = 0;
1522*2882Svi117747 	int		prev_state;
1523*2882Svi117747 	boolean_t	decr_ref = B_FALSE;
1524*2882Svi117747 	int		error;
1525*2882Svi117747 
1526*2882Svi117747 	isreq = sip_msg_is_request((sip_msg_t)sip_msg, &error);
1527*2882Svi117747 	if (error != 0)
1528*2882Svi117747 		return (dialog);
1529*2882Svi117747 	_dialog = (_sip_dialog_t *)dialog;
1530*2882Svi117747 	(void) pthread_mutex_lock(&_dialog->sip_dlg_mutex);
1531*2882Svi117747 	if (isreq) {
1532*2882Svi117747 		method = sip_get_request_method((sip_msg_t)sip_msg, &error);
1533*2882Svi117747 		if (error != 0 || _dialog->sip_dlg_method != SUBSCRIBE ||
1534*2882Svi117747 		    method != NOTIFY) {
1535*2882Svi117747 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
1536*2882Svi117747 			return (dialog);
1537*2882Svi117747 		}
1538*2882Svi117747 	} else {
1539*2882Svi117747 		resp_code = sip_get_response_code((sip_msg_t)sip_msg, &error);
1540*2882Svi117747 		if (error != 0) {
1541*2882Svi117747 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
1542*2882Svi117747 			return (dialog);
1543*2882Svi117747 		}
1544*2882Svi117747 	}
1545*2882Svi117747 	prev_state = _dialog->sip_dlg_state;
1546*2882Svi117747 	if (_dialog->sip_dlg_state == SIP_DLG_CONFIRMED) {
1547*2882Svi117747 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
1548*2882Svi117747 	} else if (_dialog->sip_dlg_state == SIP_DLG_EARLY) {
1549*2882Svi117747 		/*
1550*2882Svi117747 		 * Let the user delete the dialog if it is not a 1XX/2XX resp
1551*2882Svi117747 		 * for an early dialog.
1552*2882Svi117747 		 */
1553*2882Svi117747 		assert(!isreq);
1554*2882Svi117747 		if (SIP_OK_RESP(resp_code)) {
1555*2882Svi117747 			_dialog->sip_dlg_state = SIP_DLG_CONFIRMED;
1556*2882Svi117747 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
1557*2882Svi117747 			(void) sip_dlg_recompute_rset(_dialog, sip_msg,
1558*2882Svi117747 			    SIP_UAS_DIALOG);
1559*2882Svi117747 			if (sip_dlg_ulp_state_cb != NULL) {
1560*2882Svi117747 				sip_dlg_ulp_state_cb(dialog, (sip_msg_t)sip_msg,
1561*2882Svi117747 				    prev_state, dialog->sip_dlg_state);
1562*2882Svi117747 			}
1563*2882Svi117747 		} else {
1564*2882Svi117747 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
1565*2882Svi117747 		}
1566*2882Svi117747 	} else if (_dialog->sip_dlg_state == SIP_DLG_NEW) {
1567*2882Svi117747 		if (!isreq && _dialog->sip_dlg_method == SUBSCRIBE &&
1568*2882Svi117747 		    SIP_PROVISIONAL_RESP(resp_code)) {
1569*2882Svi117747 			(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
1570*2882Svi117747 			return (dialog);
1571*2882Svi117747 		}
1572*2882Svi117747 		if (_dialog->sip_dlg_type == SIP_UAC_DIALOG) {
1573*2882Svi117747 			_sip_dialog_t	*new_dlg;
1574*2882Svi117747 
1575*2882Svi117747 			if (_dialog->sip_dlg_on_fork) {
1576*2882Svi117747 				new_dlg = sip_copy_partial_dialog(_dialog);
1577*2882Svi117747 				if (new_dlg == NULL) {
1578*2882Svi117747 					(void) pthread_mutex_unlock(
1579*2882Svi117747 					    &_dialog->sip_dlg_mutex);
1580*2882Svi117747 					return (dialog);
1581*2882Svi117747 				}
1582*2882Svi117747 				/*
1583*2882Svi117747 				 * This decr/incr dance is because the caller
1584*2882Svi117747 				 * has incremented the ref on the partial
1585*2882Svi117747 				 * dialog, we release it here and incr the
1586*2882Svi117747 				 * ref on the new dialog which will be
1587*2882Svi117747 				 * released by the caller.
1588*2882Svi117747 				 */
1589*2882Svi117747 				(void) pthread_mutex_unlock(
1590*2882Svi117747 				    &_dialog->sip_dlg_mutex);
1591*2882Svi117747 				SIP_DLG_REFCNT_DECR(_dialog);
1592*2882Svi117747 				_dialog = new_dlg;
1593*2882Svi117747 				(void) pthread_mutex_lock(
1594*2882Svi117747 				    &_dialog->sip_dlg_mutex);
1595*2882Svi117747 				SIP_DLG_REFCNT_INCR(_dialog);
1596*2882Svi117747 			} else {
1597*2882Svi117747 				int	index;
1598*2882Svi117747 
1599*2882Svi117747 				/*
1600*2882Svi117747 				 * take it out of the list so that further
1601*2882Svi117747 				 * responses will not result in a dialog.
1602*2882Svi117747 				 * We will have an extra refcount when we
1603*2882Svi117747 				 * come back from sip_complete_dialog(), i.e.
1604*2882Svi117747 				 * one when the partial dialog was created -
1605*2882Svi117747 				 * in sip_seed_dialog(), one held by the caller
1606*2882Svi117747 				 * and one that will be added by
1607*2882Svi117747 				 * sip_complete_dialog(). We need to release
1608*2882Svi117747 				 * the one added by the sip_seed_dialog(),
1609*2882Svi117747 				 * since the one in sip_complete_dialog()
1610*2882Svi117747 				 * is for the same purpose.
1611*2882Svi117747 				 */
1612*2882Svi117747 				if (SIP_IS_TIMER_RUNNING(
1613*2882Svi117747 				    _dialog->sip_dlg_timer)) {
1614*2882Svi117747 					SIP_CANCEL_TIMER(
1615*2882Svi117747 					    _dialog->sip_dlg_timer);
1616*2882Svi117747 				}
1617*2882Svi117747 				index = SIP_DIGEST_TO_HASH(dialog->sip_dlg_id);
1618*2882Svi117747 				(void) pthread_mutex_unlock(
1619*2882Svi117747 				    &_dialog->sip_dlg_mutex);
1620*2882Svi117747 				sip_hash_delete(sip_dialog_phash,
1621*2882Svi117747 				    (void *)_dialog->sip_dlg_id,
1622*2882Svi117747 				    index, sip_dialog_dontfree);
1623*2882Svi117747 				(void) pthread_mutex_lock(
1624*2882Svi117747 				    &_dialog->sip_dlg_mutex);
1625*2882Svi117747 				decr_ref = B_TRUE;
1626*2882Svi117747 			}
1627*2882Svi117747 		} else {
1628*2882Svi117747 			decr_ref = B_TRUE;
1629*2882Svi117747 		}
1630*2882Svi117747 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
1631*2882Svi117747 		if ((dialog = sip_complete_dialog(sip_msg, _dialog)) ==
1632*2882Svi117747 		    NULL) {
1633*2882Svi117747 			return (NULL);
1634*2882Svi117747 		}
1635*2882Svi117747 		if (decr_ref)
1636*2882Svi117747 			SIP_DLG_REFCNT_DECR(_dialog);
1637*2882Svi117747 	} else {
1638*2882Svi117747 		(void) pthread_mutex_unlock(&_dialog->sip_dlg_mutex);
1639*2882Svi117747 	}
1640*2882Svi117747 	return (dialog);
1641*2882Svi117747 }
1642*2882Svi117747 
1643*2882Svi117747 /*
1644*2882Svi117747  * Initialize the hash table
1645*2882Svi117747  */
1646*2882Svi117747 void
1647*2882Svi117747 sip_dialog_init(void (*ulp_dlg_del) (sip_dialog_t, sip_msg_t, void *),
1648*2882Svi117747     void (*ulp_state_cb)(sip_dialog_t, sip_msg_t, int, int))
1649*2882Svi117747 {
1650*2882Svi117747 	int	cnt;
1651*2882Svi117747 
1652*2882Svi117747 	for (cnt = 0; cnt < SIP_HASH_SZ; cnt++) {
1653*2882Svi117747 		sip_dialog_hash[cnt].hash_count = 0;
1654*2882Svi117747 		sip_dialog_hash[cnt].hash_head = NULL;
1655*2882Svi117747 		sip_dialog_hash[cnt].hash_tail = NULL;
1656*2882Svi117747 		(void) pthread_mutex_init(
1657*2882Svi117747 		    &sip_dialog_hash[cnt].sip_hash_mutex, NULL);
1658*2882Svi117747 		sip_dialog_phash[cnt].hash_count = 0;
1659*2882Svi117747 		sip_dialog_phash[cnt].hash_head = NULL;
1660*2882Svi117747 		sip_dialog_phash[cnt].hash_tail = NULL;
1661*2882Svi117747 		(void) pthread_mutex_init(
1662*2882Svi117747 		    &sip_dialog_phash[cnt].sip_hash_mutex, NULL);
1663*2882Svi117747 	}
1664*2882Svi117747 	if (ulp_dlg_del != NULL)
1665*2882Svi117747 		sip_ulp_dlg_del_cb = ulp_dlg_del;
1666*2882Svi117747 
1667*2882Svi117747 	if (ulp_state_cb != NULL)
1668*2882Svi117747 		sip_dlg_ulp_state_cb = ulp_state_cb;
1669*2882Svi117747 }
1670