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 2007 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 <stdio.h>
30#include <stdlib.h>
31#include <assert.h>
32#include <ctype.h>
33#include <errno.h>
34#include <strings.h>
35#include <pthread.h>
36#include <sip.h>
37
38#include "sip_msg.h"
39#include "sip_miscdefs.h"
40#include "sip_parse_uri.h"
41#include "sip_xaction.h"
42
43#define	SIP_BUF_SIZE	128
44
45/*
46 * Find the header named header, consecutive calls with old_header
47 * passed in will return next header of the same type.
48 * If no name is passed the first header is returned. consectutive calls
49 * with no name but an old header will return the next header.
50 */
51const struct sip_header *
52sip_get_header(sip_msg_t sip_msg, char *header_name, sip_header_t old_header,
53    int *error)
54{
55	_sip_msg_t		*_sip_msg;
56	const struct sip_header	*sip_hdr;
57
58	if (error != NULL)
59		*error = 0;
60	if (sip_msg == NULL) {
61		if (error != NULL)
62			*error = EINVAL;
63		return (NULL);
64	}
65	_sip_msg = (_sip_msg_t *)sip_msg;
66	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
67	sip_hdr = (sip_header_t)sip_search_for_header((_sip_msg_t *)sip_msg,
68	    header_name, (_sip_header_t *)old_header);
69	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
70	if (sip_hdr == NULL && error != NULL)
71		*error = EINVAL;
72	return (sip_hdr);
73}
74
75/*
76 * Return the request line as a string. Caller releases the returned string.
77 */
78char *
79sip_reqline_to_str(sip_msg_t sip_msg, int *error)
80{
81	char	*reqstr;
82
83	if (error != NULL)
84		*error = 0;
85	if (sip_msg == NULL || !sip_msg_is_request(sip_msg, error)) {
86		if (error != NULL)
87			*error = EINVAL;
88		return (NULL);
89	}
90	reqstr = _sip_startline_to_str((_sip_msg_t *)sip_msg, error);
91	return (reqstr);
92}
93
94/*
95 * Return the response line as a string. Caller releases the returned string.
96 */
97char *
98sip_respline_to_str(sip_msg_t sip_msg, int *error)
99{
100	char	*respstr;
101
102	if (error != NULL)
103		*error = 0;
104	if (sip_msg == NULL || sip_msg_is_request(sip_msg, error)) {
105		if (error != NULL)
106			*error = EINVAL;
107		return (NULL);
108	}
109	respstr = _sip_startline_to_str((_sip_msg_t *)sip_msg, error);
110	return (respstr);
111}
112
113/*
114 * return the first value of the header
115 */
116const struct sip_value *
117sip_get_header_value(const struct sip_header *sip_header, int *error)
118{
119	_sip_header_t		*_sip_header;
120	sip_parsed_header_t	*sip_parsed_header;
121	int			ret = 0;
122	const struct sip_value	*value;
123
124	if (error != NULL)
125		*error = 0;
126	if (sip_header == NULL) {
127		if (error != NULL)
128			*error = EINVAL;
129		return (NULL);
130	}
131	_sip_header = (_sip_header_t *)sip_header;
132	if (_sip_header->sip_hdr_sipmsg != NULL) {
133		(void) pthread_mutex_lock(
134		    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
135	}
136	if (_sip_header->sip_header_state == SIP_HEADER_DELETED) {
137		if (_sip_header->sip_hdr_sipmsg != NULL) {
138			(void) pthread_mutex_unlock(
139			    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
140		}
141		if (error != NULL)
142			*error = EINVAL;
143		return (NULL);
144	}
145	ret = _sip_header->sip_header_functions->header_parse_func(
146	    _sip_header, &sip_parsed_header);
147	if (_sip_header->sip_hdr_sipmsg != NULL) {
148		(void) pthread_mutex_unlock
149		    (&_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
150	}
151	if (error != NULL)
152		*error = ret;
153
154	if (ret != 0)
155		return (NULL);
156	value = (sip_header_value_t)sip_parsed_header->value;
157	while (value != NULL && value->value_state == SIP_VALUE_DELETED)
158		value = value->next;
159	if (value != NULL && value->value_state == SIP_VALUE_BAD &&
160	    error != NULL) {
161		*error = EPROTO;
162	}
163	return ((sip_header_value_t)value);
164}
165
166/*
167 * Return the next value of the header.
168 */
169const struct sip_value *
170sip_get_next_value(sip_header_value_t old_value, int *error)
171{
172	const struct sip_value *value;
173
174	if (error != NULL)
175		*error = 0;
176	if (old_value == NULL || old_value->next == NULL) {
177		if (error != NULL)
178			*error = EINVAL;
179		return (NULL);
180	}
181	/*
182	 * We never free the deleted values so no need to hold a lock.
183	 */
184	value = (sip_header_value_t)old_value->next;
185	while (value != NULL && value->value_state == SIP_VALUE_DELETED)
186		value = value->next;
187	if (value != NULL && value->value_state == SIP_VALUE_BAD &&
188	    error != NULL) {
189		*error = EPROTO;
190	}
191	return ((sip_header_value_t)value);
192}
193
194/*
195 * Given a SIP message, delete the header "header_name".
196 */
197int
198sip_delete_header_by_name(sip_msg_t msg, char *header_name)
199{
200	_sip_msg_t	*_msg = (_sip_msg_t *)msg;
201	sip_header_t	sip_hdr;
202	_sip_header_t	*_sip_hdr;
203
204	if (_msg == NULL || header_name == NULL)
205		return (EINVAL);
206	(void) pthread_mutex_lock(&_msg->sip_msg_mutex);
207	if (_msg->sip_msg_cannot_be_modified) {
208		(void) pthread_mutex_unlock(&_msg->sip_msg_mutex);
209		return (EPERM);
210	}
211	sip_hdr = (sip_header_t)sip_search_for_header(_msg, header_name, NULL);
212	if (sip_hdr == NULL) {
213		(void) pthread_mutex_unlock(&_msg->sip_msg_mutex);
214		return (EINVAL);
215	}
216	_sip_hdr = (_sip_header_t *)sip_hdr;
217	_sip_hdr->sip_header_state = SIP_HEADER_DELETED;
218	_sip_hdr->sip_hdr_sipmsg->sip_msg_len -= _sip_hdr->sip_hdr_end -
219	    _sip_hdr->sip_hdr_start;
220	assert(_sip_hdr->sip_hdr_sipmsg->sip_msg_len >= 0);
221	if (_msg->sip_msg_buf != NULL)
222		_msg->sip_msg_modified = B_TRUE;
223	(void) pthread_mutex_unlock(&_msg->sip_msg_mutex);
224
225	return (0);
226}
227
228/*
229 * Mark the header as deleted.
230 */
231int
232sip_delete_header(sip_header_t sip_header)
233{
234	_sip_header_t	*_sip_header;
235
236	if (sip_header == NULL)
237		return (EINVAL);
238	_sip_header = (_sip_header_t *)sip_header;
239	(void) pthread_mutex_lock(&_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
240	if (_sip_header->sip_hdr_sipmsg->sip_msg_cannot_be_modified) {
241		(void) pthread_mutex_unlock
242		    (&_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
243		return (EPERM);
244	}
245	if (_sip_header->sip_header_state == SIP_HEADER_DELETED) {
246		(void) pthread_mutex_unlock(
247		    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
248		return (EINVAL);
249	}
250	_sip_header->sip_header_state = SIP_HEADER_DELETED;
251	_sip_header->sip_hdr_sipmsg->sip_msg_len -= _sip_header->sip_hdr_end -
252	    _sip_header->sip_hdr_start;
253	assert(_sip_header->sip_hdr_sipmsg->sip_msg_len >= 0);
254	if (_sip_header->sip_hdr_sipmsg->sip_msg_buf != NULL)
255		_sip_header->sip_hdr_sipmsg->sip_msg_modified = B_TRUE;
256	(void) pthread_mutex_unlock
257	    (&_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
258	return (0);
259}
260
261/*
262 * Mark the value as deleted.
263 */
264int
265sip_delete_value(sip_header_t sip_header, sip_header_value_t sip_header_value)
266{
267	_sip_header_t	*_sip_header;
268	sip_value_t	*_sip_header_value;
269	int		vlen;
270	char		*c;
271
272	if (sip_header == NULL || sip_header_value == NULL)
273		return (EINVAL);
274	_sip_header = (_sip_header_t *)sip_header;
275	(void) pthread_mutex_lock(&_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
276	if (_sip_header->sip_hdr_sipmsg->sip_msg_cannot_be_modified) {
277		(void) pthread_mutex_unlock(&_sip_header->
278		    sip_hdr_sipmsg->sip_msg_mutex);
279		return (EPERM);
280	}
281	if (_sip_header->sip_header_state == SIP_HEADER_DELETED) {
282		(void) pthread_mutex_unlock(
283		    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
284		return (EINVAL);
285	}
286	_sip_header_value = (sip_value_t *)sip_header_value;
287	if (_sip_header_value->value_state == SIP_VALUE_DELETED) {
288		(void) pthread_mutex_unlock(
289		    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
290		return (EINVAL);
291	}
292	_sip_header->sip_header_state = SIP_HEADER_DELETED_VAL;
293	_sip_header_value->value_state = SIP_VALUE_DELETED;
294	vlen = _sip_header_value->value_end - _sip_header_value->value_start;
295	if (_sip_header->sip_hdr_parsed->value == _sip_header_value) {
296		c = _sip_header_value->value_start;
297		while (*c-- != SIP_HCOLON)
298			vlen++;
299	} else {
300		c = _sip_header_value->value_start;
301		while (*c-- != SIP_COMMA)
302			vlen++;
303	}
304	if (_sip_header_value->next == NULL) {
305		sip_value_t	*value = _sip_header->sip_hdr_parsed->value;
306		boolean_t	crlf_present =  B_FALSE;
307		char		*s;
308
309		while (value != NULL && value != _sip_header_value) {
310			crlf_present = B_FALSE;
311
312			if (value->value_state == SIP_VALUE_DELETED) {
313				value = value->next;
314				continue;
315			}
316			s = value->value_end;
317			while (s != value->value_start) {
318				if (*s == '\r' && strncmp(s, SIP_CRLF,
319				    strlen(SIP_CRLF)) == 0) {
320					crlf_present = B_TRUE;
321					break;
322				}
323				s--;
324			}
325			value = value->next;
326		}
327		if (!crlf_present) {
328			c = _sip_header_value->value_end;
329			while (*c-- != '\r')
330				vlen--;
331			assert(vlen > 0);
332		}
333	}
334	_sip_header->sip_hdr_sipmsg->sip_msg_len -= vlen;
335	if (_sip_header->sip_hdr_sipmsg->sip_msg_buf != NULL)
336		_sip_header->sip_hdr_sipmsg->sip_msg_modified = B_TRUE;
337	(void) pthread_mutex_unlock
338	    (&_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
339	return (0);
340}
341
342/*
343 * Given a param list, check if a param name exists.
344 */
345boolean_t
346sip_is_param_present(const sip_param_t *param_list, char *param_name,
347    int param_len)
348{
349	const sip_param_t	*param = param_list;
350
351	while (param != NULL) {
352		if (param->param_name.sip_str_len == param_len &&
353		    strncasecmp(param->param_name.sip_str_ptr, param_name,
354			param_len) == 0) {
355			return (B_TRUE);
356		}
357		param = param->param_next;
358	}
359	return (B_FALSE);
360}
361
362
363/*
364 * Given a value header return the value of the named param.
365 */
366const sip_str_t *
367sip_get_param_value(sip_header_value_t header_value, char *param_name,
368    int *error)
369{
370	sip_value_t	*_sip_header_value;
371	sip_param_t	*sip_param;
372
373	if (error != NULL)
374		*error = 0;
375	if (header_value == NULL || param_name == NULL) {
376		if (error != NULL)
377			*error = EINVAL;
378		return (NULL);
379	}
380	_sip_header_value = (sip_value_t *)header_value;
381	if (_sip_header_value->value_state == SIP_VALUE_DELETED) {
382		if (error != NULL)
383			*error = EINVAL;
384		return (NULL);
385	}
386	if (_sip_header_value->param_list == NULL) {
387		if (error != NULL)
388			*error = EINVAL;
389		return (NULL);
390	}
391	sip_param = sip_get_param_from_list(_sip_header_value->param_list,
392	    param_name);
393	if (sip_param != NULL)
394		return (&sip_param->param_value);
395	return (NULL);
396}
397
398/*
399 * Return the list of params in the header
400 */
401const sip_param_t *
402sip_get_params(sip_header_value_t header_value, int *error)
403{
404	sip_value_t	*sip_header_value;
405
406	if (error != NULL)
407		*error = 0;
408	if (header_value == NULL) {
409		if (error != NULL)
410			*error = EINVAL;
411		return (NULL);
412	}
413	sip_header_value = (sip_value_t *)header_value;
414	if (sip_header_value->value_state == SIP_VALUE_DELETED) {
415		if (error != NULL)
416			*error = EINVAL;
417		return (NULL);
418	}
419	return (sip_header_value->param_list);
420}
421
422/*
423 * Return true if this is a SIP request
424 */
425boolean_t
426sip_msg_is_request(sip_msg_t sip_msg, int *error)
427{
428	_sip_msg_t		*_sip_msg;
429	sip_message_type_t	*sip_msg_info;
430	boolean_t		ret;
431
432	if (error != NULL)
433		*error = 0;
434	if (sip_msg == NULL) {
435		if (error != NULL)
436			*error = EINVAL;
437		return (B_FALSE);
438	}
439	_sip_msg = (_sip_msg_t *)sip_msg;
440	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
441	if (_sip_msg->sip_msg_req_res == NULL) {
442		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
443		if (error != NULL)
444			*error = EINVAL;
445		return (B_FALSE);
446	}
447	sip_msg_info = _sip_msg->sip_msg_req_res;
448	ret = sip_msg_info->is_request;
449	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
450	return (ret);
451}
452
453/*
454 * Return true if this is a SIP response
455 */
456boolean_t
457sip_msg_is_response(sip_msg_t sip_msg, int *error)
458{
459	boolean_t		is_resp;
460	_sip_msg_t		*_sip_msg;
461	sip_message_type_t	*sip_msg_info;
462
463	if (error != NULL)
464		*error = 0;
465	if (sip_msg == NULL) {
466		if (error != NULL)
467			*error = EINVAL;
468		return (B_FALSE);
469	}
470	_sip_msg = (_sip_msg_t *)sip_msg;
471	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
472	if (_sip_msg->sip_msg_req_res == NULL) {
473		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
474		if (error != NULL)
475			*error = EINVAL;
476		return (B_FALSE);
477	}
478	sip_msg_info = _sip_msg->sip_msg_req_res;
479	is_resp = !sip_msg_info->is_request;
480	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
481	return (is_resp);
482}
483
484/*
485 * Return the method in the request line
486 */
487sip_method_t
488sip_get_request_method(sip_msg_t sip_msg, int *error)
489{
490	_sip_msg_t		*_sip_msg;
491	sip_message_type_t	*sip_msg_info;
492	sip_method_t 		ret = -1;
493
494	if (error != NULL)
495		*error = 0;
496	if (sip_msg == NULL) {
497		if (error != NULL)
498			*error = EINVAL;
499		return (ret);
500	}
501	_sip_msg = (_sip_msg_t *)sip_msg;
502	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
503	sip_msg_info = _sip_msg->sip_msg_req_res;
504	if (_sip_msg->sip_msg_req_res == NULL) {
505		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
506		if (error != NULL)
507			*error = EINVAL;
508		return (ret);
509	}
510	if (sip_msg_info->is_request)
511		ret = sip_msg_info->sip_req_method;
512	else if (error != NULL)
513		*error = EINVAL;
514	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
515	return (ret);
516}
517
518/*
519 * Return the URI from the request line
520 */
521const sip_str_t *
522sip_get_request_uri_str(sip_msg_t sip_msg, int *error)
523{
524	_sip_msg_t		*_sip_msg;
525	sip_message_type_t	*sip_msg_info;
526	sip_str_t 		*ret = NULL;
527	struct sip_uri		*parsed_uri;
528
529	if (error != NULL)
530		*error = 0;
531	if (sip_msg == NULL) {
532		if (error != NULL)
533			*error = EINVAL;
534		return (NULL);
535	}
536	_sip_msg = (_sip_msg_t *)sip_msg;
537	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
538	if (_sip_msg->sip_msg_req_res == NULL) {
539		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
540		if (error != NULL)
541			*error = EINVAL;
542		return (NULL);
543	}
544	sip_msg_info = _sip_msg->sip_msg_req_res;
545	if (sip_msg_info->is_request)
546		ret = &sip_msg_info->sip_req_uri;
547	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
548
549	/*
550	 * If the error is required, check the validity of the URI via
551	 * sip_uri_parse().
552	 */
553	if (error != NULL) {
554		parsed_uri = sip_parse_uri(ret, error);
555		if (parsed_uri != NULL)
556			sip_free_parsed_uri((sip_uri_t)parsed_uri);
557	}
558	return (ret);
559}
560
561/*
562 * Return the response code
563 */
564int
565sip_get_response_code(sip_msg_t sip_msg, int *error)
566{
567	_sip_msg_t		*_sip_msg;
568	sip_message_type_t	*sip_msg_info;
569	int 			ret = -1;
570
571	if (error != NULL)
572		*error = 0;
573	if (sip_msg == NULL) {
574		if (error != NULL)
575			*error = EINVAL;
576		return (ret);
577	}
578	_sip_msg = (_sip_msg_t *)sip_msg;
579	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
580	if (_sip_msg->sip_msg_req_res == NULL) {
581		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
582		if (error != NULL)
583			*error = EINVAL;
584		return (ret);
585	}
586	sip_msg_info = _sip_msg->sip_msg_req_res;
587	if (!sip_msg_info->is_request)
588		ret = sip_msg_info->sip_resp_code;
589	else if (error != NULL)
590		*error = EINVAL;
591	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
592	return (ret);
593}
594
595/*
596 * Get the response phrase
597 */
598const sip_str_t *
599sip_get_response_phrase(sip_msg_t sip_msg, int *error)
600{
601	_sip_msg_t		*_sip_msg;
602	sip_message_type_t	*sip_msg_info;
603	sip_str_t 		*ret = NULL;
604
605	if (error != NULL)
606		*error = 0;
607	if (sip_msg == NULL) {
608		if (error != NULL)
609			*error = EINVAL;
610		return (ret);
611	}
612	_sip_msg = (_sip_msg_t *)sip_msg;
613	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
614	if (_sip_msg->sip_msg_req_res == NULL) {
615		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
616		if (error != NULL)
617			*error = EINVAL;
618		return (ret);
619	}
620	sip_msg_info = _sip_msg->sip_msg_req_res;
621	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
622	if (!sip_msg_info->is_request) {
623		if (sip_msg_info->sip_resp_phrase_len == 0)
624			ret = NULL;
625		else
626			ret = &sip_msg_info->sip_resp_phrase;
627	} else if (error != NULL) {
628		*error = EINVAL;
629	}
630	return (ret);
631}
632
633/*
634 * Get the SIP version string
635 */
636const sip_str_t *
637sip_get_sip_version(sip_msg_t sip_msg, int *error)
638{
639	_sip_msg_t		*_sip_msg;
640	sip_message_type_t	*sip_msg_info;
641	sip_str_t		*ret = NULL;
642
643	if (error != NULL)
644		*error = 0;
645	if (sip_msg == NULL) {
646		if (error != NULL)
647			*error = EINVAL;
648		return (ret);
649	}
650	_sip_msg = (_sip_msg_t *)sip_msg;
651	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
652	if (_sip_msg->sip_msg_req_res == NULL) {
653		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
654		if (error != NULL)
655			*error = EINVAL;
656		return (ret);
657	}
658	sip_msg_info = _sip_msg->sip_msg_req_res;
659	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
660	ret = &sip_msg_info->sip_proto_version.version;
661	return (ret);
662}
663
664/*
665 * Return the length of the SIP message
666 */
667int
668sip_get_msg_len(sip_msg_t sip_msg, int *error)
669{
670	_sip_msg_t	*_sip_msg;
671
672	if (error != NULL)
673		*error = 0;
674	if (sip_msg == NULL) {
675		if (error != NULL)
676			*error = EINVAL;
677		return (-1);
678	}
679	_sip_msg = (_sip_msg_t *)sip_msg;
680
681	return (_sip_msg->sip_msg_len);
682}
683
684/*
685 * Get content as a string. Caller frees the string
686 */
687char *
688sip_get_content(sip_msg_t sip_msg, int *error)
689{
690	_sip_msg_t	*_sip_msg;
691	sip_content_t	*sip_content;
692	char		*content;
693	int		len;
694	char		*p;
695
696	if (error != NULL)
697		*error = 0;
698
699	if (sip_msg == NULL) {
700		if (error != NULL)
701			*error = EINVAL;
702		return (NULL);
703	}
704	_sip_msg = (_sip_msg_t *)sip_msg;
705	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
706	if (_sip_msg->sip_msg_content == NULL) {
707		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
708		if (error != NULL)
709			*error = EINVAL;
710		return (NULL);
711	}
712	content = malloc(_sip_msg->sip_msg_content_len + 1);
713	if (content == NULL) {
714		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
715		if (error != NULL)
716			*error = ENOMEM;
717		return (NULL);
718	}
719	p = content;
720	sip_content = _sip_msg->sip_msg_content;
721	while (sip_content != NULL) {
722		len =  sip_content->sip_content_end -
723		    sip_content->sip_content_start;
724		(void) strncpy(p, sip_content->sip_content_start, len);
725		p += len;
726		sip_content = sip_content->sip_content_next;
727	}
728	content[_sip_msg->sip_msg_content_len] = '\0';
729	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
730	return (content);
731}
732
733/*
734 * copy sip_header with param, if any, to sip_msg
735 */
736int
737sip_copy_header(sip_msg_t sip_msg, sip_header_t sip_header, char *param)
738{
739	_sip_msg_t	*_sip_msg;
740	_sip_header_t	*_sip_header;
741	int		ret;
742
743	if (sip_msg == NULL || sip_header == NULL)
744		return (EINVAL);
745	_sip_msg = (_sip_msg_t *)sip_msg;
746	_sip_header = (_sip_header_t *)sip_header;
747	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
748	if (_sip_msg->sip_msg_cannot_be_modified) {
749		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
750		return (EPERM);
751	}
752	if (_sip_header->sip_header_state == SIP_HEADER_DELETED) {
753		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
754		return (EINVAL);
755	}
756
757	ret = _sip_copy_header(_sip_msg, _sip_header, param, B_TRUE);
758	if (_sip_msg->sip_msg_buf != NULL)
759		_sip_msg->sip_msg_modified = B_TRUE;
760	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
761	return (ret);
762}
763
764/*
765 * copy the header specified by header_name, with param, if any
766 */
767int
768sip_copy_header_by_name(sip_msg_t old_msg, sip_msg_t new_msg,
769    char *header_name, char *param)
770{
771	int		ret;
772	_sip_msg_t	*_old_msg = (_sip_msg_t *)old_msg;
773	_sip_msg_t	*_new_msg = (_sip_msg_t *)new_msg;
774
775	if (_old_msg == NULL || _new_msg == NULL || header_name == NULL ||
776	    _old_msg == _new_msg) {
777		return (EINVAL);
778	}
779	(void) pthread_mutex_lock(&_new_msg->sip_msg_mutex);
780	if (_new_msg->sip_msg_cannot_be_modified) {
781		(void) pthread_mutex_unlock(&_new_msg->sip_msg_mutex);
782		return (EPERM);
783	}
784
785	(void) pthread_mutex_lock(&_old_msg->sip_msg_mutex);
786	ret = _sip_find_and_copy_header(_old_msg, _new_msg, header_name, param,
787	    B_FALSE);
788	(void) pthread_mutex_unlock(&_old_msg->sip_msg_mutex);
789	if (_new_msg->sip_msg_buf != NULL)
790		_new_msg->sip_msg_modified = B_TRUE;
791	(void) pthread_mutex_unlock(&_new_msg->sip_msg_mutex);
792	return (ret);
793}
794
795/*
796 * add the given header to sip_message
797 */
798int
799sip_add_header(sip_msg_t sip_msg, char *header_string)
800{
801	int		header_size;
802	_sip_header_t	*new_header;
803	_sip_msg_t	*_sip_msg;
804
805	if (sip_msg == NULL || header_string == NULL)
806		return (EINVAL);
807	_sip_msg = (_sip_msg_t *)sip_msg;
808	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
809	if (_sip_msg->sip_msg_cannot_be_modified) {
810		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
811		return (EPERM);
812	}
813	header_size = strlen(header_string) + strlen(SIP_CRLF);
814	new_header = sip_new_header(header_size);
815	if (new_header == NULL) {
816		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
817		return (ENOMEM);
818	}
819
820	(void) snprintf(new_header->sip_hdr_start, header_size + 1, "%s%s",
821	    header_string, SIP_CRLF);
822	_sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
823	if (_sip_msg->sip_msg_buf != NULL)
824		_sip_msg->sip_msg_modified = B_TRUE;
825	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
826	return (0);
827}
828
829/*
830 * add the given param to the sip_header. create a new header with the param
831 * and mark the old header as deleted.
832 */
833sip_header_t
834sip_add_param(sip_header_t sip_header, char *param, int *error)
835{
836	_sip_header_t	*_sip_header;
837	_sip_header_t	*new_header;
838	int		hdrlen;
839	_sip_msg_t	*_sip_msg;
840	int		param_len;
841	char		*tmp_ptr;
842
843	if (error != NULL)
844		*error = 0;
845
846	if (param == NULL || sip_header == NULL) {
847		if (error != NULL)
848			*error = EINVAL;
849		return (NULL);
850	}
851
852	_sip_header = (_sip_header_t *)sip_header;
853
854	(void) pthread_mutex_lock(&_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
855	if (_sip_header->sip_hdr_sipmsg->sip_msg_cannot_be_modified) {
856		if (error != NULL)
857			*error = EPERM;
858		(void) pthread_mutex_unlock(
859		    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
860		return (NULL);
861	}
862	if (_sip_header->sip_header_state == SIP_HEADER_DELETED) {
863		if (error != NULL)
864			*error = EINVAL;
865		(void) pthread_mutex_unlock(
866		    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
867		return (NULL);
868	}
869
870	param_len = SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN +
871	    strlen(param);
872	hdrlen = _sip_header->sip_hdr_end - _sip_header->sip_hdr_start;
873	new_header = sip_new_header(hdrlen + param_len);
874	if (new_header == NULL) {
875		if (error != NULL)
876			*error = ENOMEM;
877		(void) pthread_mutex_unlock(
878		    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
879		return (NULL);
880	}
881	(void) memcpy(new_header->sip_hdr_start, _sip_header->sip_hdr_start,
882	    hdrlen);
883	new_header->sip_hdr_end = new_header->sip_hdr_start + hdrlen;
884	hdrlen = param_len + 1;
885	/*
886	 * Find CRLF
887	 */
888	tmp_ptr = new_header->sip_hdr_end;
889	while (*tmp_ptr-- != '\n') {
890		hdrlen++;
891		if (tmp_ptr == new_header->sip_hdr_start) {
892			sip_free_header(new_header);
893			if (error != NULL)
894				*error = EINVAL;
895			(void) pthread_mutex_unlock(
896			    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
897			return (NULL);
898		}
899	}
900	(void) snprintf(tmp_ptr, hdrlen + 1,
901	    " %c %s%s", SIP_SEMI, param, SIP_CRLF);
902	new_header->sip_hdr_end += param_len;
903	new_header->sip_header_functions = _sip_header->sip_header_functions;
904	_sip_msg = _sip_header->sip_hdr_sipmsg;
905	_sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
906	if (_sip_header->sip_hdr_sipmsg->sip_msg_buf != NULL)
907		_sip_header->sip_hdr_sipmsg->sip_msg_modified = B_TRUE;
908	(void) pthread_mutex_unlock(&new_header->sip_hdr_sipmsg->sip_msg_mutex);
909	(void) sip_delete_header(sip_header);
910	return ((sip_header_t)new_header);
911}
912
913/*
914 * Get Request URI
915 */
916const struct sip_uri *
917sip_get_request_uri(sip_msg_t sip_msg, int *error)
918{
919	_sip_msg_t		*_sip_msg;
920	sip_message_type_t	*sip_msg_info;
921	const struct sip_uri	*ret = NULL;
922
923	if (error != NULL)
924		*error = 0;
925
926	if (sip_msg == NULL) {
927		if (error != NULL)
928			*error = EINVAL;
929		return (NULL);
930	}
931	_sip_msg = (_sip_msg_t *)sip_msg;
932	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
933	sip_msg_info = _sip_msg->sip_msg_req_res;
934	if (sip_msg_info != NULL && sip_msg_info->is_request) {
935		ret = sip_msg_info->sip_req_parse_uri;
936	} else {
937		if (error != NULL)
938			*error = EINVAL;
939	}
940	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
941
942	if (ret != NULL) {
943		if (ret->sip_uri_scheme.sip_str_len == 0 ||
944		    ret->sip_uri_scheme.sip_str_ptr == NULL) {
945			ret = NULL;
946			if (error != NULL)
947				*error = EINVAL;
948		} else if (ret->sip_uri_errflags != 0 && error != NULL) {
949			*error = EINVAL;
950		}
951	}
952	return ((sip_uri_t)ret);
953}
954
955/*
956 * returns a comma separated string of all the sent-by values registered by
957 * the UA.
958 */
959char *
960sip_sent_by_to_str(int *error)
961{
962	sent_by_list_t	*sb;
963	int		sb_len = 0;
964	int		slen;
965	char		*sb_str;
966	char		*p;
967	int		count = 0;
968	int		cnt = 0;
969
970	if (error != NULL)
971		*error = 0;
972
973	(void) pthread_mutex_lock(&sip_sent_by_lock);
974	if (sip_sent_by == NULL) {
975		(void) pthread_mutex_unlock(&sip_sent_by_lock);
976		return (NULL);
977	}
978	sb = sip_sent_by;
979	for (cnt = 0; cnt < sip_sent_by_count; cnt++) {
980		sb_len += strlen(sb->sb_val);
981		sb = sb->sb_next;
982	}
983	/*
984	 * for the commas
985	 */
986	sb_len += sip_sent_by_count - 1;
987	sb_str = malloc(sb_len + 1);
988	if (sb_str == NULL) {
989		if (error != NULL)
990			*error = ENOMEM;
991		(void) pthread_mutex_unlock(&sip_sent_by_lock);
992		return (NULL);
993	}
994	sb = sip_sent_by;
995	p = sb_str;
996	slen = sb_len + 1;
997	for (cnt = 0; cnt < sip_sent_by_count; cnt++) {
998		if (cnt == 0) {
999			count = snprintf(p, slen, "%s", sb->sb_val);
1000		} else {
1001			count = snprintf(p, slen, "%c%s", SIP_COMMA,
1002			    sb->sb_val);
1003		}
1004		p += count;
1005		slen -= count;
1006		sb = sb->sb_next;
1007	}
1008	sb_str[sb_len] = '\0';
1009	(void) pthread_mutex_unlock(&sip_sent_by_lock);
1010	return (sb_str);
1011}
1012
1013/*
1014 * A comma separated list of sent-by values.
1015 */
1016int
1017sip_register_sent_by(char *val)
1018{
1019	sent_by_list_t	*sb = NULL;
1020	sent_by_list_t	*sb_tail = NULL;
1021	char		*str;
1022	int		count = 0;
1023
1024	if (val == NULL)
1025		return (EINVAL);
1026	str = strtok(val, ",");
1027	while (str != NULL) {
1028		int	slen;
1029		char	*start = str;
1030		char	*end = str + strlen(str) - 1;
1031
1032		while (isspace(*start))
1033			start++;
1034		while (isspace(*end))
1035			end--;
1036		if (end <= start)
1037			goto err_ret;
1038		slen = end - start + 1;
1039		sb_tail = (sent_by_list_t *)malloc(sizeof (*sb_tail));
1040		if (sb_tail == NULL)
1041			goto err_ret;
1042		sb_tail->sb_next = sb_tail->sb_prev = NULL;
1043		if ((sb_tail->sb_val = (char *)malloc(slen + 1)) == NULL) {
1044			free(sb_tail);
1045			goto err_ret;
1046		}
1047		(void) strncpy(sb_tail->sb_val, start, slen);
1048		sb_tail->sb_val[slen] = '\0';
1049		if (sb == NULL) {
1050			sb = sb_tail;
1051		} else {
1052			sb_tail->sb_next = sb;
1053			sb->sb_prev = sb_tail;
1054			sb = sb_tail;
1055		}
1056		count++;
1057		str = strtok(NULL, ",");
1058	}
1059	sb_tail = sb;
1060	while (sb_tail->sb_next != NULL)
1061		sb_tail = sb_tail->sb_next;
1062	(void) pthread_mutex_lock(&sip_sent_by_lock);
1063	if (sip_sent_by != NULL) {
1064		sb_tail->sb_next = sip_sent_by;
1065		sip_sent_by->sb_prev = sb_tail;
1066	}
1067	sip_sent_by = sb;
1068	sip_sent_by_count += count;
1069	(void) pthread_mutex_unlock(&sip_sent_by_lock);
1070	return (0);
1071err_ret:
1072	sb_tail = sb;
1073	for (; count > 0; count--) {
1074		sb = sb_tail->sb_next;
1075		free(sb_tail->sb_val);
1076		sb_tail->sb_next = NULL;
1077		sb_tail->sb_prev = NULL;
1078		free(sb_tail);
1079		sb_tail = sb;
1080	}
1081	return (EINVAL);
1082}
1083
1084/*
1085 * Un-register sent-by values; 'val' contains a comma separated list
1086 */
1087void
1088sip_unregister_sent_by(char *val)
1089{
1090	sent_by_list_t	*sb;
1091	char		*str;
1092	int		count = 0;
1093
1094	(void) pthread_mutex_lock(&sip_sent_by_lock);
1095	str = strtok(val, ",");
1096	while (str != NULL) {
1097		sb = sip_sent_by;
1098		for (count = 0; count < sip_sent_by_count; count++) {
1099			if (strncmp(sb->sb_val, str, strlen(str)) == 0) {
1100				if (sb == sip_sent_by) {
1101					if (sb->sb_next != NULL)
1102						sip_sent_by = sb->sb_next;
1103					else
1104						sip_sent_by = NULL;
1105				} else if (sb->sb_next == NULL) {
1106					sb->sb_prev->sb_next = NULL;
1107				} else {
1108					sb->sb_prev->sb_next = sb->sb_next;
1109					sb->sb_next->sb_prev = sb->sb_prev;
1110				}
1111				sip_sent_by_count--;
1112				sb->sb_next = NULL;
1113				sb->sb_prev = NULL;
1114				free(sb->sb_val);
1115				free(sb);
1116				break;
1117			}
1118			sb = sb->sb_next;
1119		}
1120		str = strtok(NULL, ",");
1121	}
1122	(void) pthread_mutex_unlock(&sip_sent_by_lock);
1123}
1124
1125/*
1126 * Un-register all the sent-by values
1127 */
1128void
1129sip_unregister_all_sent_by()
1130{
1131	sent_by_list_t	*sb;
1132	int		count;
1133
1134	(void) pthread_mutex_lock(&sip_sent_by_lock);
1135	sb = sip_sent_by;
1136	for (count = 0; count < sip_sent_by_count; count++) {
1137		sip_sent_by = sb->sb_next;
1138		free(sb->sb_val);
1139		sb->sb_next = NULL;
1140		sb->sb_prev = NULL;
1141		free(sb);
1142		sb = sip_sent_by;
1143	}
1144	sip_sent_by = NULL;
1145	sip_sent_by_count = 0;
1146	(void) pthread_mutex_unlock(&sip_sent_by_lock);
1147}
1148
1149/*
1150 * Given a response code, return the corresponding phrase
1151 */
1152char *
1153sip_get_resp_desc(int resp_code)
1154{
1155	switch (resp_code) {
1156	case SIP_TRYING:
1157		return ("TRYING");
1158	case SIP_RINGING:
1159		return ("RINGING");
1160	case SIP_CALL_IS_BEING_FORWARDED:
1161		return ("CALL_IS_BEING_FORWARDED");
1162	case SIP_QUEUED:
1163		return ("QUEUED");
1164	case SIP_SESSION_PROGRESS:
1165		return ("SESSION_PROGRESS");
1166	case SIP_OK:
1167		return ("OK");
1168	case SIP_ACCEPTED:
1169		return ("ACCEPTED");
1170	case SIP_MULTIPLE_CHOICES:
1171		return ("MULTIPLE_CHOICES");
1172	case SIP_MOVED_PERMANENTLY:
1173		return ("MOVED_PERMANENTLY");
1174	case SIP_MOVED_TEMPORARILY:
1175		return ("MOVED_TEMPORARILY");
1176	case SIP_USE_PROXY:
1177		return ("USE_PROXY");
1178	case SIP_ALTERNATIVE_SERVICE:
1179		return ("ALTERNATIVE_SERVICE");
1180	case SIP_BAD_REQUEST:
1181		return ("BAD_REQUEST");
1182	case SIP_UNAUTHORIZED:
1183		return ("UNAUTHORIZED");
1184	case SIP_PAYMENT_REQUIRED:
1185		return ("PAYMENT_REQUIRED");
1186	case SIP_FORBIDDEN:
1187		return ("FORBIDDEN");
1188	case SIP_NOT_FOUND:
1189		return ("NOT_FOUND");
1190	case SIP_METHOD_NOT_ALLOWED:
1191		return ("METHOD_NOT_ALLOWED");
1192	case SIP_NOT_ACCEPTABLE:
1193		return ("NOT_ACCEPTABLE");
1194	case SIP_PROXY_AUTH_REQUIRED:
1195		return ("PROXY_AUTH_REQUIRED");
1196	case SIP_REQUEST_TIMEOUT:
1197		return ("REQUEST_TIMEOUT");
1198	case SIP_GONE:
1199		return ("GONE");
1200	case SIP_REQUEST_ENTITY_2_LARGE:
1201		return ("REQUEST_ENTITY_2_LARGE");
1202	case SIP_REQUEST_URI_2_LONG:
1203		return ("REQUEST_URI_2_LONG");
1204	case SIP_UNSUPPORTED_MEDIA_TYPE:
1205		return ("UNSUPPORTED_MEDIA_TYPE");
1206	case SIP_UNSUPPORTED_URI_SCHEME:
1207		return ("UNSUPPORTED_URI_SCHEME");
1208	case SIP_BAD_EXTENSION:
1209		return ("BAD_EXTENSION");
1210	case SIP_EXTENSION_REQUIRED:
1211		return ("EXTENSION_REQUIRED");
1212	case SIP_INTERVAL_2_BRIEF:
1213		return ("INTERVAL_2_BRIEF");
1214	case SIP_TEMPORARILY_UNAVAIL:
1215		return ("TEMPORARILY_UNAVAIL");
1216	case SIP_CALL_NON_EXISTANT:
1217		return ("CALL_NON_EXISTANT");
1218	case SIP_LOOP_DETECTED:
1219		return ("LOOP_DETECTED");
1220	case SIP_TOO_MANY_HOOPS:
1221		return ("TOO_MANY_HOOPS");
1222	case SIP_ADDRESS_INCOMPLETE:
1223		return ("ADDRESS_INCOMPLETE");
1224	case SIP_AMBIGUOUS:
1225		return ("AMBIGUOUS");
1226	case SIP_BUSY_HERE:
1227		return ("BUSY_HERE");
1228	case SIP_REQUEST_TERMINATED:
1229		return ("REQUEST_TERMINATED");
1230	case SIP_NOT_ACCEPTABLE_HERE:
1231		return ("NOT_ACCEPTABLE_HERE");
1232	case SIP_BAD_EVENT:
1233		return ("BAD_EVENT");
1234	case SIP_REQUEST_PENDING:
1235		return ("REQUEST_PENDING");
1236	case SIP_UNDECIPHERABLE:
1237		return ("UNDECIPHERABLE");
1238	case SIP_SERVER_INTERNAL_ERROR:
1239		return ("SERVER_INTERNAL_ERROR");
1240	case SIP_NOT_IMPLEMENTED:
1241		return ("NOT_IMPLEMENTED");
1242	case SIP_BAD_GATEWAY:
1243		return ("BAD_GATEWAY");
1244	case SIP_SERVICE_UNAVAILABLE:
1245		return ("SERVICE_UNAVAILABLE");
1246	case SIP_SERVER_TIMEOUT:
1247		return ("SERVER_TIMEOUT");
1248	case SIP_VERSION_NOT_SUPPORTED:
1249		return ("VERSION_NOT_SUPPORTED");
1250	case SIP_MESSAGE_2_LARGE:
1251		return ("MESSAGE_2_LARGE");
1252	case SIP_BUSY_EVERYWHERE:
1253		return ("BUSY_EVERYWHERE");
1254	case SIP_DECLINE:
1255		return ("DECLINE");
1256	case SIP_DOES_NOT_EXIST_ANYWHERE:
1257		return ("DOES_NOT_EXIST_ANYWHERE");
1258	case SIP_NOT_ACCEPTABLE_ANYWHERE:
1259		return ("NOT_ACCEPTABLE_ANYWHERE");
1260	default:
1261		return ("UNKNOWN");
1262	}
1263}
1264
1265/*
1266 * The following three fns initialize and destroy the private library
1267 * data in sip_conn_object_t. The assumption is that the 1st member
1268 * of sip_conn_object_t is reserved for library use. The private data
1269 * is used only for byte-stream protocols such as TCP to accumulate
1270 * a complete SIP message, based on the CONTENT-LENGTH value, before
1271 * processing it.
1272 */
1273int
1274sip_init_conn_object(sip_conn_object_t obj)
1275{
1276	void			**obj_val;
1277	sip_conn_obj_pvt_t	*pvt_data;
1278
1279	if (obj == NULL)
1280		return (EINVAL);
1281	pvt_data =  malloc(sizeof (sip_conn_obj_pvt_t));
1282	if (pvt_data == NULL)
1283		return (ENOMEM);
1284	pvt_data->sip_conn_obj_cache = NULL;
1285	pvt_data->sip_conn_obj_reass = malloc(sizeof (sip_reass_entry_t));
1286	if (pvt_data->sip_conn_obj_reass == NULL) {
1287		free(pvt_data);
1288		return (ENOMEM);
1289	}
1290	bzero(pvt_data->sip_conn_obj_reass, sizeof (sip_reass_entry_t));
1291	(void) pthread_mutex_init(&pvt_data->sip_conn_obj_reass_lock, NULL);
1292	(void) pthread_mutex_init(&pvt_data->sip_conn_obj_cache_lock, NULL);
1293	sip_refhold_conn(obj);
1294	obj_val = (void *)obj;
1295	*obj_val = (void *)pvt_data;
1296
1297	return (0);
1298}
1299
1300/*
1301 * Clear private date, if any
1302 */
1303void
1304sip_clear_stale_data(sip_conn_object_t obj)
1305{
1306	void			**obj_val;
1307	sip_conn_obj_pvt_t	*pvt_data;
1308	sip_reass_entry_t	*reass;
1309
1310	if (obj == NULL)
1311		return;
1312	obj_val = (void *)obj;
1313	pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
1314	(void) pthread_mutex_lock(&pvt_data->sip_conn_obj_reass_lock);
1315	reass = pvt_data->sip_conn_obj_reass;
1316	if (reass->sip_reass_msg != NULL) {
1317		assert(reass->sip_reass_msglen > 0);
1318		free(reass->sip_reass_msg);
1319		reass->sip_reass_msglen = 0;
1320	}
1321	assert(reass->sip_reass_msglen == 0);
1322	(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
1323}
1324
1325/*
1326 * Walk through all the transactions, remove if this obj has been cached
1327 * by any.
1328 */
1329void
1330sip_conn_destroyed(sip_conn_object_t obj)
1331{
1332	void			**obj_val;
1333	sip_conn_obj_pvt_t	*pvt_data;
1334
1335	if (obj == NULL)
1336		return;
1337	obj_val = (void *)obj;
1338	pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
1339
1340	sip_clear_stale_data(obj);
1341	free(pvt_data->sip_conn_obj_reass);
1342	pvt_data->sip_conn_obj_reass = NULL;
1343	(void) pthread_mutex_destroy(&pvt_data->sip_conn_obj_reass_lock);
1344
1345	sip_del_conn_obj_cache(obj, NULL);
1346	(void) pthread_mutex_destroy(&pvt_data->sip_conn_obj_cache_lock);
1347
1348	free(pvt_data);
1349	*obj_val = NULL;
1350	sip_refrele_conn(obj);
1351}
1352