xref: /titanic_52/usr/src/lib/libsip/common/sip_xaction.c (revision 943efbc33954e332318b6365bf27037c05bff72c)
140cb5e5dSvi117747 /*
240cb5e5dSvi117747  * CDDL HEADER START
340cb5e5dSvi117747  *
440cb5e5dSvi117747  * The contents of this file are subject to the terms of the
540cb5e5dSvi117747  * Common Development and Distribution License (the "License").
640cb5e5dSvi117747  * You may not use this file except in compliance with the License.
740cb5e5dSvi117747  *
840cb5e5dSvi117747  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
940cb5e5dSvi117747  * or http://www.opensolaris.org/os/licensing.
1040cb5e5dSvi117747  * See the License for the specific language governing permissions
1140cb5e5dSvi117747  * and limitations under the License.
1240cb5e5dSvi117747  *
1340cb5e5dSvi117747  * When distributing Covered Code, include this CDDL HEADER in each
1440cb5e5dSvi117747  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1540cb5e5dSvi117747  * If applicable, add the following below this CDDL HEADER, with the
1640cb5e5dSvi117747  * fields enclosed by brackets "[]" replaced with your own identifying
1740cb5e5dSvi117747  * information: Portions Copyright [yyyy] [name of copyright owner]
1840cb5e5dSvi117747  *
1940cb5e5dSvi117747  * CDDL HEADER END
2040cb5e5dSvi117747  */
2140cb5e5dSvi117747 
2240cb5e5dSvi117747 /*
23*943efbc3Sgm209912  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2440cb5e5dSvi117747  * Use is subject to license terms.
2540cb5e5dSvi117747  */
2640cb5e5dSvi117747 
2740cb5e5dSvi117747 #pragma ident	"%Z%%M%	%I%	%E% SMI"
2840cb5e5dSvi117747 
292c2c4183Svi117747 #include <stdlib.h>
302c2c4183Svi117747 #include <assert.h>
312c2c4183Svi117747 #include <errno.h>
322c2c4183Svi117747 #include <pthread.h>
332c2c4183Svi117747 #include <strings.h>
342c2c4183Svi117747 
3540cb5e5dSvi117747 #include "sip_parse_uri.h"
3640cb5e5dSvi117747 #include "sip_msg.h"
3740cb5e5dSvi117747 #include "sip_miscdefs.h"
3840cb5e5dSvi117747 #include "sip_xaction.h"
3940cb5e5dSvi117747 #include "sip_hash.h"
4040cb5e5dSvi117747 
4140cb5e5dSvi117747 #define	RFC_3261_BRANCH "z9hG4bK"
4240cb5e5dSvi117747 
4340cb5e5dSvi117747 /*
4440cb5e5dSvi117747  * The transaction hash table
4540cb5e5dSvi117747  */
4640cb5e5dSvi117747 sip_hash_t	sip_xaction_hash[SIP_HASH_SZ];
4740cb5e5dSvi117747 
4840cb5e5dSvi117747 int (*sip_xaction_ulp_trans_err)(sip_transaction_t, int, void *) = NULL;
4940cb5e5dSvi117747 void (*sip_xaction_ulp_state_cb)(sip_transaction_t, sip_msg_t, int, int) = NULL;
5040cb5e5dSvi117747 
5140cb5e5dSvi117747 int sip_xaction_add(sip_xaction_t *, char *, _sip_msg_t *, sip_method_t);
5240cb5e5dSvi117747 static boolean_t sip_is_conn_obj_cache(sip_conn_object_t, void *);
5340cb5e5dSvi117747 
5440cb5e5dSvi117747 /*
5540cb5e5dSvi117747  * Get the md5 hash of the required fields
5640cb5e5dSvi117747  */
5740cb5e5dSvi117747 int
5840cb5e5dSvi117747 sip_find_md5_digest(char *bid, _sip_msg_t *msg, uint16_t *hindex,
5940cb5e5dSvi117747     sip_method_t method)
6040cb5e5dSvi117747 {
6140cb5e5dSvi117747 	boolean_t	is_2543;
6240cb5e5dSvi117747 
6340cb5e5dSvi117747 	is_2543 = (bid == NULL ||
6440cb5e5dSvi117747 	    strncmp(bid, RFC_3261_BRANCH, strlen(RFC_3261_BRANCH)) != 0);
6540cb5e5dSvi117747 
6640cb5e5dSvi117747 	if (is_2543 && msg == NULL)
6740cb5e5dSvi117747 		return (EINVAL);
6840cb5e5dSvi117747 	if (is_2543) {
6940cb5e5dSvi117747 		_sip_header_t	*from = NULL;
7040cb5e5dSvi117747 		_sip_header_t	*cid = NULL;
7140cb5e5dSvi117747 		_sip_header_t	*via = NULL;
7240cb5e5dSvi117747 		const sip_str_t	*to_uri = NULL;
7340cb5e5dSvi117747 		int		cseq;
7440cb5e5dSvi117747 		int		error = 0;
7540cb5e5dSvi117747 
7640cb5e5dSvi117747 		/*
7740cb5e5dSvi117747 		 * Since the response might contain parameters not in the
7840cb5e5dSvi117747 		 * request, just use the to URI.
7940cb5e5dSvi117747 		 */
8040cb5e5dSvi117747 		to_uri = sip_get_to_uri_str((sip_msg_t)msg, &error);
8140cb5e5dSvi117747 		if (to_uri == NULL || error != 0)
8240cb5e5dSvi117747 			return (EINVAL);
8340cb5e5dSvi117747 		cseq = sip_get_callseq_num((sip_msg_t)msg, &error);
8440cb5e5dSvi117747 		if (cseq < 0 || error != 0)
8540cb5e5dSvi117747 			return (EINVAL);
8640cb5e5dSvi117747 		(void) pthread_mutex_lock(&msg->sip_msg_mutex);
8740cb5e5dSvi117747 		via = sip_search_for_header(msg, SIP_VIA, NULL);
8840cb5e5dSvi117747 		from = sip_search_for_header(msg, SIP_FROM, NULL);
8940cb5e5dSvi117747 		cid = sip_search_for_header(msg, SIP_CALL_ID, NULL);
9040cb5e5dSvi117747 		(void) pthread_mutex_unlock(&msg->sip_msg_mutex);
9140cb5e5dSvi117747 		if (via == NULL || from == NULL || cid == NULL)
9240cb5e5dSvi117747 			return (EINVAL);
9340cb5e5dSvi117747 		sip_md5_hash(via->sip_hdr_start,
9440cb5e5dSvi117747 		    via->sip_hdr_end - via->sip_hdr_start,
9540cb5e5dSvi117747 		    cid->sip_hdr_start,
9640cb5e5dSvi117747 		    cid->sip_hdr_end - cid->sip_hdr_start,
9740cb5e5dSvi117747 		    from->sip_hdr_start,
9840cb5e5dSvi117747 		    from->sip_hdr_end - from->sip_hdr_start,
9940cb5e5dSvi117747 		    (char *)&cseq, sizeof (int),
10040cb5e5dSvi117747 		    (char *)&method, sizeof (sip_method_t),
10140cb5e5dSvi117747 		    to_uri->sip_str_ptr, to_uri->sip_str_len,
10240cb5e5dSvi117747 		    (uchar_t *)hindex);
10340cb5e5dSvi117747 	} else {
10440cb5e5dSvi117747 		sip_md5_hash(bid, strlen(bid), (char *)&method,
10540cb5e5dSvi117747 		    sizeof (sip_method_t), NULL, 0, NULL, 0, NULL, 0, NULL, 0,
10640cb5e5dSvi117747 		    (uchar_t *)hindex);
10740cb5e5dSvi117747 	}
10840cb5e5dSvi117747 	return (0);
10940cb5e5dSvi117747 }
11040cb5e5dSvi117747 
11140cb5e5dSvi117747 /*
11240cb5e5dSvi117747  * Add object to the connection cache object. Not checking for duplicates!!
11340cb5e5dSvi117747  */
11440cb5e5dSvi117747 int
11540cb5e5dSvi117747 sip_add_conn_obj_cache(sip_conn_object_t obj, void *cobj)
11640cb5e5dSvi117747 {
11740cb5e5dSvi117747 	void			**obj_val;
11840cb5e5dSvi117747 	sip_conn_obj_pvt_t	*pvt_data;
11940cb5e5dSvi117747 	sip_conn_cache_t	*xaction_list;
12040cb5e5dSvi117747 	sip_xaction_t		*sip_trans = (sip_xaction_t *)cobj;
12140cb5e5dSvi117747 
12240cb5e5dSvi117747 	/*
12340cb5e5dSvi117747 	 * Is already cached
12440cb5e5dSvi117747 	 */
12540cb5e5dSvi117747 	if (sip_trans->sip_xaction_conn_obj != NULL) {
12640cb5e5dSvi117747 		if (sip_is_conn_obj_cache(sip_trans->sip_xaction_conn_obj,
12740cb5e5dSvi117747 		    (void *)sip_trans)) {
12840cb5e5dSvi117747 			return (0);
12940cb5e5dSvi117747 		}
13040cb5e5dSvi117747 		/*
13140cb5e5dSvi117747 		 * Transaction has cached a different conn_obj, release it
13240cb5e5dSvi117747 		 */
13340cb5e5dSvi117747 		sip_del_conn_obj_cache(sip_trans->sip_xaction_conn_obj,
13440cb5e5dSvi117747 		    (void *)sip_trans);
13540cb5e5dSvi117747 	}
13640cb5e5dSvi117747 
13740cb5e5dSvi117747 	xaction_list = malloc(sizeof (sip_conn_cache_t));
13840cb5e5dSvi117747 	if (xaction_list == NULL)
13940cb5e5dSvi117747 		return (ENOMEM);
14040cb5e5dSvi117747 	xaction_list->obj = cobj;
14140cb5e5dSvi117747 	xaction_list->next = xaction_list->prev = NULL;
14240cb5e5dSvi117747 
14340cb5e5dSvi117747 	obj_val = (void *)obj;
14440cb5e5dSvi117747 	pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
14540cb5e5dSvi117747 	if (pvt_data == NULL) {
14640cb5e5dSvi117747 		free(xaction_list);
14740cb5e5dSvi117747 		return (EINVAL);
14840cb5e5dSvi117747 	}
14940cb5e5dSvi117747 	(void) pthread_mutex_lock(&pvt_data->sip_conn_obj_cache_lock);
15040cb5e5dSvi117747 
15140cb5e5dSvi117747 	if (pvt_data->sip_conn_obj_cache == NULL) {
15240cb5e5dSvi117747 		pvt_data->sip_conn_obj_cache = xaction_list;
15340cb5e5dSvi117747 	} else {
15440cb5e5dSvi117747 		xaction_list->next =  pvt_data->sip_conn_obj_cache;
15540cb5e5dSvi117747 		pvt_data->sip_conn_obj_cache->prev = xaction_list;
15640cb5e5dSvi117747 		pvt_data->sip_conn_obj_cache = xaction_list;
15740cb5e5dSvi117747 	}
15840cb5e5dSvi117747 	sip_refhold_conn(obj);
15940cb5e5dSvi117747 	sip_trans->sip_xaction_conn_obj = obj;
16040cb5e5dSvi117747 	(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock);
16140cb5e5dSvi117747 	return (0);
16240cb5e5dSvi117747 }
16340cb5e5dSvi117747 
16440cb5e5dSvi117747 /*
16540cb5e5dSvi117747  * Walk thru the list of transactions that have cached this obj and
16640cb5e5dSvi117747  * and return true if 'cobj' is one of them.
16740cb5e5dSvi117747  */
16840cb5e5dSvi117747 static boolean_t
16940cb5e5dSvi117747 sip_is_conn_obj_cache(sip_conn_object_t obj, void *cobj)
17040cb5e5dSvi117747 {
17140cb5e5dSvi117747 	void			**obj_val;
17240cb5e5dSvi117747 	sip_conn_obj_pvt_t	*pvt_data;
17340cb5e5dSvi117747 	sip_conn_cache_t	*xaction_list;
17440cb5e5dSvi117747 	sip_xaction_t		*trans;
17540cb5e5dSvi117747 	sip_xaction_t		*ctrans = (sip_xaction_t *)cobj;
17640cb5e5dSvi117747 
17740cb5e5dSvi117747 	obj_val = (void *)obj;
17840cb5e5dSvi117747 	pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
17940cb5e5dSvi117747 	if (pvt_data == NULL)
18040cb5e5dSvi117747 		return (B_FALSE);
18140cb5e5dSvi117747 	(void) pthread_mutex_lock(&pvt_data->sip_conn_obj_cache_lock);
18240cb5e5dSvi117747 	xaction_list = pvt_data->sip_conn_obj_cache;
18340cb5e5dSvi117747 	while (xaction_list != NULL) {
18440cb5e5dSvi117747 		trans = (sip_xaction_t *)xaction_list->obj;
18540cb5e5dSvi117747 		if (ctrans != trans) {
18640cb5e5dSvi117747 			xaction_list = xaction_list->next;
18740cb5e5dSvi117747 			continue;
18840cb5e5dSvi117747 		}
18940cb5e5dSvi117747 		(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock);
19040cb5e5dSvi117747 		return (B_TRUE);
19140cb5e5dSvi117747 	}
19240cb5e5dSvi117747 	(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock);
19340cb5e5dSvi117747 	return (B_FALSE);
19440cb5e5dSvi117747 }
19540cb5e5dSvi117747 
19640cb5e5dSvi117747 
19740cb5e5dSvi117747 /*
19840cb5e5dSvi117747  * Walk thru the list of transactions that have cached this obj and
19940cb5e5dSvi117747  * refrele the objs.
20040cb5e5dSvi117747  */
20140cb5e5dSvi117747 void
20240cb5e5dSvi117747 sip_del_conn_obj_cache(sip_conn_object_t obj, void *cobj)
20340cb5e5dSvi117747 {
20440cb5e5dSvi117747 	void			**obj_val;
20540cb5e5dSvi117747 	sip_conn_obj_pvt_t	*pvt_data;
20640cb5e5dSvi117747 	sip_conn_cache_t	*xaction_list;
20740cb5e5dSvi117747 	sip_conn_cache_t	*tmp_list;
20840cb5e5dSvi117747 	sip_xaction_t		*trans;
20940cb5e5dSvi117747 	sip_xaction_t		*ctrans = NULL;
21040cb5e5dSvi117747 
21140cb5e5dSvi117747 	if (cobj != NULL)
21240cb5e5dSvi117747 		ctrans = (sip_xaction_t *)cobj;
21340cb5e5dSvi117747 
21440cb5e5dSvi117747 	obj_val = (void *)obj;
21540cb5e5dSvi117747 	pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
21640cb5e5dSvi117747 	if (pvt_data == NULL) {	/* ASSERT FALSE if ctrans != NULL?? */
21740cb5e5dSvi117747 		if (ctrans != NULL) {
21840cb5e5dSvi117747 			sip_refrele_conn(obj);
21940cb5e5dSvi117747 			ctrans->sip_xaction_conn_obj = NULL;
22040cb5e5dSvi117747 		}
22140cb5e5dSvi117747 		return;
22240cb5e5dSvi117747 	}
22340cb5e5dSvi117747 	(void) pthread_mutex_lock(&pvt_data->sip_conn_obj_cache_lock);
22440cb5e5dSvi117747 	xaction_list = pvt_data->sip_conn_obj_cache;
22540cb5e5dSvi117747 	while (xaction_list != NULL) {
22640cb5e5dSvi117747 		tmp_list = xaction_list;
22740cb5e5dSvi117747 		trans = (sip_xaction_t *)xaction_list->obj;
22840cb5e5dSvi117747 		assert(trans != NULL);
22940cb5e5dSvi117747 		if (ctrans != NULL && ctrans != trans) {
23040cb5e5dSvi117747 			xaction_list = xaction_list->next;
23140cb5e5dSvi117747 			continue;
23240cb5e5dSvi117747 		}
23340cb5e5dSvi117747 		if (ctrans == NULL)
23440cb5e5dSvi117747 			(void) pthread_mutex_lock(&trans->sip_xaction_mutex);
23540cb5e5dSvi117747 		assert(trans->sip_xaction_conn_obj == obj);
23640cb5e5dSvi117747 		sip_refrele_conn(obj);
23740cb5e5dSvi117747 		trans->sip_xaction_conn_obj = NULL;
23840cb5e5dSvi117747 		if (ctrans == NULL)
23940cb5e5dSvi117747 			(void) pthread_mutex_unlock(&trans->sip_xaction_mutex);
24040cb5e5dSvi117747 		xaction_list = xaction_list->next;
24140cb5e5dSvi117747 
24240cb5e5dSvi117747 		/*
24340cb5e5dSvi117747 		 * Take the obj out of the list
24440cb5e5dSvi117747 		 */
24540cb5e5dSvi117747 		if (tmp_list == pvt_data->sip_conn_obj_cache) {
24640cb5e5dSvi117747 			if (xaction_list == NULL) {
24740cb5e5dSvi117747 				pvt_data->sip_conn_obj_cache = NULL;
24840cb5e5dSvi117747 			} else {
24940cb5e5dSvi117747 				xaction_list->prev = NULL;
25040cb5e5dSvi117747 				pvt_data->sip_conn_obj_cache = xaction_list;
25140cb5e5dSvi117747 			}
25240cb5e5dSvi117747 		} else if (xaction_list == NULL) {
25340cb5e5dSvi117747 			assert(tmp_list->prev != NULL);
25440cb5e5dSvi117747 			tmp_list->prev->next = NULL;
25540cb5e5dSvi117747 		} else {
25640cb5e5dSvi117747 			assert(tmp_list->prev != NULL);
25740cb5e5dSvi117747 			tmp_list->prev->next = xaction_list;
25840cb5e5dSvi117747 			xaction_list->prev = tmp_list->prev;
25940cb5e5dSvi117747 		}
26040cb5e5dSvi117747 		tmp_list->prev = NULL;
26140cb5e5dSvi117747 		tmp_list->next = NULL;
26240cb5e5dSvi117747 		tmp_list->obj = NULL;
26340cb5e5dSvi117747 
26440cb5e5dSvi117747 		free(tmp_list);
26540cb5e5dSvi117747 	}
26640cb5e5dSvi117747 	(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock);
26740cb5e5dSvi117747 }
26840cb5e5dSvi117747 
26940cb5e5dSvi117747 /*
27040cb5e5dSvi117747  * Check for a transaction match. Passed to sip_hash_find().
27140cb5e5dSvi117747  */
27240cb5e5dSvi117747 boolean_t
27340cb5e5dSvi117747 sip_xaction_match(void *obj, void *hindex)
27440cb5e5dSvi117747 {
27540cb5e5dSvi117747 	sip_xaction_t	*tmp = (sip_xaction_t *)obj;
27640cb5e5dSvi117747 
27740cb5e5dSvi117747 	tmp = (sip_xaction_t *)obj;
27840cb5e5dSvi117747 
27940cb5e5dSvi117747 	if (SIP_IS_XACTION_TERMINATED(tmp->sip_xaction_state))
28040cb5e5dSvi117747 		return (B_FALSE);
28140cb5e5dSvi117747 	if (bcmp(tmp->sip_xaction_hash_digest, hindex,
28240cb5e5dSvi117747 	    sizeof (tmp->sip_xaction_hash_digest)) == 0) {
28340cb5e5dSvi117747 		SIP_XACTION_REFCNT_INCR(tmp);
28440cb5e5dSvi117747 		return (B_TRUE);
28540cb5e5dSvi117747 	}
28640cb5e5dSvi117747 	return (B_FALSE);
28740cb5e5dSvi117747 }
28840cb5e5dSvi117747 
28940cb5e5dSvi117747 
29040cb5e5dSvi117747 /*
29140cb5e5dSvi117747  * Find a transaction
29240cb5e5dSvi117747  */
29340cb5e5dSvi117747 static sip_xaction_t *
29440cb5e5dSvi117747 sip_xaction_find(char *branchid, _sip_msg_t *msg, int which)
29540cb5e5dSvi117747 {
29640cb5e5dSvi117747 	sip_xaction_t		*tmp;
29740cb5e5dSvi117747 	uint16_t		hash_index[8];
29840cb5e5dSvi117747 	int			hindex;
29940cb5e5dSvi117747 	sip_method_t		method;
30040cb5e5dSvi117747 	int			error;
30140cb5e5dSvi117747 	sip_message_type_t	*sip_msg_info;
30240cb5e5dSvi117747 
30340cb5e5dSvi117747 	sip_msg_info = msg->sip_msg_req_res;
30440cb5e5dSvi117747 	method = sip_get_callseq_method((sip_msg_t)msg, &error);
30540cb5e5dSvi117747 	if (error != 0)
30640cb5e5dSvi117747 		return (NULL);
30740cb5e5dSvi117747 
30840cb5e5dSvi117747 	/*
30940cb5e5dSvi117747 	 * If we are getting a ACK/CANCEL we need to match with the
31040cb5e5dSvi117747 	 * corresponding INVITE, if any.
31140cb5e5dSvi117747 	 */
31240cb5e5dSvi117747 	if (sip_msg_info->is_request && which == SIP_SERVER_TRANSACTION &&
31340cb5e5dSvi117747 	    (method == ACK || method == CANCEL)) {
31440cb5e5dSvi117747 		method = INVITE;
31540cb5e5dSvi117747 	}
31640cb5e5dSvi117747 	if (sip_find_md5_digest(branchid, msg, hash_index, method) != 0)
31740cb5e5dSvi117747 		return (NULL);
31840cb5e5dSvi117747 	hindex = SIP_DIGEST_TO_HASH(hash_index);
31940cb5e5dSvi117747 	tmp = (sip_xaction_t *)sip_hash_find(sip_xaction_hash,
32040cb5e5dSvi117747 	    (void *)hash_index, hindex, sip_xaction_match);
32140cb5e5dSvi117747 	return (tmp);
32240cb5e5dSvi117747 }
32340cb5e5dSvi117747 
32440cb5e5dSvi117747 /*
32540cb5e5dSvi117747  * create a transaction.
32640cb5e5dSvi117747  */
32740cb5e5dSvi117747 static sip_xaction_t *
32840cb5e5dSvi117747 sip_xaction_create(sip_conn_object_t obj, _sip_msg_t *msg, char *branchid,
32940cb5e5dSvi117747     int *error)
33040cb5e5dSvi117747 {
33140cb5e5dSvi117747 	sip_xaction_t		*trans;
33240cb5e5dSvi117747 	sip_message_type_t	*sip_msg_info;
33340cb5e5dSvi117747 	int			state = 0;
33440cb5e5dSvi117747 	int			prev_state = 0;
33540cb5e5dSvi117747 	sip_method_t		method;
33640cb5e5dSvi117747 	int			ret;
33740cb5e5dSvi117747 	int			timer1 = sip_timer_T1;
33840cb5e5dSvi117747 	int			timer4 = sip_timer_T4;
33940cb5e5dSvi117747 	int			timerd = sip_timer_TD;
34040cb5e5dSvi117747 
34140cb5e5dSvi117747 	if (error != NULL)
34240cb5e5dSvi117747 		*error = 0;
34340cb5e5dSvi117747 	/*
34440cb5e5dSvi117747 	 * Make sure we are not creating a transaction for
34540cb5e5dSvi117747 	 * an ACK request.
34640cb5e5dSvi117747 	 */
34740cb5e5dSvi117747 	trans = (sip_xaction_t *)malloc(sizeof (sip_xaction_t));
34840cb5e5dSvi117747 	if (trans == NULL) {
34940cb5e5dSvi117747 		if (error != NULL)
35040cb5e5dSvi117747 			*error = ENOMEM;
35140cb5e5dSvi117747 		return (NULL);
35240cb5e5dSvi117747 	}
35340cb5e5dSvi117747 	bzero(trans, sizeof (sip_xaction_t));
35440cb5e5dSvi117747 	if (branchid == NULL) {
35540cb5e5dSvi117747 		trans->sip_xaction_branch_id = (char *)sip_branchid(NULL);
35640cb5e5dSvi117747 		if (trans->sip_xaction_branch_id == NULL) {
35740cb5e5dSvi117747 			free(trans);
35840cb5e5dSvi117747 			if (error != NULL)
35940cb5e5dSvi117747 				*error = ENOMEM;
36040cb5e5dSvi117747 			return (NULL);
36140cb5e5dSvi117747 		}
36240cb5e5dSvi117747 	} else {
36340cb5e5dSvi117747 		trans->sip_xaction_branch_id = (char *)malloc(strlen(branchid)
36440cb5e5dSvi117747 		    + 1);
36540cb5e5dSvi117747 		if (trans->sip_xaction_branch_id == NULL) {
36640cb5e5dSvi117747 			free(trans);
36740cb5e5dSvi117747 			if (error != NULL)
36840cb5e5dSvi117747 				*error = ENOMEM;
36940cb5e5dSvi117747 			return (NULL);
37040cb5e5dSvi117747 		}
37140cb5e5dSvi117747 		(void) strncpy(trans->sip_xaction_branch_id, branchid,
37240cb5e5dSvi117747 		    strlen(branchid));
37340cb5e5dSvi117747 		trans->sip_xaction_branch_id[strlen(branchid)] = '\0';
37440cb5e5dSvi117747 	}
37540cb5e5dSvi117747 	(void) pthread_mutex_init(&trans->sip_xaction_mutex, NULL);
37640cb5e5dSvi117747 	SIP_MSG_REFCNT_INCR(msg);
37740cb5e5dSvi117747 	trans->sip_xaction_orig_msg = msg;
37840cb5e5dSvi117747 	assert(msg->sip_msg_req_res != NULL);
37940cb5e5dSvi117747 	sip_msg_info = msg->sip_msg_req_res;
38040cb5e5dSvi117747 	if (sip_msg_info->is_request) {
38140cb5e5dSvi117747 		method = sip_msg_info->sip_req_method;
38240cb5e5dSvi117747 	} else {
38340cb5e5dSvi117747 		method = sip_get_callseq_method((sip_msg_t)msg, &ret);
38440cb5e5dSvi117747 		if (ret != 0) {
38540cb5e5dSvi117747 			free(trans->sip_xaction_branch_id);
38640cb5e5dSvi117747 			free(trans);
38740cb5e5dSvi117747 			if (error != NULL)
38840cb5e5dSvi117747 				*error = ret;
38940cb5e5dSvi117747 			return (NULL);
39040cb5e5dSvi117747 		}
39140cb5e5dSvi117747 		if (method == INVITE)
39240cb5e5dSvi117747 			state = SIP_SRV_INV_PROCEEDING;
39340cb5e5dSvi117747 		else
39440cb5e5dSvi117747 			state = SIP_SRV_TRYING;
39540cb5e5dSvi117747 	}
39640cb5e5dSvi117747 	trans->sip_xaction_method = method;
39740cb5e5dSvi117747 	trans->sip_xaction_state = state;
39840cb5e5dSvi117747 
39940cb5e5dSvi117747 	/*
40040cb5e5dSvi117747 	 * Get connection object specific timeouts, if present
40140cb5e5dSvi117747 	 */
40240cb5e5dSvi117747 	if (sip_conn_timer1 != NULL)
40340cb5e5dSvi117747 		timer1 = sip_conn_timer1(obj);
40440cb5e5dSvi117747 	if (sip_conn_timer4 != NULL)
40540cb5e5dSvi117747 		timer4 = sip_conn_timer4(obj);
40640cb5e5dSvi117747 	if (sip_conn_timerd != NULL)
40740cb5e5dSvi117747 		timerd = sip_conn_timerd(obj);
40840cb5e5dSvi117747 
40940cb5e5dSvi117747 	SIP_INIT_TIMER(trans->sip_xaction_TA, 2 * timer1);
41040cb5e5dSvi117747 	SIP_INIT_TIMER(trans->sip_xaction_TB, 64 * timer1)
41140cb5e5dSvi117747 	SIP_INIT_TIMER(trans->sip_xaction_TD,  timerd);
41240cb5e5dSvi117747 	SIP_INIT_TIMER(trans->sip_xaction_TE, timer1);
41340cb5e5dSvi117747 	SIP_INIT_TIMER(trans->sip_xaction_TF, 64 * timer1);
41440cb5e5dSvi117747 	SIP_INIT_TIMER(trans->sip_xaction_TG, 2 * timer1);
41540cb5e5dSvi117747 	SIP_INIT_TIMER(trans->sip_xaction_TH, 64 * timer1);
41640cb5e5dSvi117747 	SIP_INIT_TIMER(trans->sip_xaction_TI, timer4);
41740cb5e5dSvi117747 	SIP_INIT_TIMER(trans->sip_xaction_TJ, 64 * timer1);
41840cb5e5dSvi117747 	SIP_INIT_TIMER(trans->sip_xaction_TK, timer4);
41940cb5e5dSvi117747 
42040cb5e5dSvi117747 	if ((ret = sip_xaction_add(trans, branchid, msg, method)) != 0) {
42140cb5e5dSvi117747 		(void) pthread_mutex_destroy(&trans->sip_xaction_mutex);
42240cb5e5dSvi117747 		free(trans->sip_xaction_branch_id);
42340cb5e5dSvi117747 		free(trans);
42440cb5e5dSvi117747 		if (error != NULL)
42540cb5e5dSvi117747 			*error = ret;
42640cb5e5dSvi117747 		return (NULL);
42740cb5e5dSvi117747 	}
42840cb5e5dSvi117747 	if (sip_xaction_ulp_state_cb != NULL &&
42940cb5e5dSvi117747 	    prev_state != trans->sip_xaction_state) {
43040cb5e5dSvi117747 		sip_xaction_ulp_state_cb((sip_transaction_t)trans,
43140cb5e5dSvi117747 		    (sip_msg_t)msg, prev_state, trans->sip_xaction_state);
43240cb5e5dSvi117747 	}
43340cb5e5dSvi117747 	return (trans);
43440cb5e5dSvi117747 }
43540cb5e5dSvi117747 
43640cb5e5dSvi117747 /*
43740cb5e5dSvi117747  * Find a transaction, create if asked for
43840cb5e5dSvi117747  */
43940cb5e5dSvi117747 sip_xaction_t *
44040cb5e5dSvi117747 sip_xaction_get(sip_conn_object_t obj, sip_msg_t msg, boolean_t create,
44140cb5e5dSvi117747     int which, int *error)
44240cb5e5dSvi117747 {
44340cb5e5dSvi117747 	char			*branchid;
44440cb5e5dSvi117747 	sip_xaction_t		*sip_trans;
44540cb5e5dSvi117747 	_sip_msg_t		*_msg;
44640cb5e5dSvi117747 	sip_message_type_t	*sip_msg_info;
44740cb5e5dSvi117747 
44840cb5e5dSvi117747 	if (error != NULL)
44940cb5e5dSvi117747 		*error = 0;
45040cb5e5dSvi117747 
45140cb5e5dSvi117747 	_msg = (_sip_msg_t *)msg;
45240cb5e5dSvi117747 	sip_msg_info = ((_sip_msg_t *)msg)->sip_msg_req_res;
45340cb5e5dSvi117747 
45440cb5e5dSvi117747 	branchid = sip_get_branchid(msg, NULL);
45540cb5e5dSvi117747 	sip_trans = sip_xaction_find(branchid, _msg, which);
45640cb5e5dSvi117747 	if (sip_trans == NULL && create) {
45740cb5e5dSvi117747 		/*
45840cb5e5dSvi117747 		 * If we are sending a request, must be conformant to RFC 3261.
45940cb5e5dSvi117747 		 */
46040cb5e5dSvi117747 		if (sip_msg_info->is_request &&
46140cb5e5dSvi117747 		    (branchid == NULL || strncmp(branchid,
46240cb5e5dSvi117747 		    RFC_3261_BRANCH, strlen(RFC_3261_BRANCH) != 0))) {
46340cb5e5dSvi117747 			if (error != NULL)
46440cb5e5dSvi117747 				*error = EINVAL;
46540cb5e5dSvi117747 			if (branchid != NULL)
46640cb5e5dSvi117747 				free(branchid);
46740cb5e5dSvi117747 			return (NULL);
46840cb5e5dSvi117747 		}
46940cb5e5dSvi117747 		sip_trans = sip_xaction_create(obj, _msg, branchid, error);
47040cb5e5dSvi117747 		if (sip_trans != NULL)
47140cb5e5dSvi117747 			SIP_XACTION_REFCNT_INCR(sip_trans);
47240cb5e5dSvi117747 	}
47340cb5e5dSvi117747 	if (branchid != NULL)
47440cb5e5dSvi117747 		free(branchid);
47540cb5e5dSvi117747 	return (sip_trans);
47640cb5e5dSvi117747 }
47740cb5e5dSvi117747 
47840cb5e5dSvi117747 
47940cb5e5dSvi117747 /*
48040cb5e5dSvi117747  * Delete a transaction if the reference count is 0. Passed to
48140cb5e5dSvi117747  * sip_hash_delete().
48240cb5e5dSvi117747  */
48340cb5e5dSvi117747 boolean_t
48440cb5e5dSvi117747 sip_xaction_remove(void *obj, void *hindex, int *found)
48540cb5e5dSvi117747 {
48640cb5e5dSvi117747 	sip_xaction_t	*tmp = (sip_xaction_t *)obj;
487*943efbc3Sgm209912 	int		count = 0;
488*943efbc3Sgm209912 	sip_msg_chain_t	*msg_chain;
489*943efbc3Sgm209912 	sip_msg_chain_t	*nmsg_chain;
49040cb5e5dSvi117747 
49140cb5e5dSvi117747 	*found = 0;
49240cb5e5dSvi117747 	tmp = (sip_xaction_t *)obj;
49340cb5e5dSvi117747 	(void) pthread_mutex_lock(&tmp->sip_xaction_mutex);
49440cb5e5dSvi117747 	if (bcmp(tmp->sip_xaction_hash_digest, hindex,
49540cb5e5dSvi117747 	    sizeof (tmp->sip_xaction_hash_digest)) == 0) {
49640cb5e5dSvi117747 		*found = 1;
49740cb5e5dSvi117747 		if (tmp->sip_xaction_ref_cnt != 0) {
49840cb5e5dSvi117747 			(void) pthread_mutex_unlock(&tmp->sip_xaction_mutex);
49940cb5e5dSvi117747 			return (B_FALSE);
50040cb5e5dSvi117747 		}
50140cb5e5dSvi117747 		(void) pthread_mutex_destroy(&tmp->sip_xaction_mutex);
50240cb5e5dSvi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TA);
50340cb5e5dSvi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TB);
50440cb5e5dSvi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TD);
50540cb5e5dSvi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TE);
50640cb5e5dSvi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TF);
50740cb5e5dSvi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TG);
50840cb5e5dSvi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TH);
50940cb5e5dSvi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TI);
51040cb5e5dSvi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TJ);
51140cb5e5dSvi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TK);
512*943efbc3Sgm209912 		sip_write_to_log((void *)tmp, SIP_TRANSACTION_LOG, NULL, 0);
51340cb5e5dSvi117747 		free(tmp->sip_xaction_branch_id);
51440cb5e5dSvi117747 		if (tmp->sip_xaction_last_msg != NULL) {
51540cb5e5dSvi117747 			SIP_MSG_REFCNT_DECR(tmp->sip_xaction_last_msg);
51640cb5e5dSvi117747 			tmp->sip_xaction_last_msg = NULL;
51740cb5e5dSvi117747 		}
51840cb5e5dSvi117747 		if (tmp->sip_xaction_orig_msg != NULL) {
51940cb5e5dSvi117747 			SIP_MSG_REFCNT_DECR(tmp->sip_xaction_orig_msg);
52040cb5e5dSvi117747 			tmp->sip_xaction_orig_msg = NULL;
52140cb5e5dSvi117747 		}
52240cb5e5dSvi117747 		if (tmp->sip_xaction_conn_obj != NULL) {
52340cb5e5dSvi117747 			sip_del_conn_obj_cache(tmp->sip_xaction_conn_obj,
52440cb5e5dSvi117747 			    (void *)tmp);
52540cb5e5dSvi117747 		}
526*943efbc3Sgm209912 		/*
527*943efbc3Sgm209912 		 * If the transaction logging is disabled before we could
528*943efbc3Sgm209912 		 * write the captured messages into the transaction log, then
529*943efbc3Sgm209912 		 * we need to free those captured messsages
530*943efbc3Sgm209912 		 */
531*943efbc3Sgm209912 		for (count = 0; count <= SIP_SRV_NONINV_TERMINATED; count++) {
532*943efbc3Sgm209912 			msg_chain = tmp->sip_xaction_log[count].sip_msgs;
533*943efbc3Sgm209912 			while (msg_chain != NULL) {
534*943efbc3Sgm209912 				nmsg_chain = msg_chain->next;
535*943efbc3Sgm209912 				if (msg_chain->sip_msg != NULL)
536*943efbc3Sgm209912 					free(msg_chain->sip_msg);
537*943efbc3Sgm209912 				free(msg_chain);
538*943efbc3Sgm209912 				msg_chain = nmsg_chain;
539*943efbc3Sgm209912 			}
540*943efbc3Sgm209912 		}
54140cb5e5dSvi117747 		free(tmp);
54240cb5e5dSvi117747 		return (B_TRUE);
54340cb5e5dSvi117747 	}
54440cb5e5dSvi117747 	(void) pthread_mutex_unlock(&tmp->sip_xaction_mutex);
54540cb5e5dSvi117747 	return (B_FALSE);
54640cb5e5dSvi117747 }
54740cb5e5dSvi117747 
54840cb5e5dSvi117747 /*
54940cb5e5dSvi117747  * Delete a SIP transaction
55040cb5e5dSvi117747  */
55140cb5e5dSvi117747 void
55240cb5e5dSvi117747 sip_xaction_delete(sip_xaction_t *trans)
55340cb5e5dSvi117747 {
55440cb5e5dSvi117747 	int	hindex;
55540cb5e5dSvi117747 
55640cb5e5dSvi117747 	(void) pthread_mutex_lock(&trans->sip_xaction_mutex);
55740cb5e5dSvi117747 	hindex = SIP_DIGEST_TO_HASH(trans->sip_xaction_hash_digest);
55840cb5e5dSvi117747 	if (trans->sip_xaction_ref_cnt != 0) {
55940cb5e5dSvi117747 		(void) pthread_mutex_unlock(&trans->sip_xaction_mutex);
56040cb5e5dSvi117747 		return;
56140cb5e5dSvi117747 	}
56240cb5e5dSvi117747 	(void) pthread_mutex_unlock(&trans->sip_xaction_mutex);
56340cb5e5dSvi117747 	sip_hash_delete(sip_xaction_hash, trans->sip_xaction_hash_digest,
56440cb5e5dSvi117747 	    hindex, sip_xaction_remove);
56540cb5e5dSvi117747 }
56640cb5e5dSvi117747 
56740cb5e5dSvi117747 /*
56840cb5e5dSvi117747  * Add a SIP transaction into the hash list.
56940cb5e5dSvi117747  */
57040cb5e5dSvi117747 int
57140cb5e5dSvi117747 sip_xaction_add(sip_xaction_t *trans, char *branchid, _sip_msg_t *msg,
57240cb5e5dSvi117747     sip_method_t method)
57340cb5e5dSvi117747 {
57440cb5e5dSvi117747 	uint16_t	hash_index[8];
57540cb5e5dSvi117747 
57640cb5e5dSvi117747 	if (sip_find_md5_digest(branchid, msg, hash_index, method) != 0)
57740cb5e5dSvi117747 		return (EINVAL);
57840cb5e5dSvi117747 
57940cb5e5dSvi117747 	/*
58040cb5e5dSvi117747 	 * trans is not in the list as yet, so no need to hold the lock
58140cb5e5dSvi117747 	 */
58240cb5e5dSvi117747 	bcopy(hash_index, trans->sip_xaction_hash_digest, sizeof (hash_index));
58340cb5e5dSvi117747 
58440cb5e5dSvi117747 	if (sip_hash_add(sip_xaction_hash, (void *)trans,
58540cb5e5dSvi117747 	    SIP_DIGEST_TO_HASH(hash_index)) != 0) {
58640cb5e5dSvi117747 		return (ENOMEM);
58740cb5e5dSvi117747 	}
58840cb5e5dSvi117747 	return (0);
58940cb5e5dSvi117747 }
59040cb5e5dSvi117747 
59140cb5e5dSvi117747 
59240cb5e5dSvi117747 /*
59340cb5e5dSvi117747  * Given a state, return the  string - This is mostly for debug purposes
59440cb5e5dSvi117747  */
59540cb5e5dSvi117747 char *
59640cb5e5dSvi117747 sip_get_xaction_state(int state)
59740cb5e5dSvi117747 {
59840cb5e5dSvi117747 	switch (state) {
599*943efbc3Sgm209912 		case SIP_NEW_TRANSACTION:
600*943efbc3Sgm209912 			return ("SIP_NEW_TRANSACTION");
60140cb5e5dSvi117747 		case SIP_CLNT_CALLING:
60240cb5e5dSvi117747 			return ("SIP_CLNT_CALLING");
60340cb5e5dSvi117747 		case SIP_CLNT_INV_PROCEEDING:
60440cb5e5dSvi117747 			return ("SIP_CLNT_INV_PROCEEDING");
60540cb5e5dSvi117747 		case SIP_CLNT_INV_TERMINATED:
60640cb5e5dSvi117747 			return ("SIP_CLNT_INV_TERMINATED");
60740cb5e5dSvi117747 		case SIP_CLNT_INV_COMPLETED:
60840cb5e5dSvi117747 			return ("SIP_CLNT_INV_COMPLETED");
60940cb5e5dSvi117747 		case SIP_CLNT_TRYING:
61040cb5e5dSvi117747 			return ("SIP_CLNT_TRYING");
61140cb5e5dSvi117747 		case SIP_CLNT_NONINV_PROCEEDING:
61240cb5e5dSvi117747 			return ("SIP_CLNT_NONINV_PROCEEDING");
61340cb5e5dSvi117747 		case SIP_CLNT_NONINV_TERMINATED:
61440cb5e5dSvi117747 			return ("SIP_CLNT_NONINV_TERMINATED");
61540cb5e5dSvi117747 		case SIP_CLNT_NONINV_COMPLETED:
61640cb5e5dSvi117747 			return ("SIP_CLNT_NONINV_COMPLETED");
61740cb5e5dSvi117747 		case SIP_SRV_INV_PROCEEDING:
61840cb5e5dSvi117747 			return ("SIP_SRV_INV_PROCEEDING");
61940cb5e5dSvi117747 		case SIP_SRV_INV_COMPLETED:
62040cb5e5dSvi117747 			return ("SIP_SRV_INV_COMPLETED");
62140cb5e5dSvi117747 		case SIP_SRV_CONFIRMED:
62240cb5e5dSvi117747 			return ("SIP_SRV_CONFIRMED");
62340cb5e5dSvi117747 		case SIP_SRV_INV_TERMINATED:
62440cb5e5dSvi117747 			return ("SIP_SRV_INV_TERMINATED");
62540cb5e5dSvi117747 		case SIP_SRV_TRYING:
62640cb5e5dSvi117747 			return ("SIP_SRV_TRYING");
62740cb5e5dSvi117747 		case SIP_SRV_NONINV_PROCEEDING:
62840cb5e5dSvi117747 			return ("SIP_SRV_NONINV_PROCEEDING");
62940cb5e5dSvi117747 		case SIP_SRV_NONINV_COMPLETED:
63040cb5e5dSvi117747 			return ("SIP_SRV_NONINV_COMPLETED");
63140cb5e5dSvi117747 		case SIP_SRV_NONINV_TERMINATED:
63240cb5e5dSvi117747 			return ("SIP_SRV_NONINV_TERMINATED");
63340cb5e5dSvi117747 		default :
634*943efbc3Sgm209912 			return ("UNKNOWN");
63540cb5e5dSvi117747 	}
63640cb5e5dSvi117747 }
63740cb5e5dSvi117747 
63840cb5e5dSvi117747 /*
63940cb5e5dSvi117747  * Initialize the hash table etc.
64040cb5e5dSvi117747  */
64140cb5e5dSvi117747 void
64240cb5e5dSvi117747 sip_xaction_init(int (*ulp_trans_err)(sip_transaction_t, int, void *),
64340cb5e5dSvi117747     void (*ulp_state_cb)(sip_transaction_t, sip_msg_t, int, int))
64440cb5e5dSvi117747 {
64540cb5e5dSvi117747 	int	cnt;
64640cb5e5dSvi117747 
64740cb5e5dSvi117747 	for (cnt = 0; cnt < SIP_HASH_SZ; cnt++) {
64840cb5e5dSvi117747 		sip_xaction_hash[cnt].hash_count = 0;
64940cb5e5dSvi117747 		sip_xaction_hash[cnt].hash_head = NULL;
65040cb5e5dSvi117747 		sip_xaction_hash[cnt].hash_tail = NULL;
65140cb5e5dSvi117747 		(void) pthread_mutex_init(
65240cb5e5dSvi117747 		    &sip_xaction_hash[cnt].sip_hash_mutex, NULL);
65340cb5e5dSvi117747 	}
65440cb5e5dSvi117747 	if (ulp_trans_err != NULL)
65540cb5e5dSvi117747 		sip_xaction_ulp_trans_err = ulp_trans_err;
65640cb5e5dSvi117747 	if (ulp_state_cb != NULL)
65740cb5e5dSvi117747 		sip_xaction_ulp_state_cb = ulp_state_cb;
65840cb5e5dSvi117747 }
659