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