xref: /titanic_51/usr/src/lib/libsip/common/sip_msg.c (revision 2c2c41837e330b002c4220a39638150db504fe0e)
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*2c2c4183Svi117747  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
2440cb5e5dSvi117747  * Use is subject to license terms.
2540cb5e5dSvi117747  */
2640cb5e5dSvi117747 
2740cb5e5dSvi117747 #pragma ident	"%Z%%M%	%I%	%E% SMI"
2840cb5e5dSvi117747 
29*2c2c4183Svi117747 #include <stdio.h>
30*2c2c4183Svi117747 #include <assert.h>
31*2c2c4183Svi117747 #include <errno.h>
32*2c2c4183Svi117747 #include <pthread.h>
33*2c2c4183Svi117747 #include <stdlib.h>
34*2c2c4183Svi117747 #include <string.h>
35*2c2c4183Svi117747 #include <sip.h>
36*2c2c4183Svi117747 
3740cb5e5dSvi117747 #include "sip_msg.h"
3840cb5e5dSvi117747 #include "sip_miscdefs.h"
3940cb5e5dSvi117747 #include "sip_parse_generic.h"
4040cb5e5dSvi117747 
4140cb5e5dSvi117747 /*
4240cb5e5dSvi117747  * Response consists of SIP version, response code, response phrase and CRLF.
4340cb5e5dSvi117747  */
4440cb5e5dSvi117747 #define	SIP_RESPONSE	"%s %d %s%s"
4540cb5e5dSvi117747 
4640cb5e5dSvi117747 void sip_free_content(_sip_msg_t *);
4740cb5e5dSvi117747 
4840cb5e5dSvi117747 /*
4940cb5e5dSvi117747  * Allocate a new sip msg struct.
5040cb5e5dSvi117747  */
5140cb5e5dSvi117747 sip_msg_t
5240cb5e5dSvi117747 sip_new_msg()
5340cb5e5dSvi117747 {
5440cb5e5dSvi117747 	_sip_msg_t *sip_msg;
5540cb5e5dSvi117747 
5640cb5e5dSvi117747 	sip_msg = calloc(1, sizeof (_sip_msg_t));
5740cb5e5dSvi117747 	if (sip_msg != NULL) {
5840cb5e5dSvi117747 		sip_msg->sip_msg_ref_cnt = 1;
5940cb5e5dSvi117747 		(void) pthread_mutex_init(&sip_msg->sip_msg_mutex, NULL);
6040cb5e5dSvi117747 	}
6140cb5e5dSvi117747 	return ((sip_msg_t)sip_msg);
6240cb5e5dSvi117747 }
6340cb5e5dSvi117747 
6440cb5e5dSvi117747 /*
6540cb5e5dSvi117747  * Free all resources. The lock is taken by SIP_MSG_REFCNT_DECR. The
6640cb5e5dSvi117747  * thread that decrements the last refcount should take care that
6740cb5e5dSvi117747  * the message is not accessible to other threads before doing so.
6840cb5e5dSvi117747  * Else, if the message is still accessible to others, it is
6940cb5e5dSvi117747  * possible that the other thread could be waiting to take the
7040cb5e5dSvi117747  * lock when we proceed to destroy it.
7140cb5e5dSvi117747  */
7240cb5e5dSvi117747 void
7340cb5e5dSvi117747 sip_destroy_msg(_sip_msg_t *_sip_msg)
7440cb5e5dSvi117747 {
7540cb5e5dSvi117747 #ifdef	__solaris__
7640cb5e5dSvi117747 	assert(mutex_held(&_sip_msg->sip_msg_mutex));
7740cb5e5dSvi117747 #endif
7840cb5e5dSvi117747 	(void) sip_delete_start_line_locked(_sip_msg);
7940cb5e5dSvi117747 	assert(_sip_msg->sip_msg_ref_cnt == 0);
8040cb5e5dSvi117747 	sip_delete_all_headers((sip_msg_t)_sip_msg);
8140cb5e5dSvi117747 	sip_free_content(_sip_msg);
8240cb5e5dSvi117747 	if (_sip_msg->sip_msg_buf != NULL)
8340cb5e5dSvi117747 		free(_sip_msg->sip_msg_buf);
8440cb5e5dSvi117747 
8540cb5e5dSvi117747 	if (_sip_msg->sip_msg_old_buf != NULL)
8640cb5e5dSvi117747 		free(_sip_msg->sip_msg_old_buf);
8740cb5e5dSvi117747 
8840cb5e5dSvi117747 	while (_sip_msg->sip_msg_req_res != NULL) {
8940cb5e5dSvi117747 		sip_message_type_t	*sip_msg_type_ptr;
9040cb5e5dSvi117747 
9140cb5e5dSvi117747 		sip_msg_type_ptr = _sip_msg->sip_msg_req_res->sip_next;
9240cb5e5dSvi117747 		if (_sip_msg->sip_msg_req_res->is_request) {
9340cb5e5dSvi117747 			sip_request_t	*reqline;
9440cb5e5dSvi117747 
9540cb5e5dSvi117747 			reqline = &_sip_msg->sip_msg_req_res->U.sip_request;
9640cb5e5dSvi117747 			if (reqline->sip_parse_uri != NULL) {
9740cb5e5dSvi117747 				sip_free_parsed_uri(reqline->sip_parse_uri);
9840cb5e5dSvi117747 				reqline->sip_parse_uri = NULL;
9940cb5e5dSvi117747 			}
10040cb5e5dSvi117747 		}
10140cb5e5dSvi117747 		free(_sip_msg->sip_msg_req_res);
10240cb5e5dSvi117747 		_sip_msg->sip_msg_req_res = sip_msg_type_ptr;
10340cb5e5dSvi117747 	}
10440cb5e5dSvi117747 	(void) pthread_mutex_destroy(&_sip_msg->sip_msg_mutex);
10540cb5e5dSvi117747 	free(_sip_msg);
10640cb5e5dSvi117747 }
10740cb5e5dSvi117747 
10840cb5e5dSvi117747 /*
10940cb5e5dSvi117747  * Free a sip msg struct.
11040cb5e5dSvi117747  */
11140cb5e5dSvi117747 void
11240cb5e5dSvi117747 sip_free_msg(sip_msg_t sip_msg)
11340cb5e5dSvi117747 {
11440cb5e5dSvi117747 	if (sip_msg == NULL)
11540cb5e5dSvi117747 		return;
11640cb5e5dSvi117747 
11740cb5e5dSvi117747 	SIP_MSG_REFCNT_DECR((_sip_msg_t *)sip_msg);
11840cb5e5dSvi117747 }
11940cb5e5dSvi117747 
12040cb5e5dSvi117747 /*
12140cb5e5dSvi117747  * Hold a sip msg struct.
12240cb5e5dSvi117747  */
12340cb5e5dSvi117747 void
12440cb5e5dSvi117747 sip_hold_msg(sip_msg_t sip_msg)
12540cb5e5dSvi117747 {
12640cb5e5dSvi117747 
12740cb5e5dSvi117747 	if (sip_msg == NULL)
12840cb5e5dSvi117747 		return;
12940cb5e5dSvi117747 
13040cb5e5dSvi117747 	SIP_MSG_REFCNT_INCR((_sip_msg_t *)sip_msg);
13140cb5e5dSvi117747 }
13240cb5e5dSvi117747 
13340cb5e5dSvi117747 /*
13440cb5e5dSvi117747  * Clone a message
13540cb5e5dSvi117747  */
13640cb5e5dSvi117747 sip_msg_t
13740cb5e5dSvi117747 sip_clone_msg(sip_msg_t sip_msg)
13840cb5e5dSvi117747 {
13940cb5e5dSvi117747 	_sip_msg_t	*new_msg;
14040cb5e5dSvi117747 	_sip_msg_t	*_sip_msg;
14140cb5e5dSvi117747 	sip_content_t	*sip_content;
14240cb5e5dSvi117747 	sip_content_t	*msg_content;
14340cb5e5dSvi117747 	sip_content_t	*new_content = NULL;
14440cb5e5dSvi117747 	int		len;
14540cb5e5dSvi117747 
14640cb5e5dSvi117747 	if (sip_msg == NULL)
14740cb5e5dSvi117747 		return (NULL);
14840cb5e5dSvi117747 	new_msg = (_sip_msg_t *)sip_new_msg();
14940cb5e5dSvi117747 	if (new_msg == NULL)
15040cb5e5dSvi117747 		return (NULL);
15140cb5e5dSvi117747 	_sip_msg = (_sip_msg_t *)sip_msg;
15240cb5e5dSvi117747 	/*
15340cb5e5dSvi117747 	 * Get start line
15440cb5e5dSvi117747 	 */
15540cb5e5dSvi117747 	if (sip_copy_start_line(_sip_msg, new_msg) != 0) {
15640cb5e5dSvi117747 		sip_free_msg((sip_msg_t)new_msg);
15740cb5e5dSvi117747 		return (NULL);
15840cb5e5dSvi117747 	}
15940cb5e5dSvi117747 	if (sip_copy_all_headers(_sip_msg, new_msg) != 0) {
16040cb5e5dSvi117747 		sip_free_msg((sip_msg_t)new_msg);
16140cb5e5dSvi117747 		return (NULL);
16240cb5e5dSvi117747 	}
16340cb5e5dSvi117747 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
16440cb5e5dSvi117747 	sip_content = _sip_msg->sip_msg_content;
16540cb5e5dSvi117747 	while (sip_content != NULL) {
16640cb5e5dSvi117747 		msg_content = calloc(1, sizeof (sip_content_t));
16740cb5e5dSvi117747 		if (msg_content == NULL) {
16840cb5e5dSvi117747 			sip_free_msg((sip_msg_t)new_msg);
16940cb5e5dSvi117747 			(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
17040cb5e5dSvi117747 			return (NULL);
17140cb5e5dSvi117747 		}
17240cb5e5dSvi117747 		len = sip_content->sip_content_end -
17340cb5e5dSvi117747 		    sip_content->sip_content_start;
17440cb5e5dSvi117747 		msg_content->sip_content_start = malloc(len + 1);
17540cb5e5dSvi117747 		if (msg_content->sip_content_start == NULL) {
17640cb5e5dSvi117747 			sip_free_msg((sip_msg_t)new_msg);
17740cb5e5dSvi117747 			(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
17840cb5e5dSvi117747 			return (NULL);
17940cb5e5dSvi117747 		}
18040cb5e5dSvi117747 		(void) strncpy(msg_content->sip_content_start,
18140cb5e5dSvi117747 		    sip_content->sip_content_start, len);
18240cb5e5dSvi117747 		msg_content->sip_content_start[len] = '\0';
18340cb5e5dSvi117747 		msg_content->sip_content_current =
18440cb5e5dSvi117747 		    msg_content->sip_content_start;
18540cb5e5dSvi117747 		msg_content->sip_content_end =  msg_content->sip_content_start +
18640cb5e5dSvi117747 		    len;
18740cb5e5dSvi117747 		msg_content->sip_content_allocated = B_TRUE;
18840cb5e5dSvi117747 		new_msg->sip_msg_content_len += len;
18940cb5e5dSvi117747 		new_msg->sip_msg_len += len;
19040cb5e5dSvi117747 		if (new_msg->sip_msg_content == NULL)
19140cb5e5dSvi117747 			new_msg->sip_msg_content = msg_content;
19240cb5e5dSvi117747 		else
19340cb5e5dSvi117747 			new_content->sip_content_next = msg_content;
19440cb5e5dSvi117747 		new_content = msg_content;
19540cb5e5dSvi117747 		sip_content = sip_content->sip_content_next;
19640cb5e5dSvi117747 	}
19740cb5e5dSvi117747 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
19840cb5e5dSvi117747 	/*
19940cb5e5dSvi117747 	 * Since this is a new message, no threads should be referring
20040cb5e5dSvi117747 	 * to this, so it is not necessary to take the lock, however,
20140cb5e5dSvi117747 	 * since sip_msg_to_msgbuf() expects the lock to be held, we'll
20240cb5e5dSvi117747 	 * take it here.
20340cb5e5dSvi117747 	 */
20440cb5e5dSvi117747 	(void) pthread_mutex_lock(&new_msg->sip_msg_mutex);
20540cb5e5dSvi117747 	new_msg->sip_msg_buf = sip_msg_to_msgbuf((sip_msg_t)new_msg, NULL);
20640cb5e5dSvi117747 	if (new_msg->sip_msg_buf == NULL) {
20740cb5e5dSvi117747 		(void) pthread_mutex_unlock(&new_msg->sip_msg_mutex);
20840cb5e5dSvi117747 		sip_free_msg((sip_msg_t)new_msg);
20940cb5e5dSvi117747 		return (NULL);
21040cb5e5dSvi117747 	}
21140cb5e5dSvi117747 	new_msg->sip_msg_cannot_be_modified = B_TRUE;
21240cb5e5dSvi117747 	(void) pthread_mutex_unlock(&new_msg->sip_msg_mutex);
21340cb5e5dSvi117747 
21440cb5e5dSvi117747 	return ((sip_msg_t)new_msg);
21540cb5e5dSvi117747 }
21640cb5e5dSvi117747 
21740cb5e5dSvi117747 /*
21840cb5e5dSvi117747  * Return the SIP message as a string. Caller frees the string
21940cb5e5dSvi117747  */
22040cb5e5dSvi117747 char *
22140cb5e5dSvi117747 sip_msg_to_str(sip_msg_t sip_msg, int *error)
22240cb5e5dSvi117747 {
22340cb5e5dSvi117747 	_sip_msg_t	*msg;
22440cb5e5dSvi117747 	char		*msgstr;
22540cb5e5dSvi117747 
22640cb5e5dSvi117747 	if (sip_msg == NULL) {
22740cb5e5dSvi117747 		if (error != NULL)
22840cb5e5dSvi117747 			*error = EINVAL;
22940cb5e5dSvi117747 		return (NULL);
23040cb5e5dSvi117747 	}
23140cb5e5dSvi117747 	msg = (_sip_msg_t *)sip_msg;
23240cb5e5dSvi117747 	(void) pthread_mutex_lock(&msg->sip_msg_mutex);
23340cb5e5dSvi117747 	msgstr = sip_msg_to_msgbuf(msg, error);
23440cb5e5dSvi117747 	(void) pthread_mutex_unlock(&msg->sip_msg_mutex);
23540cb5e5dSvi117747 	return (msgstr);
23640cb5e5dSvi117747 }
23740cb5e5dSvi117747 
23840cb5e5dSvi117747 /*
23940cb5e5dSvi117747  * Given a message generate a string that includes all the headers and the
24040cb5e5dSvi117747  * content.
24140cb5e5dSvi117747  */
24240cb5e5dSvi117747 char *
24340cb5e5dSvi117747 sip_msg_to_msgbuf(_sip_msg_t *msg, int *error)
24440cb5e5dSvi117747 {
24540cb5e5dSvi117747 	_sip_header_t	*header;
24640cb5e5dSvi117747 	int		len = 0;
24740cb5e5dSvi117747 	char		*p;
24840cb5e5dSvi117747 	char		*e;
24940cb5e5dSvi117747 	sip_content_t	*sip_content;
25040cb5e5dSvi117747 #ifdef	_DEBUG
25140cb5e5dSvi117747 	int		tlen = 0;
25240cb5e5dSvi117747 	int		clen = 0;
25340cb5e5dSvi117747 #endif
25440cb5e5dSvi117747 
25540cb5e5dSvi117747 	if (error != NULL)
25640cb5e5dSvi117747 		*error = 0;
25740cb5e5dSvi117747 
25840cb5e5dSvi117747 	if (msg == NULL) {
25940cb5e5dSvi117747 		if (error != NULL)
26040cb5e5dSvi117747 			*error = EINVAL;
26140cb5e5dSvi117747 		return (NULL);
26240cb5e5dSvi117747 	}
26340cb5e5dSvi117747 #ifdef	__solaris__
26440cb5e5dSvi117747 	assert(mutex_held(&msg->sip_msg_mutex));
26540cb5e5dSvi117747 #endif
26640cb5e5dSvi117747 
26740cb5e5dSvi117747 	p = (char *)malloc(msg->sip_msg_len + 1);
26840cb5e5dSvi117747 	if (p == NULL) {
26940cb5e5dSvi117747 		if (error != 0)
27040cb5e5dSvi117747 			*error = ENOMEM;
27140cb5e5dSvi117747 		return (NULL);
27240cb5e5dSvi117747 	}
27340cb5e5dSvi117747 	e = p;
27440cb5e5dSvi117747 
27540cb5e5dSvi117747 	/*
27640cb5e5dSvi117747 	 * Get the start line
27740cb5e5dSvi117747 	 */
27840cb5e5dSvi117747 	if (msg->sip_msg_start_line != NULL) {
27940cb5e5dSvi117747 		len = msg->sip_msg_start_line->sip_hdr_end -
28040cb5e5dSvi117747 		    msg->sip_msg_start_line->sip_hdr_start;
28140cb5e5dSvi117747 		(void) strncpy(e, msg->sip_msg_start_line->sip_hdr_start, len);
28240cb5e5dSvi117747 		e += len;
28340cb5e5dSvi117747 #ifdef	_DEBUG
28440cb5e5dSvi117747 		tlen += len;
28540cb5e5dSvi117747 #endif
28640cb5e5dSvi117747 	}
28740cb5e5dSvi117747 	header = sip_search_for_header(msg, NULL, NULL);
28840cb5e5dSvi117747 	while (header != NULL) {
28940cb5e5dSvi117747 		if (header->sip_header_state != SIP_HEADER_DELETED) {
29040cb5e5dSvi117747 			if (header->sip_header_state ==
29140cb5e5dSvi117747 			    SIP_HEADER_DELETED_VAL) {
29240cb5e5dSvi117747 				len = sip_copy_values(e, header);
29340cb5e5dSvi117747 			} else {
29440cb5e5dSvi117747 				len = header->sip_hdr_end -
29540cb5e5dSvi117747 				    header->sip_hdr_start;
29640cb5e5dSvi117747 				(void) strncpy(e, header->sip_hdr_start, len);
29740cb5e5dSvi117747 			}
29840cb5e5dSvi117747 #ifdef	_DEBUG
29940cb5e5dSvi117747 			tlen += len;
30040cb5e5dSvi117747 			assert(tlen <= msg->sip_msg_len);
30140cb5e5dSvi117747 #endif
30240cb5e5dSvi117747 		}
30340cb5e5dSvi117747 		header = sip_search_for_header(msg, NULL, header);
30440cb5e5dSvi117747 		e += len;
30540cb5e5dSvi117747 	}
30640cb5e5dSvi117747 	sip_content = msg->sip_msg_content;
30740cb5e5dSvi117747 	while (sip_content != NULL) {
30840cb5e5dSvi117747 		len = sip_content->sip_content_end -
30940cb5e5dSvi117747 		    sip_content->sip_content_start;
31040cb5e5dSvi117747 #ifdef	_DEBUG
31140cb5e5dSvi117747 		clen += len;
31240cb5e5dSvi117747 		assert(clen <= msg->sip_msg_content_len);
31340cb5e5dSvi117747 		tlen += len;
31440cb5e5dSvi117747 		assert(tlen <= msg->sip_msg_len);
31540cb5e5dSvi117747 #endif
31640cb5e5dSvi117747 		(void) strncpy(e, sip_content->sip_content_start, len);
31740cb5e5dSvi117747 		e += len;
31840cb5e5dSvi117747 		sip_content = sip_content->sip_content_next;
31940cb5e5dSvi117747 	}
32040cb5e5dSvi117747 	p[msg->sip_msg_len] = '\0';
32140cb5e5dSvi117747 	return (p);
32240cb5e5dSvi117747 }
32340cb5e5dSvi117747 
32440cb5e5dSvi117747 /*
32540cb5e5dSvi117747  * This is called just before sending the message to the transport. It
32640cb5e5dSvi117747  * creates the sip_msg_buf from the SIP headers.
32740cb5e5dSvi117747  */
32840cb5e5dSvi117747 int
32940cb5e5dSvi117747 sip_adjust_msgbuf(_sip_msg_t *msg)
33040cb5e5dSvi117747 {
33140cb5e5dSvi117747 	_sip_header_t	*header;
33240cb5e5dSvi117747 	int		ret;
33340cb5e5dSvi117747 #ifdef	_DEBUG
33440cb5e5dSvi117747 	int		tlen = 0;
33540cb5e5dSvi117747 	int		clen = 0;
33640cb5e5dSvi117747 #endif
33740cb5e5dSvi117747 
33840cb5e5dSvi117747 	if (msg == NULL)
33940cb5e5dSvi117747 		return (EINVAL);
34040cb5e5dSvi117747 
34140cb5e5dSvi117747 	(void) pthread_mutex_lock(&msg->sip_msg_mutex);
34240cb5e5dSvi117747 	if ((msg->sip_msg_buf != NULL) && (!msg->sip_msg_modified)) {
34340cb5e5dSvi117747 		/*
34440cb5e5dSvi117747 		 * We could just be forwarding the message we
34540cb5e5dSvi117747 		 * received.
34640cb5e5dSvi117747 		 */
34740cb5e5dSvi117747 		(void) pthread_mutex_unlock(&msg->sip_msg_mutex);
34840cb5e5dSvi117747 		return (0);
34940cb5e5dSvi117747 	}
35040cb5e5dSvi117747 
35140cb5e5dSvi117747 	/*
35240cb5e5dSvi117747 	 * We are sending a new message or a message that we received
35340cb5e5dSvi117747 	 * but have modified it. We keep the old
35440cb5e5dSvi117747 	 * msgbuf till the message is freed as some
35540cb5e5dSvi117747 	 * headers still point to it.
35640cb5e5dSvi117747 	 */
35740cb5e5dSvi117747 
35840cb5e5dSvi117747 	assert(msg->sip_msg_old_buf == NULL);
35940cb5e5dSvi117747 	msg->sip_msg_old_buf = msg->sip_msg_buf;
36040cb5e5dSvi117747 	/*
36140cb5e5dSvi117747 	 * We add the content-length header here, if it has not
36240cb5e5dSvi117747 	 * already been added.
36340cb5e5dSvi117747 	 */
36440cb5e5dSvi117747 	header = sip_search_for_header(msg, SIP_CONTENT_LENGTH, NULL);
36540cb5e5dSvi117747 	if (header != NULL) {
36640cb5e5dSvi117747 		/*
36740cb5e5dSvi117747 		 * Mark the previous header as deleted.
36840cb5e5dSvi117747 		 */
36940cb5e5dSvi117747 		header->sip_header_state = SIP_HEADER_DELETED;
37040cb5e5dSvi117747 		header->sip_hdr_sipmsg->sip_msg_len -= header->sip_hdr_end -
37140cb5e5dSvi117747 		    header->sip_hdr_start;
37240cb5e5dSvi117747 	}
37340cb5e5dSvi117747 	(void) pthread_mutex_unlock(&msg->sip_msg_mutex);
37440cb5e5dSvi117747 	ret = sip_add_content_length(msg, msg->sip_msg_content_len);
37540cb5e5dSvi117747 	if (ret != 0) {
37640cb5e5dSvi117747 		(void) pthread_mutex_unlock(&msg->sip_msg_mutex);
37740cb5e5dSvi117747 		return (ret);
37840cb5e5dSvi117747 	}
37940cb5e5dSvi117747 	(void) pthread_mutex_lock(&msg->sip_msg_mutex);
38040cb5e5dSvi117747 	msg->sip_msg_modified = B_FALSE;
38140cb5e5dSvi117747 
38240cb5e5dSvi117747 	msg->sip_msg_buf = sip_msg_to_msgbuf((sip_msg_t)msg, &ret);
38340cb5e5dSvi117747 	if (msg->sip_msg_buf == NULL) {
38440cb5e5dSvi117747 		(void) pthread_mutex_unlock(&msg->sip_msg_mutex);
38540cb5e5dSvi117747 		return (ret);
38640cb5e5dSvi117747 	}
38740cb5e5dSvi117747 	/*
38840cb5e5dSvi117747 	 * Once the message has been sent it can not be modified
38940cb5e5dSvi117747 	 * any furthur as we keep a pointer to it for retransmission
39040cb5e5dSvi117747 	 */
39140cb5e5dSvi117747 	msg->sip_msg_cannot_be_modified = B_TRUE;
39240cb5e5dSvi117747 
39340cb5e5dSvi117747 	(void) pthread_mutex_unlock(&msg->sip_msg_mutex);
39440cb5e5dSvi117747 	return (0);
39540cb5e5dSvi117747 }
39640cb5e5dSvi117747 
39740cb5e5dSvi117747 /*
39840cb5e5dSvi117747  * Copy header values into ptr
39940cb5e5dSvi117747  */
40040cb5e5dSvi117747 int
40140cb5e5dSvi117747 sip_copy_values(char *ptr, _sip_header_t *header)
40240cb5e5dSvi117747 {
40340cb5e5dSvi117747 	sip_header_value_t	value;
40440cb5e5dSvi117747 	int			tlen = 0;
40540cb5e5dSvi117747 	int			len = 0;
40640cb5e5dSvi117747 	boolean_t		first = B_TRUE;
40740cb5e5dSvi117747 	char			*p = ptr;
40840cb5e5dSvi117747 	char			*s;
40940cb5e5dSvi117747 	boolean_t		crlf_present = B_FALSE;
41040cb5e5dSvi117747 
41140cb5e5dSvi117747 	if (sip_parse_goto_values(header) != 0)
41240cb5e5dSvi117747 		return (0);
41340cb5e5dSvi117747 
41440cb5e5dSvi117747 	len = header->sip_hdr_current - header->sip_hdr_start;
41540cb5e5dSvi117747 	(void) strncpy(p, header->sip_hdr_start, len);
41640cb5e5dSvi117747 	tlen += len;
41740cb5e5dSvi117747 	p += len;
41840cb5e5dSvi117747 	value = header->sip_hdr_parsed->value;
41940cb5e5dSvi117747 	while (value != NULL) {
42040cb5e5dSvi117747 		if (value->value_state != SIP_VALUE_DELETED) {
42140cb5e5dSvi117747 			crlf_present = B_FALSE;
42240cb5e5dSvi117747 			len = value->value_end - value->value_start;
42340cb5e5dSvi117747 			if (first) {
42440cb5e5dSvi117747 				(void) strncpy(p, value->value_start, len);
42540cb5e5dSvi117747 				first = B_FALSE;
42640cb5e5dSvi117747 			} else {
42740cb5e5dSvi117747 				s = value->value_start;
42840cb5e5dSvi117747 				while (*s != SIP_COMMA)
42940cb5e5dSvi117747 					s--;
43040cb5e5dSvi117747 				len += value->value_start - s;
43140cb5e5dSvi117747 				(void) strncpy(p, s, len);
43240cb5e5dSvi117747 			}
43340cb5e5dSvi117747 			tlen += len;
43440cb5e5dSvi117747 			p += len;
43540cb5e5dSvi117747 			s = value->value_end;
43640cb5e5dSvi117747 			while (s != value->value_start) {
43740cb5e5dSvi117747 				if (*s == '\r' && strncmp(s, SIP_CRLF,
43840cb5e5dSvi117747 				    strlen(SIP_CRLF)) == 0) {
43940cb5e5dSvi117747 					crlf_present = B_TRUE;
44040cb5e5dSvi117747 					break;
44140cb5e5dSvi117747 				}
44240cb5e5dSvi117747 				s--;
44340cb5e5dSvi117747 			}
44440cb5e5dSvi117747 		} else {
44540cb5e5dSvi117747 			if (value->next == NULL && !first && !crlf_present) {
44640cb5e5dSvi117747 				s = value->value_end;
44740cb5e5dSvi117747 				while (*s != '\r')
44840cb5e5dSvi117747 					s--;
44940cb5e5dSvi117747 				len = value->value_end - s;
45040cb5e5dSvi117747 				(void) strncpy(p, s, len);
45140cb5e5dSvi117747 				tlen += len;
45240cb5e5dSvi117747 				p += len;
45340cb5e5dSvi117747 			}
45440cb5e5dSvi117747 		}
45540cb5e5dSvi117747 		value = value->next;
45640cb5e5dSvi117747 	}
45740cb5e5dSvi117747 	return (tlen);
45840cb5e5dSvi117747 }
45940cb5e5dSvi117747 
46040cb5e5dSvi117747 
46140cb5e5dSvi117747 /*
46240cb5e5dSvi117747  * Add content (message body) to sip_msg
46340cb5e5dSvi117747  */
46440cb5e5dSvi117747 int
46540cb5e5dSvi117747 sip_add_content(sip_msg_t sip_msg, char *content)
46640cb5e5dSvi117747 {
46740cb5e5dSvi117747 	size_t		len;
46840cb5e5dSvi117747 	sip_content_t	**loc;
46940cb5e5dSvi117747 	sip_content_t	*msg_content;
47040cb5e5dSvi117747 	_sip_msg_t	*_sip_msg;
47140cb5e5dSvi117747 
47240cb5e5dSvi117747 	if (sip_msg == NULL || content == NULL || strlen(content) == 0)
47340cb5e5dSvi117747 		return (EINVAL);
47440cb5e5dSvi117747 	len = strlen(content);
47540cb5e5dSvi117747 	_sip_msg = (_sip_msg_t *)sip_msg;
47640cb5e5dSvi117747 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
47740cb5e5dSvi117747 
47840cb5e5dSvi117747 	if (_sip_msg->sip_msg_cannot_be_modified) {
47940cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
48040cb5e5dSvi117747 		return (ENOTSUP);
48140cb5e5dSvi117747 	}
48240cb5e5dSvi117747 
48340cb5e5dSvi117747 	msg_content = calloc(1, sizeof (sip_content_t));
48440cb5e5dSvi117747 	if (msg_content == NULL) {
48540cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
48640cb5e5dSvi117747 		return (ENOMEM);
48740cb5e5dSvi117747 	}
48840cb5e5dSvi117747 	msg_content->sip_content_start = malloc(strlen(content) + 1);
48940cb5e5dSvi117747 	if (msg_content->sip_content_start == NULL) {
49040cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
49140cb5e5dSvi117747 		free(msg_content);
49240cb5e5dSvi117747 		return (ENOMEM);
49340cb5e5dSvi117747 	}
49440cb5e5dSvi117747 	(void) strncpy(msg_content->sip_content_start, content,
49540cb5e5dSvi117747 	    strlen(content));
49640cb5e5dSvi117747 	msg_content->sip_content_start[strlen(content)] = '\0';
49740cb5e5dSvi117747 	msg_content->sip_content_current = msg_content->sip_content_start;
49840cb5e5dSvi117747 	msg_content->sip_content_end = msg_content->sip_content_start +
49940cb5e5dSvi117747 	    strlen(msg_content->sip_content_start);
50040cb5e5dSvi117747 	msg_content->sip_content_allocated = B_TRUE;
50140cb5e5dSvi117747 
50240cb5e5dSvi117747 	loc = &_sip_msg->sip_msg_content;
50340cb5e5dSvi117747 	while (*loc != NULL)
50440cb5e5dSvi117747 		loc = &((*loc)->sip_content_next);
50540cb5e5dSvi117747 	*loc = msg_content;
50640cb5e5dSvi117747 
50740cb5e5dSvi117747 	_sip_msg->sip_msg_content_len += len;
50840cb5e5dSvi117747 	_sip_msg->sip_msg_len += len;
50940cb5e5dSvi117747 	if (_sip_msg->sip_msg_buf != NULL)
51040cb5e5dSvi117747 		_sip_msg->sip_msg_modified = B_TRUE;
51140cb5e5dSvi117747 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
51240cb5e5dSvi117747 	return (0);
51340cb5e5dSvi117747 }
51440cb5e5dSvi117747 
51540cb5e5dSvi117747 /*
51640cb5e5dSvi117747  * Free the message content
51740cb5e5dSvi117747  */
51840cb5e5dSvi117747 void
51940cb5e5dSvi117747 sip_free_content(_sip_msg_t *sip_msg)
52040cb5e5dSvi117747 {
52140cb5e5dSvi117747 	sip_content_t *content;
52240cb5e5dSvi117747 
52340cb5e5dSvi117747 	if (sip_msg == NULL)
52440cb5e5dSvi117747 		return;
52540cb5e5dSvi117747 	content = sip_msg->sip_msg_content;
52640cb5e5dSvi117747 	while (content != NULL) {
52740cb5e5dSvi117747 		sip_content_t *content_tmp;
52840cb5e5dSvi117747 
52940cb5e5dSvi117747 		content_tmp = content;
53040cb5e5dSvi117747 		content = content->sip_content_next;
53140cb5e5dSvi117747 		if (content_tmp->sip_content_allocated)
53240cb5e5dSvi117747 			free(content_tmp->sip_content_start);
53340cb5e5dSvi117747 		free(content_tmp);
53440cb5e5dSvi117747 	}
53540cb5e5dSvi117747 	sip_msg->sip_msg_content = NULL;
53640cb5e5dSvi117747 }
53740cb5e5dSvi117747 
53840cb5e5dSvi117747 
53940cb5e5dSvi117747 /*
54040cb5e5dSvi117747  * Add a response line to sip_response
54140cb5e5dSvi117747  */
54240cb5e5dSvi117747 int
54340cb5e5dSvi117747 sip_add_response_line(sip_msg_t sip_response, int response, char *response_code)
54440cb5e5dSvi117747 {
54540cb5e5dSvi117747 	_sip_header_t	*new_header;
54640cb5e5dSvi117747 	int		header_size;
54740cb5e5dSvi117747 	_sip_msg_t	*_sip_response;
54840cb5e5dSvi117747 	int		ret;
54940cb5e5dSvi117747 
55040cb5e5dSvi117747 	if (sip_response == NULL || response < 0 || response_code == NULL)
55140cb5e5dSvi117747 		return (EINVAL);
55240cb5e5dSvi117747 	_sip_response = (_sip_msg_t *)sip_response;
55340cb5e5dSvi117747 	(void) pthread_mutex_lock(&_sip_response->sip_msg_mutex);
55440cb5e5dSvi117747 	if (_sip_response->sip_msg_cannot_be_modified) {
55540cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_sip_response->sip_msg_mutex);
55640cb5e5dSvi117747 		return (ENOTSUP);
55740cb5e5dSvi117747 	}
55840cb5e5dSvi117747 	header_size = strlen(SIP_VERSION) + SIP_SPACE_LEN +
55940cb5e5dSvi117747 	    SIP_SIZE_OF_STATUS_CODE + SIP_SPACE_LEN + strlen(response_code) +
56040cb5e5dSvi117747 	    strlen(SIP_CRLF);
56140cb5e5dSvi117747 
56240cb5e5dSvi117747 	new_header = sip_new_header(header_size);
56340cb5e5dSvi117747 	if (new_header == NULL) {
56440cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_sip_response->sip_msg_mutex);
56540cb5e5dSvi117747 		return (ENOMEM);
56640cb5e5dSvi117747 	}
56740cb5e5dSvi117747 	new_header->sip_hdr_sipmsg = _sip_response;
56840cb5e5dSvi117747 
56940cb5e5dSvi117747 	(void) snprintf(new_header->sip_hdr_start, header_size + 1,
57040cb5e5dSvi117747 	    SIP_RESPONSE, SIP_VERSION, response, response_code, SIP_CRLF);
57140cb5e5dSvi117747 
57240cb5e5dSvi117747 	new_header->sip_hdr_next = _sip_response->sip_msg_start_line;
57340cb5e5dSvi117747 	_sip_response->sip_msg_start_line = new_header;
57440cb5e5dSvi117747 	_sip_response->sip_msg_len += header_size;
57540cb5e5dSvi117747 	ret = sip_parse_first_line(_sip_response->sip_msg_start_line,
57640cb5e5dSvi117747 	    &_sip_response->sip_msg_req_res);
57740cb5e5dSvi117747 	if (_sip_response->sip_msg_buf != NULL)
57840cb5e5dSvi117747 		_sip_response->sip_msg_modified = B_TRUE;
57940cb5e5dSvi117747 	(void) pthread_mutex_unlock(&_sip_response->sip_msg_mutex);
58040cb5e5dSvi117747 	return (ret);
58140cb5e5dSvi117747 }
58240cb5e5dSvi117747 
58340cb5e5dSvi117747 /*
58440cb5e5dSvi117747  * create a response based on the sip_request.
58540cb5e5dSvi117747  * Copies Call-ID, CSeq, From, To and Via headers from the request.
58640cb5e5dSvi117747  */
58740cb5e5dSvi117747 sip_msg_t
58840cb5e5dSvi117747 sip_create_response(sip_msg_t sip_request, int response, char *response_code,
58940cb5e5dSvi117747     char *totag, char *mycontact)
59040cb5e5dSvi117747 {
59140cb5e5dSvi117747 	_sip_msg_t	*new_msg;
59240cb5e5dSvi117747 	_sip_msg_t	*_sip_request;
59340cb5e5dSvi117747 	boolean_t	ttag_present;
59440cb5e5dSvi117747 
59540cb5e5dSvi117747 	if (sip_request == NULL || response_code == NULL)
59640cb5e5dSvi117747 		return (NULL);
59740cb5e5dSvi117747 
59840cb5e5dSvi117747 	ttag_present =  sip_get_to_tag(sip_request, NULL) != NULL;
59940cb5e5dSvi117747 
60040cb5e5dSvi117747 	new_msg = (_sip_msg_t *)sip_new_msg();
60140cb5e5dSvi117747 	if (new_msg == NULL)
60240cb5e5dSvi117747 		return (NULL);
60340cb5e5dSvi117747 	_sip_request = (_sip_msg_t *)sip_request;
60440cb5e5dSvi117747 
60540cb5e5dSvi117747 	(void) pthread_mutex_lock(&_sip_request->sip_msg_mutex);
60640cb5e5dSvi117747 
60740cb5e5dSvi117747 	/*
60840cb5e5dSvi117747 	 * Add response line.
60940cb5e5dSvi117747 	 */
61040cb5e5dSvi117747 	if (sip_add_response_line(new_msg, response, response_code) != 0)
61140cb5e5dSvi117747 		goto error;
61240cb5e5dSvi117747 
61340cb5e5dSvi117747 	/*
61440cb5e5dSvi117747 	 * Copy Via headers
61540cb5e5dSvi117747 	 */
61640cb5e5dSvi117747 	if (_sip_find_and_copy_all_header(_sip_request, new_msg, SIP_VIA) != 0)
61740cb5e5dSvi117747 		goto error;
61840cb5e5dSvi117747 
61940cb5e5dSvi117747 	/*
62040cb5e5dSvi117747 	 * Copy From header.
62140cb5e5dSvi117747 	 */
62240cb5e5dSvi117747 	if (_sip_find_and_copy_header(_sip_request, new_msg, SIP_FROM,
62340cb5e5dSvi117747 	    NULL, B_FALSE)) {
62440cb5e5dSvi117747 		goto error;
62540cb5e5dSvi117747 	}
62640cb5e5dSvi117747 	/*
62740cb5e5dSvi117747 	 * Copy To header. If To tag is present, copy it, if not then
62840cb5e5dSvi117747 	 * add one if the repsonse is not provisional.
62940cb5e5dSvi117747 	 */
63040cb5e5dSvi117747 	if (ttag_present || (totag == NULL && response == SIP_TRYING)) {
63140cb5e5dSvi117747 		if (_sip_find_and_copy_header(_sip_request, new_msg, SIP_TO,
63240cb5e5dSvi117747 		    NULL, B_FALSE)) {
63340cb5e5dSvi117747 			goto error;
63440cb5e5dSvi117747 		}
63540cb5e5dSvi117747 	} else {
63640cb5e5dSvi117747 		char		*xtra_param;
63740cb5e5dSvi117747 		boolean_t	tag_alloc = B_FALSE;
63840cb5e5dSvi117747 		int		taglen;
63940cb5e5dSvi117747 
64040cb5e5dSvi117747 		if (totag == NULL) {
64140cb5e5dSvi117747 			totag = sip_guid();
64240cb5e5dSvi117747 			if (totag == NULL)
64340cb5e5dSvi117747 				goto error;
64440cb5e5dSvi117747 			tag_alloc = B_TRUE;
64540cb5e5dSvi117747 		}
64640cb5e5dSvi117747 		taglen = strlen(SIP_TAG) + strlen(totag) + 1;
64740cb5e5dSvi117747 		xtra_param = (char *)malloc(taglen);
64840cb5e5dSvi117747 		if (xtra_param == NULL) {
64940cb5e5dSvi117747 			if (tag_alloc)
65040cb5e5dSvi117747 				free(totag);
65140cb5e5dSvi117747 			goto error;
65240cb5e5dSvi117747 		}
65340cb5e5dSvi117747 		(void) snprintf(xtra_param, taglen, "%s%s", SIP_TAG, totag);
65440cb5e5dSvi117747 		if (tag_alloc)
65540cb5e5dSvi117747 			free(totag);
65640cb5e5dSvi117747 		if (_sip_find_and_copy_header(_sip_request, new_msg,
65740cb5e5dSvi117747 		    SIP_TO, xtra_param, B_FALSE)) {
65840cb5e5dSvi117747 			free(xtra_param);
65940cb5e5dSvi117747 			goto error;
66040cb5e5dSvi117747 		}
66140cb5e5dSvi117747 		free(xtra_param);
66240cb5e5dSvi117747 	}
66340cb5e5dSvi117747 
66440cb5e5dSvi117747 	/*
66540cb5e5dSvi117747 	 * Copy Call-ID header.
66640cb5e5dSvi117747 	 */
66740cb5e5dSvi117747 	if (_sip_find_and_copy_header(_sip_request, new_msg, SIP_CALL_ID, NULL,
66840cb5e5dSvi117747 	    B_FALSE)) {
66940cb5e5dSvi117747 		goto error;
67040cb5e5dSvi117747 	}
67140cb5e5dSvi117747 	/*
67240cb5e5dSvi117747 	 * Copy CSEQ header
67340cb5e5dSvi117747 	 */
67440cb5e5dSvi117747 	if (_sip_find_and_copy_header(_sip_request, new_msg, SIP_CSEQ, NULL,
67540cb5e5dSvi117747 	    B_FALSE)) {
67640cb5e5dSvi117747 		goto error;
67740cb5e5dSvi117747 	}
67840cb5e5dSvi117747 	/*
67940cb5e5dSvi117747 	 * Copy RECORD-ROUTE header, if present.
68040cb5e5dSvi117747 	 */
68140cb5e5dSvi117747 	if (sip_search_for_header(_sip_request, SIP_RECORD_ROUTE, NULL) !=
68240cb5e5dSvi117747 	    NULL) {
68340cb5e5dSvi117747 		if (_sip_find_and_copy_all_header(_sip_request, new_msg,
68440cb5e5dSvi117747 		    SIP_RECORD_ROUTE) != 0) {
68540cb5e5dSvi117747 			goto error;
68640cb5e5dSvi117747 		}
68740cb5e5dSvi117747 	}
68840cb5e5dSvi117747 	if (mycontact != NULL) {
68940cb5e5dSvi117747 		if (sip_add_contact(new_msg, NULL, mycontact, B_FALSE,
69040cb5e5dSvi117747 		    NULL) != 0) {
69140cb5e5dSvi117747 			goto error;
69240cb5e5dSvi117747 		}
69340cb5e5dSvi117747 	}
69440cb5e5dSvi117747 	(void) pthread_mutex_unlock(&_sip_request->sip_msg_mutex);
69540cb5e5dSvi117747 	return ((sip_msg_t)new_msg);
69640cb5e5dSvi117747 error:
69740cb5e5dSvi117747 	sip_free_msg((sip_msg_t)new_msg);
69840cb5e5dSvi117747 	(void) pthread_mutex_unlock(&_sip_request->sip_msg_mutex);
69940cb5e5dSvi117747 	return (NULL);
70040cb5e5dSvi117747 }
70140cb5e5dSvi117747 
70240cb5e5dSvi117747 /*
70340cb5e5dSvi117747  * NON OK ACK : MUST contain values for the Call-ID, From, and Request-URI
70440cb5e5dSvi117747  * that are equal to the values of those header fields in the orig request
70540cb5e5dSvi117747  * passed to the transport. The To header field in the ACK MUST equal the To
70640cb5e5dSvi117747  * header field in the response being acknowledged. The ACK MUST contain the
70740cb5e5dSvi117747  * top Via header field of the original request.  The CSeq header field in
70840cb5e5dSvi117747  * the ACK MUST contain the same value for the sequence number as was
70940cb5e5dSvi117747  * present in the original request, but the method parameter MUST be equal
71040cb5e5dSvi117747  * to "ACK".
71140cb5e5dSvi117747  */
71240cb5e5dSvi117747 int
71340cb5e5dSvi117747 sip_create_nonOKack(sip_msg_t request, sip_msg_t response, sip_msg_t ack_msg)
71440cb5e5dSvi117747 {
71540cb5e5dSvi117747 	int		seqno;
71640cb5e5dSvi117747 	char		*uri;
71740cb5e5dSvi117747 	_sip_msg_t	*_request;
71840cb5e5dSvi117747 	_sip_msg_t	*_response;
71940cb5e5dSvi117747 	_sip_msg_t	*_ack_msg;
72040cb5e5dSvi117747 	int		ret;
72140cb5e5dSvi117747 
72240cb5e5dSvi117747 	if (request == NULL || response == NULL || ack_msg == NULL ||
72340cb5e5dSvi117747 	    request == ack_msg) {
72440cb5e5dSvi117747 		return (EINVAL);
72540cb5e5dSvi117747 	}
72640cb5e5dSvi117747 	_request = (_sip_msg_t *)request;
72740cb5e5dSvi117747 	_response = (_sip_msg_t *)response;
72840cb5e5dSvi117747 	_ack_msg = (_sip_msg_t *)ack_msg;
72940cb5e5dSvi117747 
73040cb5e5dSvi117747 	(void) pthread_mutex_lock(&_request->sip_msg_mutex);
73140cb5e5dSvi117747 	if (_request->sip_msg_req_res == NULL) {
73240cb5e5dSvi117747 		if ((ret = sip_parse_first_line(_request->sip_msg_start_line,
73340cb5e5dSvi117747 		    &_request->sip_msg_req_res)) != 0) {
73440cb5e5dSvi117747 			(void) pthread_mutex_unlock(&_request->sip_msg_mutex);
73540cb5e5dSvi117747 			return (ret);
73640cb5e5dSvi117747 		}
73740cb5e5dSvi117747 	}
73840cb5e5dSvi117747 	if (_request->sip_msg_req_res->U.sip_request.sip_request_uri.
73940cb5e5dSvi117747 	    sip_str_ptr == NULL) {
74040cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_request->sip_msg_mutex);
74140cb5e5dSvi117747 		return (EINVAL);
74240cb5e5dSvi117747 	}
74340cb5e5dSvi117747 	uri = (char *)malloc(_request->sip_msg_req_res->U.sip_request.
74440cb5e5dSvi117747 	    sip_request_uri.sip_str_len + 1);
74540cb5e5dSvi117747 	if (uri == NULL) {
74640cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_request->sip_msg_mutex);
74740cb5e5dSvi117747 		return (EINVAL);
74840cb5e5dSvi117747 	}
74940cb5e5dSvi117747 	(void) strncpy(uri,
75040cb5e5dSvi117747 	    _request->sip_msg_req_res->U.sip_request.sip_request_uri.
75140cb5e5dSvi117747 	    sip_str_ptr, _request->sip_msg_req_res->U.sip_request.
75240cb5e5dSvi117747 	    sip_request_uri.sip_str_len);
75340cb5e5dSvi117747 	uri[_request->sip_msg_req_res->U.sip_request.
75440cb5e5dSvi117747 	    sip_request_uri.sip_str_len] = '\0';
75540cb5e5dSvi117747 	if ((ret = sip_add_request_line(_ack_msg, ACK, uri)) != 0) {
75640cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_request->sip_msg_mutex);
75740cb5e5dSvi117747 		return (ret);
75840cb5e5dSvi117747 	}
75940cb5e5dSvi117747 	free(uri);
76040cb5e5dSvi117747 	if ((ret = _sip_find_and_copy_header(_request, _ack_msg, SIP_VIA,
76140cb5e5dSvi117747 	    NULL, B_TRUE)) != 0) {
76240cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_request->sip_msg_mutex);
76340cb5e5dSvi117747 		return (ret);
76440cb5e5dSvi117747 	}
76540cb5e5dSvi117747 	(void) _sip_find_and_copy_header(_request, _ack_msg,
76640cb5e5dSvi117747 	    SIP_MAX_FORWARDS, NULL, B_TRUE);
76740cb5e5dSvi117747 
76840cb5e5dSvi117747 	(void) pthread_mutex_lock(&_response->sip_msg_mutex);
76940cb5e5dSvi117747 	if ((ret = _sip_find_and_copy_header(_response, _ack_msg, SIP_TO,
77040cb5e5dSvi117747 	    NULL, B_TRUE)) != 0) {
77140cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_response->sip_msg_mutex);
77240cb5e5dSvi117747 		return (ret);
77340cb5e5dSvi117747 	}
77440cb5e5dSvi117747 	(void) pthread_mutex_unlock(&_response->sip_msg_mutex);
77540cb5e5dSvi117747 	if ((ret = _sip_find_and_copy_header(_request, _ack_msg, SIP_FROM,
77640cb5e5dSvi117747 	    NULL, B_TRUE)) != 0) {
77740cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_request->sip_msg_mutex);
77840cb5e5dSvi117747 		return (ret);
77940cb5e5dSvi117747 	}
78040cb5e5dSvi117747 	if ((ret = _sip_find_and_copy_header(_request, _ack_msg, SIP_CALL_ID,
78140cb5e5dSvi117747 	    NULL, B_TRUE)) != 0) {
78240cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_request->sip_msg_mutex);
78340cb5e5dSvi117747 		return (ret);
78440cb5e5dSvi117747 	}
78540cb5e5dSvi117747 	(void) pthread_mutex_unlock(&_request->sip_msg_mutex);
78640cb5e5dSvi117747 	seqno = sip_get_callseq_num(_request, &ret);
78740cb5e5dSvi117747 	if (ret != 0)
78840cb5e5dSvi117747 		return (ret);
78940cb5e5dSvi117747 	if ((ret = sip_add_cseq(_ack_msg, ACK, seqno)) != 0)
79040cb5e5dSvi117747 		return (ret);
79140cb5e5dSvi117747 	if ((ret = sip_adjust_msgbuf(_ack_msg)) != 0)
79240cb5e5dSvi117747 		return (ret);
79340cb5e5dSvi117747 	return (0);
79440cb5e5dSvi117747 }
79540cb5e5dSvi117747 
79640cb5e5dSvi117747 /*
79740cb5e5dSvi117747  * This is a 2XX ACK, for others ACK is constructed differently,
79840cb5e5dSvi117747  * esp. the branch id is retained.
79940cb5e5dSvi117747  */
80040cb5e5dSvi117747 int
80140cb5e5dSvi117747 sip_create_OKack(sip_msg_t response, sip_msg_t ack_msg, char *transport,
80240cb5e5dSvi117747     char *sent_by, int sent_by_port, char *via_params)
80340cb5e5dSvi117747 {
80440cb5e5dSvi117747 	int			seqno;
80540cb5e5dSvi117747 	char			*uri;
80640cb5e5dSvi117747 	sip_parsed_header_t	*parsed_header;
80740cb5e5dSvi117747 	sip_hdr_value_t		*contact_value;
80840cb5e5dSvi117747 	_sip_header_t		*header;
80940cb5e5dSvi117747 	_sip_msg_t		*_response;
81040cb5e5dSvi117747 	_sip_msg_t		*_ack_msg;
81140cb5e5dSvi117747 	int			ret;
81240cb5e5dSvi117747 
81340cb5e5dSvi117747 	if (response == NULL || response == NULL || transport == NULL)
81440cb5e5dSvi117747 		return (EINVAL);
81540cb5e5dSvi117747 	_response = (_sip_msg_t *)response;
81640cb5e5dSvi117747 	_ack_msg = (_sip_msg_t *)ack_msg;
81740cb5e5dSvi117747 
81840cb5e5dSvi117747 	/*
81940cb5e5dSvi117747 	 * Get URI from the response, Contact field
82040cb5e5dSvi117747 	 */
82140cb5e5dSvi117747 	(void) pthread_mutex_lock(&_response->sip_msg_mutex);
82240cb5e5dSvi117747 	if ((header = sip_search_for_header(_response, SIP_CONTACT,
82340cb5e5dSvi117747 	    NULL)) == NULL) {
82440cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_response->sip_msg_mutex);
82540cb5e5dSvi117747 		return (EINVAL);
82640cb5e5dSvi117747 	}
82740cb5e5dSvi117747 	if ((ret = sip_parse_cftr_header(header, (void *)&parsed_header)) !=
82840cb5e5dSvi117747 	    0) {
82940cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_response->sip_msg_mutex);
83040cb5e5dSvi117747 		return (ret);
83140cb5e5dSvi117747 	}
83240cb5e5dSvi117747 	contact_value = (sip_hdr_value_t *)parsed_header->value;
83340cb5e5dSvi117747 	if (contact_value->cftr_uri.sip_str_ptr == NULL) {
83440cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_response->sip_msg_mutex);
83540cb5e5dSvi117747 		return (EINVAL);
83640cb5e5dSvi117747 	}
83740cb5e5dSvi117747 	uri = (char *)malloc(contact_value->cftr_uri.sip_str_len + 1);
83840cb5e5dSvi117747 	if (uri == NULL) {
83940cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_response->sip_msg_mutex);
84040cb5e5dSvi117747 		return (ENOMEM);
84140cb5e5dSvi117747 	}
84240cb5e5dSvi117747 	(void) strncpy(uri, contact_value->cftr_uri.sip_str_ptr,
84340cb5e5dSvi117747 	    contact_value->cftr_uri.sip_str_len);
84440cb5e5dSvi117747 	uri[contact_value->cftr_uri.sip_str_len] = '\0';
84540cb5e5dSvi117747 	if ((ret = sip_add_request_line(_ack_msg, ACK, uri)) != 0) {
84640cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_response->sip_msg_mutex);
84740cb5e5dSvi117747 		return (ret);
84840cb5e5dSvi117747 	}
84940cb5e5dSvi117747 	free(uri);
85040cb5e5dSvi117747 	if ((ret = sip_add_via(_ack_msg, transport, sent_by, sent_by_port,
85140cb5e5dSvi117747 	    via_params)) != 0) {
85240cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_response->sip_msg_mutex);
85340cb5e5dSvi117747 		return (ret);
85440cb5e5dSvi117747 	}
85540cb5e5dSvi117747 
85640cb5e5dSvi117747 	if ((ret = _sip_find_and_copy_header(_response, _ack_msg, SIP_TO,
85740cb5e5dSvi117747 	    NULL, B_TRUE)) != 0) {
85840cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_response->sip_msg_mutex);
85940cb5e5dSvi117747 		return (ret);
86040cb5e5dSvi117747 	}
86140cb5e5dSvi117747 	if ((ret = _sip_find_and_copy_header(_response, _ack_msg, SIP_FROM,
86240cb5e5dSvi117747 	    NULL, B_TRUE)) != 0) {
86340cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_response->sip_msg_mutex);
86440cb5e5dSvi117747 		return (ret);
86540cb5e5dSvi117747 	}
86640cb5e5dSvi117747 	if ((ret = _sip_find_and_copy_header(_response, _ack_msg, SIP_CALL_ID,
86740cb5e5dSvi117747 	    NULL, B_TRUE)) != 0) {
86840cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_response->sip_msg_mutex);
86940cb5e5dSvi117747 		return (ret);
87040cb5e5dSvi117747 	}
87140cb5e5dSvi117747 	/*
87240cb5e5dSvi117747 	 * Copy Max-Forward if present
87340cb5e5dSvi117747 	 */
87440cb5e5dSvi117747 	if (sip_search_for_header(_response, SIP_MAX_FORWARDS, NULL) != NULL) {
87540cb5e5dSvi117747 		if ((ret = _sip_find_and_copy_header(_response, _ack_msg,
87640cb5e5dSvi117747 		    SIP_MAX_FORWARDS, NULL, B_TRUE)) != 0) {
87740cb5e5dSvi117747 			(void) pthread_mutex_unlock(&_response->sip_msg_mutex);
87840cb5e5dSvi117747 			return (ret);
87940cb5e5dSvi117747 		}
88040cb5e5dSvi117747 	}
88140cb5e5dSvi117747 	(void) pthread_mutex_unlock(&_response->sip_msg_mutex);
88240cb5e5dSvi117747 	seqno = sip_get_callseq_num(_response, &ret);
88340cb5e5dSvi117747 	if (ret != 0)
88440cb5e5dSvi117747 		return (ret);
88540cb5e5dSvi117747 	if ((ret = sip_add_cseq(_ack_msg, ACK, seqno)) != 0)
88640cb5e5dSvi117747 		return (ret);
88740cb5e5dSvi117747 
88840cb5e5dSvi117747 	return (0);
88940cb5e5dSvi117747 }
89040cb5e5dSvi117747 
89140cb5e5dSvi117747 /*
89240cb5e5dSvi117747  * Request-Line   =  Method SP Request-URI SP SIP-Version CRLF
89340cb5e5dSvi117747  */
89440cb5e5dSvi117747 int
89540cb5e5dSvi117747 sip_add_request_line(sip_msg_t sip_request, sip_method_t method,
89640cb5e5dSvi117747     char *request_uri)
89740cb5e5dSvi117747 {
89840cb5e5dSvi117747 	_sip_header_t	*new_header;
89940cb5e5dSvi117747 	int		 header_size;
90040cb5e5dSvi117747 	_sip_msg_t	*_sip_request;
90140cb5e5dSvi117747 
90240cb5e5dSvi117747 	if (method < INVITE || method >= MAX_SIP_METHODS ||
90340cb5e5dSvi117747 	    request_uri == NULL || sip_request == NULL) {
90440cb5e5dSvi117747 		return (EINVAL);
90540cb5e5dSvi117747 	}
90640cb5e5dSvi117747 
90740cb5e5dSvi117747 	_sip_request = (_sip_msg_t *)sip_request;
90840cb5e5dSvi117747 	(void) pthread_mutex_lock(&_sip_request->sip_msg_mutex);
90940cb5e5dSvi117747 	if (_sip_request->sip_msg_cannot_be_modified) {
91040cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_sip_request->sip_msg_mutex);
91140cb5e5dSvi117747 		return (ENOTSUP);
91240cb5e5dSvi117747 	}
91340cb5e5dSvi117747 
91440cb5e5dSvi117747 	header_size = strlen(sip_methods[method].name) + SIP_SPACE_LEN +
91540cb5e5dSvi117747 	    strlen(request_uri) + SIP_SPACE_LEN + strlen(SIP_VERSION) +
91640cb5e5dSvi117747 	    strlen(SIP_CRLF);
91740cb5e5dSvi117747 
91840cb5e5dSvi117747 	new_header = sip_new_header(header_size);
91940cb5e5dSvi117747 	if (new_header == NULL) {
92040cb5e5dSvi117747 		(void) pthread_mutex_unlock(&_sip_request->sip_msg_mutex);
92140cb5e5dSvi117747 		return (ENOMEM);
92240cb5e5dSvi117747 	}
92340cb5e5dSvi117747 	new_header->sip_hdr_sipmsg = _sip_request;
92440cb5e5dSvi117747 
92540cb5e5dSvi117747 	(void) snprintf(new_header->sip_hdr_start, header_size + 1,
92640cb5e5dSvi117747 	    "%s %s %s%s", sip_methods[method].name, request_uri,
92740cb5e5dSvi117747 	    SIP_VERSION, SIP_CRLF);
92840cb5e5dSvi117747 
92940cb5e5dSvi117747 	new_header->sip_hdr_next = _sip_request->sip_msg_start_line;
93040cb5e5dSvi117747 	_sip_request->sip_msg_start_line = new_header;
93140cb5e5dSvi117747 	_sip_request->sip_msg_len += header_size;
93240cb5e5dSvi117747 	(void) sip_parse_first_line(_sip_request->sip_msg_start_line,
93340cb5e5dSvi117747 	    &_sip_request->sip_msg_req_res);
93440cb5e5dSvi117747 	if (_sip_request->sip_msg_buf != NULL)
93540cb5e5dSvi117747 		_sip_request->sip_msg_modified = B_TRUE;
93640cb5e5dSvi117747 	(void) pthread_mutex_unlock(&_sip_request->sip_msg_mutex);
93740cb5e5dSvi117747 	return (0);
93840cb5e5dSvi117747 }
939