1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <stdlib.h>
30#include <assert.h>
31#include <errno.h>
32#include <pthread.h>
33#include <strings.h>
34
35#include "sip_parse_uri.h"
36#include "sip_msg.h"
37#include "sip_miscdefs.h"
38#include "sip_xaction.h"
39#include "sip_hash.h"
40
41#define	RFC_3261_BRANCH "z9hG4bK"
42
43/*
44 * The transaction hash table
45 */
46sip_hash_t	sip_xaction_hash[SIP_HASH_SZ];
47
48int (*sip_xaction_ulp_trans_err)(sip_transaction_t, int, void *) = NULL;
49void (*sip_xaction_ulp_state_cb)(sip_transaction_t, sip_msg_t, int, int) = NULL;
50
51int sip_xaction_add(sip_xaction_t *, char *, _sip_msg_t *, sip_method_t);
52static boolean_t sip_is_conn_obj_cache(sip_conn_object_t, void *);
53
54/*
55 * Get the md5 hash of the required fields
56 */
57int
58sip_find_md5_digest(char *bid, _sip_msg_t *msg, uint16_t *hindex,
59    sip_method_t method)
60{
61	boolean_t	is_2543;
62
63	is_2543 = (bid == NULL ||
64	    strncmp(bid, RFC_3261_BRANCH, strlen(RFC_3261_BRANCH)) != 0);
65
66	if (is_2543 && msg == NULL)
67		return (EINVAL);
68	if (is_2543) {
69		_sip_header_t	*from = NULL;
70		_sip_header_t	*cid = NULL;
71		_sip_header_t	*via = NULL;
72		const sip_str_t	*to_uri = NULL;
73		int		cseq;
74		int		error = 0;
75
76		/*
77		 * Since the response might contain parameters not in the
78		 * request, just use the to URI.
79		 */
80		to_uri = sip_get_to_uri_str((sip_msg_t)msg, &error);
81		if (to_uri == NULL || error != 0)
82			return (EINVAL);
83		cseq = sip_get_callseq_num((sip_msg_t)msg, &error);
84		if (cseq < 0 || error != 0)
85			return (EINVAL);
86		(void) pthread_mutex_lock(&msg->sip_msg_mutex);
87		via = sip_search_for_header(msg, SIP_VIA, NULL);
88		from = sip_search_for_header(msg, SIP_FROM, NULL);
89		cid = sip_search_for_header(msg, SIP_CALL_ID, NULL);
90		(void) pthread_mutex_unlock(&msg->sip_msg_mutex);
91		if (via == NULL || from == NULL || cid == NULL)
92			return (EINVAL);
93		sip_md5_hash(via->sip_hdr_start,
94		    via->sip_hdr_end - via->sip_hdr_start,
95		    cid->sip_hdr_start,
96		    cid->sip_hdr_end - cid->sip_hdr_start,
97		    from->sip_hdr_start,
98		    from->sip_hdr_end - from->sip_hdr_start,
99		    (char *)&cseq, sizeof (int),
100		    (char *)&method, sizeof (sip_method_t),
101		    to_uri->sip_str_ptr, to_uri->sip_str_len,
102		    (uchar_t *)hindex);
103	} else {
104		sip_md5_hash(bid, strlen(bid), (char *)&method,
105		    sizeof (sip_method_t), NULL, 0, NULL, 0, NULL, 0, NULL, 0,
106		    (uchar_t *)hindex);
107	}
108	return (0);
109}
110
111/*
112 * Add object to the connection cache object. Not checking for duplicates!!
113 */
114int
115sip_add_conn_obj_cache(sip_conn_object_t obj, void *cobj)
116{
117	void			**obj_val;
118	sip_conn_obj_pvt_t	*pvt_data;
119	sip_conn_cache_t	*xaction_list;
120	sip_xaction_t		*sip_trans = (sip_xaction_t *)cobj;
121
122	/*
123	 * Is already cached
124	 */
125	if (sip_trans->sip_xaction_conn_obj != NULL) {
126		if (sip_is_conn_obj_cache(sip_trans->sip_xaction_conn_obj,
127		    (void *)sip_trans)) {
128			return (0);
129		}
130		/*
131		 * Transaction has cached a different conn_obj, release it
132		 */
133		sip_del_conn_obj_cache(sip_trans->sip_xaction_conn_obj,
134		    (void *)sip_trans);
135	}
136
137	xaction_list = malloc(sizeof (sip_conn_cache_t));
138	if (xaction_list == NULL)
139		return (ENOMEM);
140	xaction_list->obj = cobj;
141	xaction_list->next = xaction_list->prev = NULL;
142
143	obj_val = (void *)obj;
144	pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
145	if (pvt_data == NULL) {
146		free(xaction_list);
147		return (EINVAL);
148	}
149	(void) pthread_mutex_lock(&pvt_data->sip_conn_obj_cache_lock);
150
151	if (pvt_data->sip_conn_obj_cache == NULL) {
152		pvt_data->sip_conn_obj_cache = xaction_list;
153	} else {
154		xaction_list->next =  pvt_data->sip_conn_obj_cache;
155		pvt_data->sip_conn_obj_cache->prev = xaction_list;
156		pvt_data->sip_conn_obj_cache = xaction_list;
157	}
158	sip_refhold_conn(obj);
159	sip_trans->sip_xaction_conn_obj = obj;
160	(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock);
161	return (0);
162}
163
164/*
165 * Walk thru the list of transactions that have cached this obj and
166 * and return true if 'cobj' is one of them.
167 */
168static boolean_t
169sip_is_conn_obj_cache(sip_conn_object_t obj, void *cobj)
170{
171	void			**obj_val;
172	sip_conn_obj_pvt_t	*pvt_data;
173	sip_conn_cache_t	*xaction_list;
174	sip_xaction_t		*trans;
175	sip_xaction_t		*ctrans = (sip_xaction_t *)cobj;
176
177	obj_val = (void *)obj;
178	pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
179	if (pvt_data == NULL)
180		return (B_FALSE);
181	(void) pthread_mutex_lock(&pvt_data->sip_conn_obj_cache_lock);
182	xaction_list = pvt_data->sip_conn_obj_cache;
183	while (xaction_list != NULL) {
184		trans = (sip_xaction_t *)xaction_list->obj;
185		if (ctrans != trans) {
186			xaction_list = xaction_list->next;
187			continue;
188		}
189		(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock);
190		return (B_TRUE);
191	}
192	(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock);
193	return (B_FALSE);
194}
195
196
197/*
198 * Walk thru the list of transactions that have cached this obj and
199 * refrele the objs.
200 */
201void
202sip_del_conn_obj_cache(sip_conn_object_t obj, void *cobj)
203{
204	void			**obj_val;
205	sip_conn_obj_pvt_t	*pvt_data;
206	sip_conn_cache_t	*xaction_list;
207	sip_conn_cache_t	*tmp_list;
208	sip_xaction_t		*trans;
209	sip_xaction_t		*ctrans = NULL;
210
211	if (cobj != NULL)
212		ctrans = (sip_xaction_t *)cobj;
213
214	obj_val = (void *)obj;
215	pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
216	if (pvt_data == NULL) {	/* ASSERT FALSE if ctrans != NULL?? */
217		if (ctrans != NULL) {
218			sip_refrele_conn(obj);
219			ctrans->sip_xaction_conn_obj = NULL;
220		}
221		return;
222	}
223	(void) pthread_mutex_lock(&pvt_data->sip_conn_obj_cache_lock);
224	xaction_list = pvt_data->sip_conn_obj_cache;
225	while (xaction_list != NULL) {
226		tmp_list = xaction_list;
227		trans = (sip_xaction_t *)xaction_list->obj;
228		assert(trans != NULL);
229		if (ctrans != NULL && ctrans != trans) {
230			xaction_list = xaction_list->next;
231			continue;
232		}
233		if (ctrans == NULL)
234			(void) pthread_mutex_lock(&trans->sip_xaction_mutex);
235		assert(trans->sip_xaction_conn_obj == obj);
236		sip_refrele_conn(obj);
237		trans->sip_xaction_conn_obj = NULL;
238		if (ctrans == NULL)
239			(void) pthread_mutex_unlock(&trans->sip_xaction_mutex);
240		xaction_list = xaction_list->next;
241
242		/*
243		 * Take the obj out of the list
244		 */
245		if (tmp_list == pvt_data->sip_conn_obj_cache) {
246			if (xaction_list == NULL) {
247				pvt_data->sip_conn_obj_cache = NULL;
248			} else {
249				xaction_list->prev = NULL;
250				pvt_data->sip_conn_obj_cache = xaction_list;
251			}
252		} else if (xaction_list == NULL) {
253			assert(tmp_list->prev != NULL);
254			tmp_list->prev->next = NULL;
255		} else {
256			assert(tmp_list->prev != NULL);
257			tmp_list->prev->next = xaction_list;
258			xaction_list->prev = tmp_list->prev;
259		}
260		tmp_list->prev = NULL;
261		tmp_list->next = NULL;
262		tmp_list->obj = NULL;
263
264		free(tmp_list);
265	}
266	(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock);
267}
268
269/*
270 * Check for a transaction match. Passed to sip_hash_find().
271 */
272boolean_t
273sip_xaction_match(void *obj, void *hindex)
274{
275	sip_xaction_t	*tmp = (sip_xaction_t *)obj;
276
277	tmp = (sip_xaction_t *)obj;
278
279	if (SIP_IS_XACTION_TERMINATED(tmp->sip_xaction_state))
280		return (B_FALSE);
281	if (bcmp(tmp->sip_xaction_hash_digest, hindex,
282	    sizeof (tmp->sip_xaction_hash_digest)) == 0) {
283		SIP_XACTION_REFCNT_INCR(tmp);
284		return (B_TRUE);
285	}
286	return (B_FALSE);
287}
288
289
290/*
291 * Find a transaction
292 */
293static sip_xaction_t *
294sip_xaction_find(char *branchid, _sip_msg_t *msg, int which)
295{
296	sip_xaction_t		*tmp;
297	uint16_t		hash_index[8];
298	int			hindex;
299	sip_method_t		method;
300	int			error;
301	sip_message_type_t	*sip_msg_info;
302
303	sip_msg_info = msg->sip_msg_req_res;
304	method = sip_get_callseq_method((sip_msg_t)msg, &error);
305	if (error != 0)
306		return (NULL);
307
308	/*
309	 * If we are getting a ACK/CANCEL we need to match with the
310	 * corresponding INVITE, if any.
311	 */
312	if (sip_msg_info->is_request && which == SIP_SERVER_TRANSACTION &&
313	    (method == ACK || method == CANCEL)) {
314		method = INVITE;
315	}
316	if (sip_find_md5_digest(branchid, msg, hash_index, method) != 0)
317		return (NULL);
318	hindex = SIP_DIGEST_TO_HASH(hash_index);
319	tmp = (sip_xaction_t *)sip_hash_find(sip_xaction_hash,
320	    (void *)hash_index, hindex, sip_xaction_match);
321	return (tmp);
322}
323
324/*
325 * create a transaction.
326 */
327static sip_xaction_t *
328sip_xaction_create(sip_conn_object_t obj, _sip_msg_t *msg, char *branchid,
329    int *error)
330{
331	sip_xaction_t		*trans;
332	sip_message_type_t	*sip_msg_info;
333	int			state = 0;
334	int			prev_state = 0;
335	sip_method_t		method;
336	int			ret;
337	int			timer1 = sip_timer_T1;
338	int			timer4 = sip_timer_T4;
339	int			timerd = sip_timer_TD;
340
341	if (error != NULL)
342		*error = 0;
343	/*
344	 * Make sure we are not creating a transaction for
345	 * an ACK request.
346	 */
347	trans = (sip_xaction_t *)malloc(sizeof (sip_xaction_t));
348	if (trans == NULL) {
349		if (error != NULL)
350			*error = ENOMEM;
351		return (NULL);
352	}
353	bzero(trans, sizeof (sip_xaction_t));
354	if (branchid == NULL) {
355		trans->sip_xaction_branch_id = (char *)sip_branchid(NULL);
356		if (trans->sip_xaction_branch_id == NULL) {
357			free(trans);
358			if (error != NULL)
359				*error = ENOMEM;
360			return (NULL);
361		}
362	} else {
363		trans->sip_xaction_branch_id = (char *)malloc(strlen(branchid)
364		    + 1);
365		if (trans->sip_xaction_branch_id == NULL) {
366			free(trans);
367			if (error != NULL)
368				*error = ENOMEM;
369			return (NULL);
370		}
371		(void) strncpy(trans->sip_xaction_branch_id, branchid,
372		    strlen(branchid));
373		trans->sip_xaction_branch_id[strlen(branchid)] = '\0';
374	}
375	(void) pthread_mutex_init(&trans->sip_xaction_mutex, NULL);
376	SIP_MSG_REFCNT_INCR(msg);
377	trans->sip_xaction_orig_msg = msg;
378	assert(msg->sip_msg_req_res != NULL);
379	sip_msg_info = msg->sip_msg_req_res;
380	if (sip_msg_info->is_request) {
381		method = sip_msg_info->sip_req_method;
382	} else {
383		method = sip_get_callseq_method((sip_msg_t)msg, &ret);
384		if (ret != 0) {
385			free(trans->sip_xaction_branch_id);
386			free(trans);
387			if (error != NULL)
388				*error = ret;
389			return (NULL);
390		}
391		if (method == INVITE)
392			state = SIP_SRV_INV_PROCEEDING;
393		else
394			state = SIP_SRV_TRYING;
395	}
396	trans->sip_xaction_method = method;
397	trans->sip_xaction_state = state;
398
399	/*
400	 * Get connection object specific timeouts, if present
401	 */
402	if (sip_conn_timer1 != NULL)
403		timer1 = sip_conn_timer1(obj);
404	if (sip_conn_timer4 != NULL)
405		timer4 = sip_conn_timer4(obj);
406	if (sip_conn_timerd != NULL)
407		timerd = sip_conn_timerd(obj);
408
409	SIP_INIT_TIMER(trans->sip_xaction_TA, 2 * timer1);
410	SIP_INIT_TIMER(trans->sip_xaction_TB, 64 * timer1)
411	SIP_INIT_TIMER(trans->sip_xaction_TD,  timerd);
412	SIP_INIT_TIMER(trans->sip_xaction_TE, timer1);
413	SIP_INIT_TIMER(trans->sip_xaction_TF, 64 * timer1);
414	SIP_INIT_TIMER(trans->sip_xaction_TG, 2 * timer1);
415	SIP_INIT_TIMER(trans->sip_xaction_TH, 64 * timer1);
416	SIP_INIT_TIMER(trans->sip_xaction_TI, timer4);
417	SIP_INIT_TIMER(trans->sip_xaction_TJ, 64 * timer1);
418	SIP_INIT_TIMER(trans->sip_xaction_TK, timer4);
419
420	if ((ret = sip_xaction_add(trans, branchid, msg, method)) != 0) {
421		(void) pthread_mutex_destroy(&trans->sip_xaction_mutex);
422		free(trans->sip_xaction_branch_id);
423		free(trans);
424		if (error != NULL)
425			*error = ret;
426		return (NULL);
427	}
428	if (sip_xaction_ulp_state_cb != NULL &&
429	    prev_state != trans->sip_xaction_state) {
430		sip_xaction_ulp_state_cb((sip_transaction_t)trans,
431		    (sip_msg_t)msg, prev_state, trans->sip_xaction_state);
432	}
433	return (trans);
434}
435
436/*
437 * Find a transaction, create if asked for
438 */
439sip_xaction_t *
440sip_xaction_get(sip_conn_object_t obj, sip_msg_t msg, boolean_t create,
441    int which, int *error)
442{
443	char			*branchid;
444	sip_xaction_t		*sip_trans;
445	_sip_msg_t		*_msg;
446	sip_message_type_t	*sip_msg_info;
447
448	if (error != NULL)
449		*error = 0;
450
451	_msg = (_sip_msg_t *)msg;
452	sip_msg_info = ((_sip_msg_t *)msg)->sip_msg_req_res;
453
454	branchid = sip_get_branchid(msg, NULL);
455	sip_trans = sip_xaction_find(branchid, _msg, which);
456	if (sip_trans == NULL && create) {
457		/*
458		 * If we are sending a request, must be conformant to RFC 3261.
459		 */
460		if (sip_msg_info->is_request &&
461		    (branchid == NULL || strncmp(branchid,
462		    RFC_3261_BRANCH, strlen(RFC_3261_BRANCH) != 0))) {
463			if (error != NULL)
464				*error = EINVAL;
465			if (branchid != NULL)
466				free(branchid);
467			return (NULL);
468		}
469		sip_trans = sip_xaction_create(obj, _msg, branchid, error);
470		if (sip_trans != NULL)
471			SIP_XACTION_REFCNT_INCR(sip_trans);
472	}
473	if (branchid != NULL)
474		free(branchid);
475	return (sip_trans);
476}
477
478
479/*
480 * Delete a transaction if the reference count is 0. Passed to
481 * sip_hash_delete().
482 */
483boolean_t
484sip_xaction_remove(void *obj, void *hindex, int *found)
485{
486	sip_xaction_t	*tmp = (sip_xaction_t *)obj;
487	int		count = 0;
488	sip_msg_chain_t	*msg_chain;
489	sip_msg_chain_t	*nmsg_chain;
490
491	*found = 0;
492	tmp = (sip_xaction_t *)obj;
493	(void) pthread_mutex_lock(&tmp->sip_xaction_mutex);
494	if (bcmp(tmp->sip_xaction_hash_digest, hindex,
495	    sizeof (tmp->sip_xaction_hash_digest)) == 0) {
496		*found = 1;
497		if (tmp->sip_xaction_ref_cnt != 0) {
498			(void) pthread_mutex_unlock(&tmp->sip_xaction_mutex);
499			return (B_FALSE);
500		}
501		(void) pthread_mutex_destroy(&tmp->sip_xaction_mutex);
502		SIP_CANCEL_TIMER(tmp->sip_xaction_TA);
503		SIP_CANCEL_TIMER(tmp->sip_xaction_TB);
504		SIP_CANCEL_TIMER(tmp->sip_xaction_TD);
505		SIP_CANCEL_TIMER(tmp->sip_xaction_TE);
506		SIP_CANCEL_TIMER(tmp->sip_xaction_TF);
507		SIP_CANCEL_TIMER(tmp->sip_xaction_TG);
508		SIP_CANCEL_TIMER(tmp->sip_xaction_TH);
509		SIP_CANCEL_TIMER(tmp->sip_xaction_TI);
510		SIP_CANCEL_TIMER(tmp->sip_xaction_TJ);
511		SIP_CANCEL_TIMER(tmp->sip_xaction_TK);
512		sip_write_to_log((void *)tmp, SIP_TRANSACTION_LOG, NULL, 0);
513		free(tmp->sip_xaction_branch_id);
514		if (tmp->sip_xaction_last_msg != NULL) {
515			SIP_MSG_REFCNT_DECR(tmp->sip_xaction_last_msg);
516			tmp->sip_xaction_last_msg = NULL;
517		}
518		if (tmp->sip_xaction_orig_msg != NULL) {
519			SIP_MSG_REFCNT_DECR(tmp->sip_xaction_orig_msg);
520			tmp->sip_xaction_orig_msg = NULL;
521		}
522		if (tmp->sip_xaction_conn_obj != NULL) {
523			sip_del_conn_obj_cache(tmp->sip_xaction_conn_obj,
524			    (void *)tmp);
525		}
526		/*
527		 * If the transaction logging is disabled before we could
528		 * write the captured messages into the transaction log, then
529		 * we need to free those captured messsages
530		 */
531		for (count = 0; count <= SIP_SRV_NONINV_TERMINATED; count++) {
532			msg_chain = tmp->sip_xaction_log[count].sip_msgs;
533			while (msg_chain != NULL) {
534				nmsg_chain = msg_chain->next;
535				if (msg_chain->sip_msg != NULL)
536					free(msg_chain->sip_msg);
537				free(msg_chain);
538				msg_chain = nmsg_chain;
539			}
540		}
541		free(tmp);
542		return (B_TRUE);
543	}
544	(void) pthread_mutex_unlock(&tmp->sip_xaction_mutex);
545	return (B_FALSE);
546}
547
548/*
549 * Delete a SIP transaction
550 */
551void
552sip_xaction_delete(sip_xaction_t *trans)
553{
554	int	hindex;
555
556	(void) pthread_mutex_lock(&trans->sip_xaction_mutex);
557	hindex = SIP_DIGEST_TO_HASH(trans->sip_xaction_hash_digest);
558	if (trans->sip_xaction_ref_cnt != 0) {
559		(void) pthread_mutex_unlock(&trans->sip_xaction_mutex);
560		return;
561	}
562	(void) pthread_mutex_unlock(&trans->sip_xaction_mutex);
563	sip_hash_delete(sip_xaction_hash, trans->sip_xaction_hash_digest,
564	    hindex, sip_xaction_remove);
565}
566
567/*
568 * Add a SIP transaction into the hash list.
569 */
570int
571sip_xaction_add(sip_xaction_t *trans, char *branchid, _sip_msg_t *msg,
572    sip_method_t method)
573{
574	uint16_t	hash_index[8];
575
576	if (sip_find_md5_digest(branchid, msg, hash_index, method) != 0)
577		return (EINVAL);
578
579	/*
580	 * trans is not in the list as yet, so no need to hold the lock
581	 */
582	bcopy(hash_index, trans->sip_xaction_hash_digest, sizeof (hash_index));
583
584	if (sip_hash_add(sip_xaction_hash, (void *)trans,
585	    SIP_DIGEST_TO_HASH(hash_index)) != 0) {
586		return (ENOMEM);
587	}
588	return (0);
589}
590
591
592/*
593 * Given a state, return the  string - This is mostly for debug purposes
594 */
595char *
596sip_get_xaction_state(int state)
597{
598	switch (state) {
599		case SIP_NEW_TRANSACTION:
600			return ("SIP_NEW_TRANSACTION");
601		case SIP_CLNT_CALLING:
602			return ("SIP_CLNT_CALLING");
603		case SIP_CLNT_INV_PROCEEDING:
604			return ("SIP_CLNT_INV_PROCEEDING");
605		case SIP_CLNT_INV_TERMINATED:
606			return ("SIP_CLNT_INV_TERMINATED");
607		case SIP_CLNT_INV_COMPLETED:
608			return ("SIP_CLNT_INV_COMPLETED");
609		case SIP_CLNT_TRYING:
610			return ("SIP_CLNT_TRYING");
611		case SIP_CLNT_NONINV_PROCEEDING:
612			return ("SIP_CLNT_NONINV_PROCEEDING");
613		case SIP_CLNT_NONINV_TERMINATED:
614			return ("SIP_CLNT_NONINV_TERMINATED");
615		case SIP_CLNT_NONINV_COMPLETED:
616			return ("SIP_CLNT_NONINV_COMPLETED");
617		case SIP_SRV_INV_PROCEEDING:
618			return ("SIP_SRV_INV_PROCEEDING");
619		case SIP_SRV_INV_COMPLETED:
620			return ("SIP_SRV_INV_COMPLETED");
621		case SIP_SRV_CONFIRMED:
622			return ("SIP_SRV_CONFIRMED");
623		case SIP_SRV_INV_TERMINATED:
624			return ("SIP_SRV_INV_TERMINATED");
625		case SIP_SRV_TRYING:
626			return ("SIP_SRV_TRYING");
627		case SIP_SRV_NONINV_PROCEEDING:
628			return ("SIP_SRV_NONINV_PROCEEDING");
629		case SIP_SRV_NONINV_COMPLETED:
630			return ("SIP_SRV_NONINV_COMPLETED");
631		case SIP_SRV_NONINV_TERMINATED:
632			return ("SIP_SRV_NONINV_TERMINATED");
633		default :
634			return ("UNKNOWN");
635	}
636}
637
638/*
639 * Initialize the hash table etc.
640 */
641void
642sip_xaction_init(int (*ulp_trans_err)(sip_transaction_t, int, void *),
643    void (*ulp_state_cb)(sip_transaction_t, sip_msg_t, int, int))
644{
645	int	cnt;
646
647	for (cnt = 0; cnt < SIP_HASH_SZ; cnt++) {
648		sip_xaction_hash[cnt].hash_count = 0;
649		sip_xaction_hash[cnt].hash_head = NULL;
650		sip_xaction_hash[cnt].hash_tail = NULL;
651		(void) pthread_mutex_init(
652		    &sip_xaction_hash[cnt].sip_hash_mutex, NULL);
653	}
654	if (ulp_trans_err != NULL)
655		sip_xaction_ulp_trans_err = ulp_trans_err;
656	if (ulp_state_cb != NULL)
657		sip_xaction_ulp_state_cb = ulp_state_cb;
658}
659