xref: /titanic_51/usr/src/lib/libcommputil/common/sdp.c (revision a93a1f58a8763fa69172980b98e3d24720c1136e)
1*a93a1f58Sgm209912 /*
2*a93a1f58Sgm209912  * CDDL HEADER START
3*a93a1f58Sgm209912  *
4*a93a1f58Sgm209912  * The contents of this file are subject to the terms of the
5*a93a1f58Sgm209912  * Common Development and Distribution License (the "License").
6*a93a1f58Sgm209912  * You may not use this file except in compliance with the License.
7*a93a1f58Sgm209912  *
8*a93a1f58Sgm209912  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*a93a1f58Sgm209912  * or http://www.opensolaris.org/os/licensing.
10*a93a1f58Sgm209912  * See the License for the specific language governing permissions
11*a93a1f58Sgm209912  * and limitations under the License.
12*a93a1f58Sgm209912  *
13*a93a1f58Sgm209912  * When distributing Covered Code, include this CDDL HEADER in each
14*a93a1f58Sgm209912  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*a93a1f58Sgm209912  * If applicable, add the following below this CDDL HEADER, with the
16*a93a1f58Sgm209912  * fields enclosed by brackets "[]" replaced with your own identifying
17*a93a1f58Sgm209912  * information: Portions Copyright [yyyy] [name of copyright owner]
18*a93a1f58Sgm209912  *
19*a93a1f58Sgm209912  * CDDL HEADER END
20*a93a1f58Sgm209912  */
21*a93a1f58Sgm209912 
22*a93a1f58Sgm209912 /*
23*a93a1f58Sgm209912  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*a93a1f58Sgm209912  * Use is subject to license terms.
25*a93a1f58Sgm209912  */
26*a93a1f58Sgm209912 
27*a93a1f58Sgm209912 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*a93a1f58Sgm209912 
29*a93a1f58Sgm209912 /*
30*a93a1f58Sgm209912  * Contains implementation of various interfaces exported by library
31*a93a1f58Sgm209912  */
32*a93a1f58Sgm209912 
33*a93a1f58Sgm209912 #include <stdio.h>
34*a93a1f58Sgm209912 #include <assert.h>
35*a93a1f58Sgm209912 #include <errno.h>
36*a93a1f58Sgm209912 #include <stdlib.h>
37*a93a1f58Sgm209912 #include <string.h>
38*a93a1f58Sgm209912 #include <ctype.h>
39*a93a1f58Sgm209912 #include <sdp.h>
40*a93a1f58Sgm209912 
41*a93a1f58Sgm209912 #include "sdp_parse.h"
42*a93a1f58Sgm209912 #include "commp_util.h"
43*a93a1f58Sgm209912 
44*a93a1f58Sgm209912 #define	FIELD_EQUALS_CRLF_LEN		4  /* first two characters and CRLF */
45*a93a1f58Sgm209912 
46*a93a1f58Sgm209912 #define	SDP_ATTR_TO_STR(m_attr) {					\
47*a93a1f58Sgm209912 	while ((m_attr) != NULL) {					\
48*a93a1f58Sgm209912 		if ((m_attr)->a_value != NULL) {			\
49*a93a1f58Sgm209912 			wrote = snprintf(buf, len, "a=%s%c%s%s",	\
50*a93a1f58Sgm209912 			    (m_attr)->a_name, COMMP_COLON, (m_attr)->  	\
51*a93a1f58Sgm209912 			    a_value, COMMP_CRLF);			\
52*a93a1f58Sgm209912 		} else {						\
53*a93a1f58Sgm209912 			wrote = snprintf(buf, len, "a=%s%s", (m_attr)-> \
54*a93a1f58Sgm209912 			    a_name, COMMP_CRLF);			\
55*a93a1f58Sgm209912 		}							\
56*a93a1f58Sgm209912 		len = len - wrote;					\
57*a93a1f58Sgm209912 		buf = buf + wrote;					\
58*a93a1f58Sgm209912 		(m_attr) = (m_attr)->a_next;				\
59*a93a1f58Sgm209912 	}								\
60*a93a1f58Sgm209912 }
61*a93a1f58Sgm209912 
62*a93a1f58Sgm209912 #define	SDP_KEY_TO_STR(m_key) {						\
63*a93a1f58Sgm209912 	if ((m_key) != NULL) {						\
64*a93a1f58Sgm209912 		if ((m_key)->k_enckey != NULL) {			\
65*a93a1f58Sgm209912 			wrote = snprintf(buf, len, "k=%s%c%s%s",	\
66*a93a1f58Sgm209912 			    (m_key)->k_method, COMMP_COLON, (m_key)->	\
67*a93a1f58Sgm209912 			    k_enckey, COMMP_CRLF);			\
68*a93a1f58Sgm209912 		} else {						\
69*a93a1f58Sgm209912 			wrote = snprintf(buf, len, "k=%s%s", (m_key)->	\
70*a93a1f58Sgm209912 			    k_method, COMMP_CRLF);			\
71*a93a1f58Sgm209912 		}							\
72*a93a1f58Sgm209912 		len = len - wrote;					\
73*a93a1f58Sgm209912 		buf = buf + wrote;					\
74*a93a1f58Sgm209912 	}								\
75*a93a1f58Sgm209912 }
76*a93a1f58Sgm209912 
77*a93a1f58Sgm209912 #define	SDP_BANDWIDTH_TO_STR(m_bw) {					\
78*a93a1f58Sgm209912 	while ((m_bw) != NULL) {					\
79*a93a1f58Sgm209912 		wrote = snprintf(buf, len, "b=%s%c%llu%s", (m_bw)->	\
80*a93a1f58Sgm209912 		    b_type, COMMP_COLON, (m_bw)->b_value, COMMP_CRLF);	\
81*a93a1f58Sgm209912 		len = len - wrote;					\
82*a93a1f58Sgm209912 		buf = buf + wrote;					\
83*a93a1f58Sgm209912 		(m_bw) = (m_bw)->b_next;				\
84*a93a1f58Sgm209912 	}								\
85*a93a1f58Sgm209912 }
86*a93a1f58Sgm209912 
87*a93a1f58Sgm209912 #define	SDP_INFORMATION_TO_STR(m_info) {				       \
88*a93a1f58Sgm209912 	if ((m_info) != NULL) {						       \
89*a93a1f58Sgm209912 		wrote = snprintf(buf, len, "i=%s%s", (m_info), COMMP_CRLF);    \
90*a93a1f58Sgm209912 		len = len - wrote;					       \
91*a93a1f58Sgm209912 		buf = buf + wrote;					       \
92*a93a1f58Sgm209912 	}								       \
93*a93a1f58Sgm209912 }
94*a93a1f58Sgm209912 
95*a93a1f58Sgm209912 #define	SDP_CONNECTION_TO_STR(m_conn) {					       \
96*a93a1f58Sgm209912 	while ((m_conn) != NULL) {					       \
97*a93a1f58Sgm209912 		if (strcasecmp((m_conn)->c_addrtype,			       \
98*a93a1f58Sgm209912 		    COMMP_ADDRTYPE_IP4) == 0) {				       \
99*a93a1f58Sgm209912 			if ((m_conn)->c_addrcount > 1) {		       \
100*a93a1f58Sgm209912 				wrote = snprintf(buf, len, "c=%s %s %s/%d/%d"  \
101*a93a1f58Sgm209912 				    "%s", (m_conn)->c_nettype, (m_conn)->      \
102*a93a1f58Sgm209912 				    c_addrtype, (m_conn)->c_address, (m_conn)->\
103*a93a1f58Sgm209912 				    c_ttl, (m_conn)->c_addrcount, COMMP_CRLF); \
104*a93a1f58Sgm209912 			} else if ((m_conn)->c_addrcount == 1) {	       \
105*a93a1f58Sgm209912 				wrote = snprintf(buf, len, "c=%s %s %s/%d%s",  \
106*a93a1f58Sgm209912 				    (m_conn)->c_nettype, (m_conn)->c_addrtype, \
107*a93a1f58Sgm209912 				    (m_conn)->c_address, (m_conn)->c_ttl,      \
108*a93a1f58Sgm209912 				    COMMP_CRLF);			       \
109*a93a1f58Sgm209912 			} else {					       \
110*a93a1f58Sgm209912 				wrote = snprintf(buf, len, "c=%s %s %s%s",     \
111*a93a1f58Sgm209912 				    (m_conn)->c_nettype, (m_conn)->c_addrtype, \
112*a93a1f58Sgm209912 				    (m_conn)->c_address, COMMP_CRLF);	       \
113*a93a1f58Sgm209912 			}						       \
114*a93a1f58Sgm209912 		} else if (strcasecmp((m_conn)->c_addrtype,		       \
115*a93a1f58Sgm209912 		    COMMP_ADDRTYPE_IP6) == 0) {                                \
116*a93a1f58Sgm209912 			if ((m_conn)->c_addrcount <= 1) {		       \
117*a93a1f58Sgm209912 				wrote = snprintf(buf, len, "c=%s %s %s%s",     \
118*a93a1f58Sgm209912 				    (m_conn)->c_nettype, (m_conn)->c_addrtype, \
119*a93a1f58Sgm209912 				    (m_conn)->c_address, COMMP_CRLF);	       \
120*a93a1f58Sgm209912 			} else {					       \
121*a93a1f58Sgm209912 				wrote = snprintf(buf, len, "c=%s %s %s/%d%s",  \
122*a93a1f58Sgm209912 				    (m_conn)->c_nettype, (m_conn)->c_addrtype, \
123*a93a1f58Sgm209912 				    (m_conn)->c_address, (m_conn)->c_addrcount,\
124*a93a1f58Sgm209912 				    COMMP_CRLF);			       \
125*a93a1f58Sgm209912 			}						       \
126*a93a1f58Sgm209912 		} else {						       \
127*a93a1f58Sgm209912 			wrote = snprintf(buf, len, "c=%s %s %s%s", (m_conn)->  \
128*a93a1f58Sgm209912 			    c_nettype, (m_conn)->c_addrtype, (m_conn)->        \
129*a93a1f58Sgm209912 			    c_address, COMMP_CRLF);			       \
130*a93a1f58Sgm209912 		}							       \
131*a93a1f58Sgm209912 		len = len - wrote;					       \
132*a93a1f58Sgm209912 		buf = buf + wrote;					       \
133*a93a1f58Sgm209912 		(m_conn) = (m_conn)->c_next;				       \
134*a93a1f58Sgm209912 	}								       \
135*a93a1f58Sgm209912 }
136*a93a1f58Sgm209912 
137*a93a1f58Sgm209912 #define	SDP_ADD_KEY(d_key, s_key) {					\
138*a93a1f58Sgm209912 	if ((s_key) != NULL) {						\
139*a93a1f58Sgm209912 		if (sdp_add_key(&(d_key), (s_key)->k_method,		\
140*a93a1f58Sgm209912 		    (s_key)->k_enckey) != 0) {				\
141*a93a1f58Sgm209912 			sdp_free_session(new_sess);			\
142*a93a1f58Sgm209912 			return (NULL);					\
143*a93a1f58Sgm209912 		}							\
144*a93a1f58Sgm209912 	}								\
145*a93a1f58Sgm209912 }
146*a93a1f58Sgm209912 
147*a93a1f58Sgm209912 #define	SDP_ADD_ATTRIBUTE(d_attr, s_attr) {				\
148*a93a1f58Sgm209912 	while ((s_attr) != NULL) {					\
149*a93a1f58Sgm209912 		if (sdp_add_attribute(&(d_attr), (s_attr)->a_name,	\
150*a93a1f58Sgm209912 		    (s_attr)->a_value) != 0) {		 		\
151*a93a1f58Sgm209912 			sdp_free_session(new_sess);			\
152*a93a1f58Sgm209912 			return (NULL);					\
153*a93a1f58Sgm209912 		}							\
154*a93a1f58Sgm209912 		(s_attr) = (s_attr)->a_next;				\
155*a93a1f58Sgm209912 	}								\
156*a93a1f58Sgm209912 }
157*a93a1f58Sgm209912 
158*a93a1f58Sgm209912 #define	SDP_ADD_BANDWIDTH(d_bw, s_bw) {					\
159*a93a1f58Sgm209912 	while ((s_bw) != NULL) {					\
160*a93a1f58Sgm209912 		if (sdp_add_bandwidth(&(d_bw), (s_bw)->b_type,		\
161*a93a1f58Sgm209912 		    (s_bw)->b_value) != 0) {				\
162*a93a1f58Sgm209912 			sdp_free_session(new_sess);			\
163*a93a1f58Sgm209912 			return (NULL);					\
164*a93a1f58Sgm209912 		}							\
165*a93a1f58Sgm209912 		(s_bw) = (s_bw)->b_next;				\
166*a93a1f58Sgm209912 	}								\
167*a93a1f58Sgm209912 }
168*a93a1f58Sgm209912 
169*a93a1f58Sgm209912 #define	SDP_ADD_CONNECTION(d_conn, s_conn) {				\
170*a93a1f58Sgm209912 	while ((s_conn) != NULL) {					\
171*a93a1f58Sgm209912 		if (sdp_add_connection(&(d_conn), (s_conn)->c_nettype,	\
172*a93a1f58Sgm209912 		    (s_conn)->c_addrtype, (s_conn)->c_address,		\
173*a93a1f58Sgm209912 		    (s_conn)->c_ttl, (s_conn)->c_addrcount) != 0) {	\
174*a93a1f58Sgm209912 			sdp_free_session(new_sess);			\
175*a93a1f58Sgm209912 			return (NULL);					\
176*a93a1f58Sgm209912 		}							\
177*a93a1f58Sgm209912 		(s_conn) = (s_conn)->c_next;				\
178*a93a1f58Sgm209912 	}								\
179*a93a1f58Sgm209912 }
180*a93a1f58Sgm209912 
181*a93a1f58Sgm209912 #define	SDP_LEN_CONNECTION(m_conn) {					  \
182*a93a1f58Sgm209912 	while ((m_conn) != NULL) {					  \
183*a93a1f58Sgm209912 		len += FIELD_EQUALS_CRLF_LEN;				  \
184*a93a1f58Sgm209912 		len += strlen((m_conn)->c_nettype);			  \
185*a93a1f58Sgm209912 		len += strlen((m_conn)->c_addrtype) + 1;		  \
186*a93a1f58Sgm209912 		len += strlen((m_conn)->c_address) + 1;			  \
187*a93a1f58Sgm209912 		len += snprintf(buf, 1, "%u", (m_conn)->c_ttl) + 1;	  \
188*a93a1f58Sgm209912 		len += snprintf(buf, 1, "%d", (m_conn)->c_addrcount) + 1; \
189*a93a1f58Sgm209912 		(m_conn) = (m_conn)->c_next;				  \
190*a93a1f58Sgm209912 	}								  \
191*a93a1f58Sgm209912 }
192*a93a1f58Sgm209912 
193*a93a1f58Sgm209912 #define	SDP_LEN_BANDWIDTH(m_bw) {					\
194*a93a1f58Sgm209912 	while ((m_bw) != NULL) {					\
195*a93a1f58Sgm209912 		len += FIELD_EQUALS_CRLF_LEN;				\
196*a93a1f58Sgm209912 		len += strlen((m_bw)->b_type);				\
197*a93a1f58Sgm209912 		len += snprintf(buf, 1, "%llu", (m_bw)->b_value) + 1;	\
198*a93a1f58Sgm209912 		(m_bw) = (m_bw)->b_next;				\
199*a93a1f58Sgm209912 	}								\
200*a93a1f58Sgm209912 }
201*a93a1f58Sgm209912 
202*a93a1f58Sgm209912 #define	SDP_LEN_KEY(m_key) {						\
203*a93a1f58Sgm209912 	if ((m_key) != NULL) {						\
204*a93a1f58Sgm209912 		len += FIELD_EQUALS_CRLF_LEN;				\
205*a93a1f58Sgm209912 		len += strlen((m_key)->k_method);			\
206*a93a1f58Sgm209912 		if ((m_key)->k_enckey != NULL)				\
207*a93a1f58Sgm209912 			len += strlen((m_key)->k_enckey) + 1;		\
208*a93a1f58Sgm209912 	}								\
209*a93a1f58Sgm209912 }
210*a93a1f58Sgm209912 
211*a93a1f58Sgm209912 #define	SDP_LEN_ATTRIBUTE(m_attr) {					\
212*a93a1f58Sgm209912 	while ((m_attr) != NULL) {					\
213*a93a1f58Sgm209912 		len += FIELD_EQUALS_CRLF_LEN;				\
214*a93a1f58Sgm209912 		len += strlen((m_attr)->a_name);			\
215*a93a1f58Sgm209912 		if ((m_attr)->a_value != NULL)				\
216*a93a1f58Sgm209912 			len += strlen((m_attr)->a_value) + 1;		\
217*a93a1f58Sgm209912 		(m_attr) = (m_attr)->a_next;				\
218*a93a1f58Sgm209912 	}								\
219*a93a1f58Sgm209912 }
220*a93a1f58Sgm209912 
221*a93a1f58Sgm209912 /*
222*a93a1f58Sgm209912  * Given a media list and media name ("audio", "video", et al), it searches
223*a93a1f58Sgm209912  * the list for that media. Returns NULL if media not present.
224*a93a1f58Sgm209912  */
225*a93a1f58Sgm209912 sdp_media_t *
226*a93a1f58Sgm209912 sdp_find_media(sdp_media_t *media, const char *name)
227*a93a1f58Sgm209912 {
228*a93a1f58Sgm209912 	if (media == NULL || name == NULL || (strlen(name) == 0)) {
229*a93a1f58Sgm209912 		return (NULL);
230*a93a1f58Sgm209912 	}
231*a93a1f58Sgm209912 	while (media != NULL) {
232*a93a1f58Sgm209912 		if (media->m_name != NULL) {
233*a93a1f58Sgm209912 			if (strcasecmp(name, media->m_name) == 0)
234*a93a1f58Sgm209912 				return (media);
235*a93a1f58Sgm209912 		}
236*a93a1f58Sgm209912 		media = media->m_next;
237*a93a1f58Sgm209912 	}
238*a93a1f58Sgm209912 	return (media);
239*a93a1f58Sgm209912 }
240*a93a1f58Sgm209912 
241*a93a1f58Sgm209912 /*
242*a93a1f58Sgm209912  * Given a attribute list and name of the attribute ("rtpmap", "fmtp", et al),
243*a93a1f58Sgm209912  * this API searches the list for that attribute. Returns NULL if not found.
244*a93a1f58Sgm209912  */
245*a93a1f58Sgm209912 sdp_attr_t *
246*a93a1f58Sgm209912 sdp_find_attribute(sdp_attr_t *attr, const char *name)
247*a93a1f58Sgm209912 {
248*a93a1f58Sgm209912 	if (attr == NULL || name == NULL || (strlen(name) == 0)) {
249*a93a1f58Sgm209912 		return (NULL);
250*a93a1f58Sgm209912 	}
251*a93a1f58Sgm209912 	while (attr != NULL) {
252*a93a1f58Sgm209912 		if (attr->a_name != NULL) {
253*a93a1f58Sgm209912 			if (strcasecmp(attr->a_name, name) == 0)
254*a93a1f58Sgm209912 				return (attr);
255*a93a1f58Sgm209912 		}
256*a93a1f58Sgm209912 		attr = attr->a_next;
257*a93a1f58Sgm209912 	}
258*a93a1f58Sgm209912 	return (attr);
259*a93a1f58Sgm209912 }
260*a93a1f58Sgm209912 
261*a93a1f58Sgm209912 /*
262*a93a1f58Sgm209912  * Given a media list and a format number, this API will return the rtpmap
263*a93a1f58Sgm209912  * attribute matching the format number.
264*a93a1f58Sgm209912  */
265*a93a1f58Sgm209912 sdp_attr_t *
266*a93a1f58Sgm209912 sdp_find_media_rtpmap(sdp_media_t *media, const char *format)
267*a93a1f58Sgm209912 {
268*a93a1f58Sgm209912 	sdp_attr_t		*attr = NULL;
269*a93a1f58Sgm209912 	char			*tmp = NULL;
270*a93a1f58Sgm209912 
271*a93a1f58Sgm209912 	if (media == NULL || format == NULL || (strlen(format) == 0)) {
272*a93a1f58Sgm209912 		return (NULL);
273*a93a1f58Sgm209912 	}
274*a93a1f58Sgm209912 	attr = media->m_attr;
275*a93a1f58Sgm209912 	while (attr != NULL) {
276*a93a1f58Sgm209912 		if (attr->a_name != NULL && (strcasecmp(attr->a_name,
277*a93a1f58Sgm209912 		    SDP_RTPMAP) == 0)) {
278*a93a1f58Sgm209912 			if (attr->a_value != NULL) {
279*a93a1f58Sgm209912 				tmp = attr->a_value;
280*a93a1f58Sgm209912 				while (isspace(*tmp))
281*a93a1f58Sgm209912 					++tmp;
282*a93a1f58Sgm209912 				if (strncasecmp(tmp, format,
283*a93a1f58Sgm209912 				    strlen(format)) == 0) {
284*a93a1f58Sgm209912 					return (attr);
285*a93a1f58Sgm209912 				}
286*a93a1f58Sgm209912 			}
287*a93a1f58Sgm209912 		}
288*a93a1f58Sgm209912 		attr = attr->a_next;
289*a93a1f58Sgm209912 	}
290*a93a1f58Sgm209912 	return (attr);
291*a93a1f58Sgm209912 }
292*a93a1f58Sgm209912 
293*a93a1f58Sgm209912 /*
294*a93a1f58Sgm209912  * Adds origin field to the session.
295*a93a1f58Sgm209912  * o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address>
296*a93a1f58Sgm209912  */
297*a93a1f58Sgm209912 int
298*a93a1f58Sgm209912 sdp_add_origin(sdp_session_t *session, const char *name, uint64_t id,
299*a93a1f58Sgm209912     uint64_t ver, const char *nettype, const char *addrtype,
300*a93a1f58Sgm209912     const char *address)
301*a93a1f58Sgm209912 {
302*a93a1f58Sgm209912 	sdp_origin_t		*origin;
303*a93a1f58Sgm209912 	int			ret = 0;
304*a93a1f58Sgm209912 
305*a93a1f58Sgm209912 	if (session == NULL || name == NULL || nettype == NULL ||
306*a93a1f58Sgm209912 	    addrtype == NULL || address == NULL) {
307*a93a1f58Sgm209912 		return (EINVAL);
308*a93a1f58Sgm209912 	}
309*a93a1f58Sgm209912 	if (session->s_origin != NULL)
310*a93a1f58Sgm209912 		return (EPROTO);
311*a93a1f58Sgm209912 	origin = calloc(1, sizeof (sdp_origin_t));
312*a93a1f58Sgm209912 	if (origin == NULL)
313*a93a1f58Sgm209912 		return (ENOMEM);
314*a93a1f58Sgm209912 	origin->o_id = id;
315*a93a1f58Sgm209912 	origin->o_version = ver;
316*a93a1f58Sgm209912 	if ((ret = commp_add_str(&origin->o_username, name, strlen(name))) != 0)
317*a93a1f58Sgm209912 		goto err_ret;
318*a93a1f58Sgm209912 	if ((ret = commp_add_str(&origin->o_nettype, nettype,
319*a93a1f58Sgm209912 	    strlen(nettype))) != 0) {
320*a93a1f58Sgm209912 		goto err_ret;
321*a93a1f58Sgm209912 	}
322*a93a1f58Sgm209912 	if ((ret = commp_add_str(&origin->o_addrtype, addrtype,
323*a93a1f58Sgm209912 	    strlen(addrtype))) != 0) {
324*a93a1f58Sgm209912 		goto err_ret;
325*a93a1f58Sgm209912 	}
326*a93a1f58Sgm209912 	if ((ret = commp_add_str(&origin->o_address, address,
327*a93a1f58Sgm209912 	    strlen(address))) != 0) {
328*a93a1f58Sgm209912 		goto err_ret;
329*a93a1f58Sgm209912 	}
330*a93a1f58Sgm209912 	session->s_origin = origin;
331*a93a1f58Sgm209912 	return (ret);
332*a93a1f58Sgm209912 err_ret:
333*a93a1f58Sgm209912 	sdp_free_origin(origin);
334*a93a1f58Sgm209912 	return (ret);
335*a93a1f58Sgm209912 }
336*a93a1f58Sgm209912 
337*a93a1f58Sgm209912 /*
338*a93a1f58Sgm209912  * Adds session name field to the session.
339*a93a1f58Sgm209912  * s=<session name>
340*a93a1f58Sgm209912  */
341*a93a1f58Sgm209912 int
342*a93a1f58Sgm209912 sdp_add_name(sdp_session_t *session, const char *name)
343*a93a1f58Sgm209912 {
344*a93a1f58Sgm209912 	if (session == NULL || name == NULL)
345*a93a1f58Sgm209912 		return (EINVAL);
346*a93a1f58Sgm209912 	if (session->s_name != NULL)
347*a93a1f58Sgm209912 		return (EPROTO);
348*a93a1f58Sgm209912 	return (commp_add_str(&session->s_name, name, strlen(name)));
349*a93a1f58Sgm209912 }
350*a93a1f58Sgm209912 
351*a93a1f58Sgm209912 /*
352*a93a1f58Sgm209912  * Adds session information field to the session or media section of SDP.
353*a93a1f58Sgm209912  * i=<session description>
354*a93a1f58Sgm209912  */
355*a93a1f58Sgm209912 int
356*a93a1f58Sgm209912 sdp_add_information(char **information, const char *value)
357*a93a1f58Sgm209912 {
358*a93a1f58Sgm209912 	if (information == NULL || value == NULL)
359*a93a1f58Sgm209912 		return (EINVAL);
360*a93a1f58Sgm209912 	if (*information != NULL)
361*a93a1f58Sgm209912 		return (EPROTO);
362*a93a1f58Sgm209912 	return (commp_add_str(information, value, strlen(value)));
363*a93a1f58Sgm209912 }
364*a93a1f58Sgm209912 
365*a93a1f58Sgm209912 /*
366*a93a1f58Sgm209912  * Adds uri field to the session.
367*a93a1f58Sgm209912  * u=<uri>
368*a93a1f58Sgm209912  */
369*a93a1f58Sgm209912 int
370*a93a1f58Sgm209912 sdp_add_uri(sdp_session_t *session, const char *uri)
371*a93a1f58Sgm209912 {
372*a93a1f58Sgm209912 	if (session == NULL || uri == NULL)
373*a93a1f58Sgm209912 		return (EINVAL);
374*a93a1f58Sgm209912 	if (session->s_uri != NULL)
375*a93a1f58Sgm209912 		return (EPROTO);
376*a93a1f58Sgm209912 	return (commp_add_str(&session->s_uri, uri, strlen(uri)));
377*a93a1f58Sgm209912 }
378*a93a1f58Sgm209912 
379*a93a1f58Sgm209912 /*
380*a93a1f58Sgm209912  * Adds email address field to the session.
381*a93a1f58Sgm209912  * e=<email-address>
382*a93a1f58Sgm209912  */
383*a93a1f58Sgm209912 int
384*a93a1f58Sgm209912 sdp_add_email(sdp_session_t *session, const char *email)
385*a93a1f58Sgm209912 {
386*a93a1f58Sgm209912 	if (session == NULL || email == NULL || (strlen(email) == 0))
387*a93a1f58Sgm209912 		return (EINVAL);
388*a93a1f58Sgm209912 	return (add_value_to_list(&session->s_email, email, strlen(email),
389*a93a1f58Sgm209912 	    B_TRUE));
390*a93a1f58Sgm209912 }
391*a93a1f58Sgm209912 
392*a93a1f58Sgm209912 /*
393*a93a1f58Sgm209912  * Adds phone number field to the session.
394*a93a1f58Sgm209912  * p=<phone-number>
395*a93a1f58Sgm209912  */
396*a93a1f58Sgm209912 int
397*a93a1f58Sgm209912 sdp_add_phone(sdp_session_t *session, const char *phone)
398*a93a1f58Sgm209912 {
399*a93a1f58Sgm209912 	if (session == NULL || phone == NULL || (strlen(phone) == 0))
400*a93a1f58Sgm209912 		return (EINVAL);
401*a93a1f58Sgm209912 	return (add_value_to_list(&session->s_phone, phone, strlen(phone),
402*a93a1f58Sgm209912 	    B_TRUE));
403*a93a1f58Sgm209912 }
404*a93a1f58Sgm209912 
405*a93a1f58Sgm209912 /*
406*a93a1f58Sgm209912  * Adds connection field to the session or media section of SDP
407*a93a1f58Sgm209912  * c=<nettype> <addrtype> <connection-address>[/ttl]/<number of addresses>
408*a93a1f58Sgm209912  */
409*a93a1f58Sgm209912 int
410*a93a1f58Sgm209912 sdp_add_connection(sdp_conn_t **conn, const char *nettype, const char *addrtype,
411*a93a1f58Sgm209912     const char *address, uint8_t ttl, int addrcount)
412*a93a1f58Sgm209912 {
413*a93a1f58Sgm209912 	sdp_conn_t		*tmp;
414*a93a1f58Sgm209912 	sdp_conn_t		*new_conn;
415*a93a1f58Sgm209912 	int			ret = 0;
416*a93a1f58Sgm209912 
417*a93a1f58Sgm209912 	if (conn == NULL || nettype == NULL || addrtype == NULL ||
418*a93a1f58Sgm209912 	    address == NULL) {
419*a93a1f58Sgm209912 		return (EINVAL);
420*a93a1f58Sgm209912 	}
421*a93a1f58Sgm209912 	new_conn = calloc(1, sizeof (sdp_conn_t));
422*a93a1f58Sgm209912 	if (new_conn == NULL)
423*a93a1f58Sgm209912 		return (ENOMEM);
424*a93a1f58Sgm209912 	new_conn->c_ttl = ttl;
425*a93a1f58Sgm209912 	new_conn->c_addrcount = addrcount;
426*a93a1f58Sgm209912 	if ((ret = commp_add_str(&new_conn->c_nettype, nettype,
427*a93a1f58Sgm209912 	    strlen(nettype))) != 0) {
428*a93a1f58Sgm209912 		goto err_ret;
429*a93a1f58Sgm209912 	}
430*a93a1f58Sgm209912 	if ((ret = commp_add_str(&new_conn->c_addrtype, addrtype,
431*a93a1f58Sgm209912 	    strlen(addrtype))) != 0) {
432*a93a1f58Sgm209912 		goto err_ret;
433*a93a1f58Sgm209912 	}
434*a93a1f58Sgm209912 	if ((ret = commp_add_str(&new_conn->c_address, address,
435*a93a1f58Sgm209912 	    strlen(address))) != 0) {
436*a93a1f58Sgm209912 		goto err_ret;
437*a93a1f58Sgm209912 	}
438*a93a1f58Sgm209912 	if (*conn == NULL) {
439*a93a1f58Sgm209912 		*conn = new_conn;
440*a93a1f58Sgm209912 	} else {
441*a93a1f58Sgm209912 		tmp = *conn;
442*a93a1f58Sgm209912 		while (tmp->c_next != NULL)
443*a93a1f58Sgm209912 			tmp = tmp->c_next;
444*a93a1f58Sgm209912 		tmp->c_next = new_conn;
445*a93a1f58Sgm209912 	}
446*a93a1f58Sgm209912 	return (ret);
447*a93a1f58Sgm209912 err_ret:
448*a93a1f58Sgm209912 	sdp_free_connection(new_conn);
449*a93a1f58Sgm209912 	return (ret);
450*a93a1f58Sgm209912 }
451*a93a1f58Sgm209912 
452*a93a1f58Sgm209912 /*
453*a93a1f58Sgm209912  * Adds bandwidth field to the session or media section of SDP.
454*a93a1f58Sgm209912  * b=<bwtype>:<bandwidth>
455*a93a1f58Sgm209912  */
456*a93a1f58Sgm209912 int
457*a93a1f58Sgm209912 sdp_add_bandwidth(sdp_bandwidth_t **bw, const char *type, uint64_t value)
458*a93a1f58Sgm209912 {
459*a93a1f58Sgm209912 	sdp_bandwidth_t		*new_bw;
460*a93a1f58Sgm209912 	sdp_bandwidth_t		*tmp;
461*a93a1f58Sgm209912 	int			ret = 0;
462*a93a1f58Sgm209912 
463*a93a1f58Sgm209912 	if (bw == NULL || type == NULL)
464*a93a1f58Sgm209912 		return (EINVAL);
465*a93a1f58Sgm209912 	new_bw = calloc(1, sizeof (sdp_bandwidth_t));
466*a93a1f58Sgm209912 	if (new_bw == NULL)
467*a93a1f58Sgm209912 		return (ENOMEM);
468*a93a1f58Sgm209912 	new_bw->b_value = value;
469*a93a1f58Sgm209912 	if ((ret = commp_add_str(&new_bw->b_type, type, strlen(type))) != 0) {
470*a93a1f58Sgm209912 		free(new_bw);
471*a93a1f58Sgm209912 		return (ret);
472*a93a1f58Sgm209912 	}
473*a93a1f58Sgm209912 	if (*bw == NULL) {
474*a93a1f58Sgm209912 		*bw = new_bw;
475*a93a1f58Sgm209912 	} else {
476*a93a1f58Sgm209912 		tmp = *bw;
477*a93a1f58Sgm209912 		while (tmp->b_next != NULL)
478*a93a1f58Sgm209912 			tmp = tmp->b_next;
479*a93a1f58Sgm209912 		tmp->b_next = new_bw;
480*a93a1f58Sgm209912 	}
481*a93a1f58Sgm209912 	return (ret);
482*a93a1f58Sgm209912 }
483*a93a1f58Sgm209912 
484*a93a1f58Sgm209912 /*
485*a93a1f58Sgm209912  * Adds time field to the session
486*a93a1f58Sgm209912  * t=<start-time> <stop-time>
487*a93a1f58Sgm209912  */
488*a93a1f58Sgm209912 int
489*a93a1f58Sgm209912 sdp_add_time(sdp_session_t *session, uint64_t starttime, uint64_t stoptime,
490*a93a1f58Sgm209912     sdp_time_t **time)
491*a93a1f58Sgm209912 {
492*a93a1f58Sgm209912 	sdp_time_t		*new_time;
493*a93a1f58Sgm209912 	sdp_time_t		*tmp;
494*a93a1f58Sgm209912 
495*a93a1f58Sgm209912 	if (time != NULL)
496*a93a1f58Sgm209912 		*time = NULL;
497*a93a1f58Sgm209912 	if (session == NULL) {
498*a93a1f58Sgm209912 		return (EINVAL);
499*a93a1f58Sgm209912 	}
500*a93a1f58Sgm209912 	new_time = calloc(1, sizeof (sdp_time_t));
501*a93a1f58Sgm209912 	if (new_time == NULL) {
502*a93a1f58Sgm209912 		return (ENOMEM);
503*a93a1f58Sgm209912 	}
504*a93a1f58Sgm209912 	new_time->t_start = starttime;
505*a93a1f58Sgm209912 	new_time->t_stop = stoptime;
506*a93a1f58Sgm209912 	tmp = session->s_time;
507*a93a1f58Sgm209912 	if (tmp == NULL)
508*a93a1f58Sgm209912 		session->s_time = new_time;
509*a93a1f58Sgm209912 	else {
510*a93a1f58Sgm209912 		while (tmp->t_next != NULL)
511*a93a1f58Sgm209912 			tmp = tmp->t_next;
512*a93a1f58Sgm209912 		tmp->t_next = new_time;
513*a93a1f58Sgm209912 	}
514*a93a1f58Sgm209912 	if (time != NULL)
515*a93a1f58Sgm209912 		*time = new_time;
516*a93a1f58Sgm209912 	return (0);
517*a93a1f58Sgm209912 }
518*a93a1f58Sgm209912 
519*a93a1f58Sgm209912 /*
520*a93a1f58Sgm209912  * Adds repeat field to the time structure of session
521*a93a1f58Sgm209912  * r=<repeat interval> <active duration> <offsets from start-time>
522*a93a1f58Sgm209912  */
523*a93a1f58Sgm209912 int
524*a93a1f58Sgm209912 sdp_add_repeat(sdp_time_t *time, uint64_t interval, uint64_t duration,
525*a93a1f58Sgm209912     const char *offset)
526*a93a1f58Sgm209912 {
527*a93a1f58Sgm209912 	sdp_repeat_t		*tmp;
528*a93a1f58Sgm209912 	sdp_repeat_t		*new_repeat;
529*a93a1f58Sgm209912 	int			ret = 0;
530*a93a1f58Sgm209912 
531*a93a1f58Sgm209912 	if (time == NULL || offset == NULL)
532*a93a1f58Sgm209912 		return (EINVAL);
533*a93a1f58Sgm209912 	new_repeat = calloc(1, sizeof (sdp_repeat_t));
534*a93a1f58Sgm209912 	if (new_repeat == NULL)
535*a93a1f58Sgm209912 		return (ENOMEM);
536*a93a1f58Sgm209912 	new_repeat->r_interval = interval;
537*a93a1f58Sgm209912 	new_repeat->r_duration = duration;
538*a93a1f58Sgm209912 	if ((ret = sdp_str_to_list(&new_repeat->r_offset, offset,
539*a93a1f58Sgm209912 	    strlen(offset), B_FALSE)) != 0) {
540*a93a1f58Sgm209912 		goto err_ret;
541*a93a1f58Sgm209912 	}
542*a93a1f58Sgm209912 	tmp = time->t_repeat;
543*a93a1f58Sgm209912 	if (tmp == NULL) {
544*a93a1f58Sgm209912 		time->t_repeat = new_repeat;
545*a93a1f58Sgm209912 	} else {
546*a93a1f58Sgm209912 		while (tmp->r_next != NULL)
547*a93a1f58Sgm209912 			tmp = tmp->r_next;
548*a93a1f58Sgm209912 		tmp->r_next = new_repeat;
549*a93a1f58Sgm209912 	}
550*a93a1f58Sgm209912 	return (ret);
551*a93a1f58Sgm209912 err_ret:
552*a93a1f58Sgm209912 	sdp_free_repeat(new_repeat);
553*a93a1f58Sgm209912 	return (ret);
554*a93a1f58Sgm209912 }
555*a93a1f58Sgm209912 
556*a93a1f58Sgm209912 /*
557*a93a1f58Sgm209912  * Adds time zone field to the session
558*a93a1f58Sgm209912  * z=<adjustment time> <offset> <adjustment time> <offset> ....
559*a93a1f58Sgm209912  */
560*a93a1f58Sgm209912 int
561*a93a1f58Sgm209912 sdp_add_zone(sdp_session_t *session, uint64_t time, const char *offset)
562*a93a1f58Sgm209912 {
563*a93a1f58Sgm209912 	sdp_zone_t		*new_zone;
564*a93a1f58Sgm209912 	sdp_zone_t		*tmp;
565*a93a1f58Sgm209912 	int			ret = 0;
566*a93a1f58Sgm209912 
567*a93a1f58Sgm209912 	if (session == NULL || offset == NULL)
568*a93a1f58Sgm209912 		return (EINVAL);
569*a93a1f58Sgm209912 	new_zone = calloc(1, sizeof (sdp_zone_t));
570*a93a1f58Sgm209912 	if (new_zone == NULL)
571*a93a1f58Sgm209912 		return (ENOMEM);
572*a93a1f58Sgm209912 	new_zone->z_time = time;
573*a93a1f58Sgm209912 	if ((ret = commp_add_str(&new_zone->z_offset, offset,
574*a93a1f58Sgm209912 	    strlen(offset))) != 0) {
575*a93a1f58Sgm209912 		free(new_zone);
576*a93a1f58Sgm209912 		return (ret);
577*a93a1f58Sgm209912 	}
578*a93a1f58Sgm209912 	tmp = session->s_zone;
579*a93a1f58Sgm209912 	if (tmp == NULL) {
580*a93a1f58Sgm209912 		session->s_zone = new_zone;
581*a93a1f58Sgm209912 	} else {
582*a93a1f58Sgm209912 		while (tmp->z_next != NULL) {
583*a93a1f58Sgm209912 			tmp = tmp->z_next;
584*a93a1f58Sgm209912 		}
585*a93a1f58Sgm209912 		tmp->z_next = new_zone;
586*a93a1f58Sgm209912 	}
587*a93a1f58Sgm209912 	return (ret);
588*a93a1f58Sgm209912 }
589*a93a1f58Sgm209912 
590*a93a1f58Sgm209912 /*
591*a93a1f58Sgm209912  * Adds key field to session or media section of SDP.
592*a93a1f58Sgm209912  * k=<method>
593*a93a1f58Sgm209912  * k=<method>:<encryption key>
594*a93a1f58Sgm209912  */
595*a93a1f58Sgm209912 int
596*a93a1f58Sgm209912 sdp_add_key(sdp_key_t **key, const char *method, const char *enckey)
597*a93a1f58Sgm209912 {
598*a93a1f58Sgm209912 	int			ret = 0;
599*a93a1f58Sgm209912 
600*a93a1f58Sgm209912 	if (key == NULL || method == NULL)
601*a93a1f58Sgm209912 		return (EINVAL);
602*a93a1f58Sgm209912 	if (*key != NULL)
603*a93a1f58Sgm209912 		return (EPROTO);
604*a93a1f58Sgm209912 	*key = calloc(1, sizeof (sdp_key_t));
605*a93a1f58Sgm209912 	if (*key == NULL)
606*a93a1f58Sgm209912 		return (ENOMEM);
607*a93a1f58Sgm209912 	if ((ret = commp_add_str(&((*key)->k_method), method,
608*a93a1f58Sgm209912 	    strlen(method))) != 0) {
609*a93a1f58Sgm209912 		goto err_ret;
610*a93a1f58Sgm209912 	}
611*a93a1f58Sgm209912 	if (enckey != NULL) {
612*a93a1f58Sgm209912 		if ((ret = commp_add_str(&((*key)->k_enckey), enckey,
613*a93a1f58Sgm209912 		    strlen(enckey))) != 0) {
614*a93a1f58Sgm209912 			goto err_ret;
615*a93a1f58Sgm209912 		}
616*a93a1f58Sgm209912 	}
617*a93a1f58Sgm209912 	return (ret);
618*a93a1f58Sgm209912 err_ret:
619*a93a1f58Sgm209912 	sdp_free_key(*key);
620*a93a1f58Sgm209912 	*key = NULL;
621*a93a1f58Sgm209912 	return (ret);
622*a93a1f58Sgm209912 }
623*a93a1f58Sgm209912 
624*a93a1f58Sgm209912 /*
625*a93a1f58Sgm209912  * Adds attribute field to session or media section of SDP.
626*a93a1f58Sgm209912  * a=<attribute>
627*a93a1f58Sgm209912  * a=<attribute>:<value>
628*a93a1f58Sgm209912  */
629*a93a1f58Sgm209912 int
630*a93a1f58Sgm209912 sdp_add_attribute(sdp_attr_t **attr, const char *name, const char *value)
631*a93a1f58Sgm209912 {
632*a93a1f58Sgm209912 	sdp_attr_t		*tmp;
633*a93a1f58Sgm209912 	sdp_attr_t		*new_attr;
634*a93a1f58Sgm209912 	int			ret = 0;
635*a93a1f58Sgm209912 
636*a93a1f58Sgm209912 	if (attr == NULL || name == NULL)
637*a93a1f58Sgm209912 		return (EINVAL);
638*a93a1f58Sgm209912 	new_attr = calloc(1, sizeof (sdp_attr_t));
639*a93a1f58Sgm209912 	if (new_attr == NULL)
640*a93a1f58Sgm209912 		return (ENOMEM);
641*a93a1f58Sgm209912 	if ((ret = commp_add_str(&new_attr->a_name, name, strlen(name))) != 0)
642*a93a1f58Sgm209912 		goto err_ret;
643*a93a1f58Sgm209912 	if (value != NULL) {
644*a93a1f58Sgm209912 		if ((ret = commp_add_str(&new_attr->a_value, value,
645*a93a1f58Sgm209912 		    strlen(value))) != 0) {
646*a93a1f58Sgm209912 			goto err_ret;
647*a93a1f58Sgm209912 		}
648*a93a1f58Sgm209912 	}
649*a93a1f58Sgm209912 	tmp = *attr;
650*a93a1f58Sgm209912 	if (tmp == NULL) {
651*a93a1f58Sgm209912 		*attr = new_attr;
652*a93a1f58Sgm209912 	} else {
653*a93a1f58Sgm209912 		while (tmp->a_next != NULL)
654*a93a1f58Sgm209912 			tmp = tmp->a_next;
655*a93a1f58Sgm209912 		tmp->a_next = new_attr;
656*a93a1f58Sgm209912 	}
657*a93a1f58Sgm209912 	return (ret);
658*a93a1f58Sgm209912 err_ret:
659*a93a1f58Sgm209912 	sdp_free_attribute(new_attr);
660*a93a1f58Sgm209912 	return (ret);
661*a93a1f58Sgm209912 }
662*a93a1f58Sgm209912 
663*a93a1f58Sgm209912 /*
664*a93a1f58Sgm209912  * Adds media field to the session.
665*a93a1f58Sgm209912  * m=<media> <port>[/portcount] <proto> <fmt> ...
666*a93a1f58Sgm209912  */
667*a93a1f58Sgm209912 int
668*a93a1f58Sgm209912 sdp_add_media(sdp_session_t *session, const char *name, uint_t port,
669*a93a1f58Sgm209912     int portcount, const char *protocol, const char *fmt, sdp_media_t **media)
670*a93a1f58Sgm209912 {
671*a93a1f58Sgm209912 	sdp_media_t		*tmp;
672*a93a1f58Sgm209912 	sdp_media_t		*new_media;
673*a93a1f58Sgm209912 	int			ret = 0;
674*a93a1f58Sgm209912 
675*a93a1f58Sgm209912 	if (media != NULL)
676*a93a1f58Sgm209912 		*media = NULL;
677*a93a1f58Sgm209912 	if (session == NULL || name == NULL || protocol == NULL ||
678*a93a1f58Sgm209912 	    portcount <= 0 || fmt == NULL) {
679*a93a1f58Sgm209912 		return (EINVAL);
680*a93a1f58Sgm209912 	}
681*a93a1f58Sgm209912 	new_media = calloc(1, sizeof (sdp_media_t));
682*a93a1f58Sgm209912 	if (new_media == NULL) {
683*a93a1f58Sgm209912 		return (ENOMEM);
684*a93a1f58Sgm209912 	}
685*a93a1f58Sgm209912 	new_media->m_session = session;
686*a93a1f58Sgm209912 	new_media->m_port = port;
687*a93a1f58Sgm209912 	new_media->m_portcount = portcount;
688*a93a1f58Sgm209912 	if ((ret = commp_add_str(&new_media->m_name, name, strlen(name))) != 0)
689*a93a1f58Sgm209912 		goto err_ret;
690*a93a1f58Sgm209912 	if ((ret = commp_add_str(&new_media->m_proto, protocol,
691*a93a1f58Sgm209912 	    strlen(protocol))) != 0) {
692*a93a1f58Sgm209912 		goto err_ret;
693*a93a1f58Sgm209912 	}
694*a93a1f58Sgm209912 	if ((ret = sdp_str_to_list(&new_media->m_format, fmt,
695*a93a1f58Sgm209912 	    strlen(fmt), B_TRUE)) != 0) {
696*a93a1f58Sgm209912 		goto err_ret;
697*a93a1f58Sgm209912 	}
698*a93a1f58Sgm209912 	tmp = session->s_media;
699*a93a1f58Sgm209912 	if (tmp == NULL) {
700*a93a1f58Sgm209912 		session->s_media = new_media;
701*a93a1f58Sgm209912 	} else {
702*a93a1f58Sgm209912 		while (tmp->m_next != NULL)
703*a93a1f58Sgm209912 			tmp = tmp->m_next;
704*a93a1f58Sgm209912 		tmp->m_next = new_media;
705*a93a1f58Sgm209912 	}
706*a93a1f58Sgm209912 	if (media != NULL)
707*a93a1f58Sgm209912 		*media = new_media;
708*a93a1f58Sgm209912 	return (0);
709*a93a1f58Sgm209912 err_ret:
710*a93a1f58Sgm209912 	sdp_free_media(new_media);
711*a93a1f58Sgm209912 	return (ret);
712*a93a1f58Sgm209912 }
713*a93a1f58Sgm209912 
714*a93a1f58Sgm209912 /*
715*a93a1f58Sgm209912  * This internal API is required by sdp_session_to_str(). It determines the
716*a93a1f58Sgm209912  * length of buffer that is required to hold the session. Since the RFC does
717*a93a1f58Sgm209912  * not limit the size of various sub-fields in the field. We need to scan
718*a93a1f58Sgm209912  * through the structure to determine the length.
719*a93a1f58Sgm209912  */
720*a93a1f58Sgm209912 int
721*a93a1f58Sgm209912 sdp_get_length(const sdp_session_t *session)
722*a93a1f58Sgm209912 {
723*a93a1f58Sgm209912 	int			len = 0;
724*a93a1f58Sgm209912 	char			buf[1];
725*a93a1f58Sgm209912 	sdp_list_t		*list;
726*a93a1f58Sgm209912 	sdp_conn_t		*conn;
727*a93a1f58Sgm209912 	sdp_bandwidth_t		*bw;
728*a93a1f58Sgm209912 	sdp_zone_t		*zone;
729*a93a1f58Sgm209912 	sdp_time_t		*time;
730*a93a1f58Sgm209912 	sdp_repeat_t		*repeat;
731*a93a1f58Sgm209912 	sdp_attr_t		*attr;
732*a93a1f58Sgm209912 	sdp_media_t		*media;
733*a93a1f58Sgm209912 
734*a93a1f58Sgm209912 	len += FIELD_EQUALS_CRLF_LEN;
735*a93a1f58Sgm209912 	len += snprintf(buf, 1, "%d", session->s_version);
736*a93a1f58Sgm209912 	if (session->s_origin != NULL) {
737*a93a1f58Sgm209912 		len += FIELD_EQUALS_CRLF_LEN;
738*a93a1f58Sgm209912 		len += strlen(session->s_origin->o_username);
739*a93a1f58Sgm209912 		len += snprintf(buf, 1, "%llu", session->s_origin->o_id) + 1;
740*a93a1f58Sgm209912 		len += snprintf(buf, 1, "%llu", session->s_origin->o_version)
741*a93a1f58Sgm209912 		    + 1;
742*a93a1f58Sgm209912 		len += strlen(session->s_origin->o_nettype) + 1;
743*a93a1f58Sgm209912 		len += strlen(session->s_origin->o_addrtype) + 1;
744*a93a1f58Sgm209912 		len += strlen(session->s_origin->o_address) + 1;
745*a93a1f58Sgm209912 	}
746*a93a1f58Sgm209912 	if (session->s_name != NULL)
747*a93a1f58Sgm209912 		len += strlen(session->s_name) + FIELD_EQUALS_CRLF_LEN;
748*a93a1f58Sgm209912 	if (session->s_info != NULL)
749*a93a1f58Sgm209912 		len += strlen(session->s_info) + FIELD_EQUALS_CRLF_LEN;
750*a93a1f58Sgm209912 	if (session->s_uri != NULL)
751*a93a1f58Sgm209912 		len += strlen(session->s_uri) + FIELD_EQUALS_CRLF_LEN;
752*a93a1f58Sgm209912 	list = session->s_email;
753*a93a1f58Sgm209912 	while (list != NULL) {
754*a93a1f58Sgm209912 		len += strlen((char *)list->value) + FIELD_EQUALS_CRLF_LEN;
755*a93a1f58Sgm209912 		list = list->next;
756*a93a1f58Sgm209912 	}
757*a93a1f58Sgm209912 	list = session->s_phone;
758*a93a1f58Sgm209912 	while (list != NULL) {
759*a93a1f58Sgm209912 		len += strlen((char *)list->value) + FIELD_EQUALS_CRLF_LEN;
760*a93a1f58Sgm209912 		list = list->next;
761*a93a1f58Sgm209912 	}
762*a93a1f58Sgm209912 	conn = session->s_conn;
763*a93a1f58Sgm209912 	SDP_LEN_CONNECTION(conn);
764*a93a1f58Sgm209912 	bw = session->s_bw;
765*a93a1f58Sgm209912 	SDP_LEN_BANDWIDTH(bw);
766*a93a1f58Sgm209912 	time = session->s_time;
767*a93a1f58Sgm209912 	while (time != NULL) {
768*a93a1f58Sgm209912 		len += FIELD_EQUALS_CRLF_LEN;
769*a93a1f58Sgm209912 		len += snprintf(buf, 1, "%llu", time->t_start);
770*a93a1f58Sgm209912 		len += snprintf(buf, 1, "%llu", time->t_stop) + 1;
771*a93a1f58Sgm209912 		repeat = time->t_repeat;
772*a93a1f58Sgm209912 		while (repeat != NULL) {
773*a93a1f58Sgm209912 			len += FIELD_EQUALS_CRLF_LEN;
774*a93a1f58Sgm209912 			len += snprintf(buf, 1, "%llu", repeat->r_interval);
775*a93a1f58Sgm209912 			len += snprintf(buf, 1, "%llu", repeat->r_duration) + 1;
776*a93a1f58Sgm209912 			list = repeat->r_offset;
777*a93a1f58Sgm209912 			while (list != NULL) {
778*a93a1f58Sgm209912 				len += snprintf(buf, 1, "%llu",
779*a93a1f58Sgm209912 				    *(uint64_t *)list->value) + 1;
780*a93a1f58Sgm209912 				list = list->next;
781*a93a1f58Sgm209912 			}
782*a93a1f58Sgm209912 			repeat = repeat->r_next;
783*a93a1f58Sgm209912 		}
784*a93a1f58Sgm209912 		time = time->t_next;
785*a93a1f58Sgm209912 	}
786*a93a1f58Sgm209912 	if (session->s_zone != NULL)
787*a93a1f58Sgm209912 		len += FIELD_EQUALS_CRLF_LEN;
788*a93a1f58Sgm209912 	zone = session->s_zone;
789*a93a1f58Sgm209912 	while (zone != NULL) {
790*a93a1f58Sgm209912 		len += snprintf(buf, 1, "%llu", zone->z_time) + 1;
791*a93a1f58Sgm209912 		len += strlen(zone->z_offset) + 1;
792*a93a1f58Sgm209912 		zone = zone->z_next;
793*a93a1f58Sgm209912 	}
794*a93a1f58Sgm209912 	SDP_LEN_KEY(session->s_key);
795*a93a1f58Sgm209912 	attr = session->s_attr;
796*a93a1f58Sgm209912 	SDP_LEN_ATTRIBUTE(attr);
797*a93a1f58Sgm209912 	media = session->s_media;
798*a93a1f58Sgm209912 	while (media != NULL) {
799*a93a1f58Sgm209912 		len += FIELD_EQUALS_CRLF_LEN;
800*a93a1f58Sgm209912 		len += strlen(media->m_name);
801*a93a1f58Sgm209912 		len += snprintf(buf, 1, "%u", media->m_port) + 1;
802*a93a1f58Sgm209912 		len += snprintf(buf, 1, "%d", media->m_portcount) + 1;
803*a93a1f58Sgm209912 		len += strlen(media->m_proto) + 1;
804*a93a1f58Sgm209912 		list = media->m_format;
805*a93a1f58Sgm209912 		while (list != NULL) {
806*a93a1f58Sgm209912 			len += strlen((char *)list->value) + 1;
807*a93a1f58Sgm209912 			list = list->next;
808*a93a1f58Sgm209912 		}
809*a93a1f58Sgm209912 		if (media->m_info != NULL)
810*a93a1f58Sgm209912 			len += strlen(media->m_info) + FIELD_EQUALS_CRLF_LEN;
811*a93a1f58Sgm209912 		conn = media->m_conn;
812*a93a1f58Sgm209912 		SDP_LEN_CONNECTION(conn);
813*a93a1f58Sgm209912 		bw = media->m_bw;
814*a93a1f58Sgm209912 		SDP_LEN_BANDWIDTH(bw);
815*a93a1f58Sgm209912 		SDP_LEN_KEY(media->m_key);
816*a93a1f58Sgm209912 		attr = media->m_attr;
817*a93a1f58Sgm209912 		SDP_LEN_ATTRIBUTE(attr);
818*a93a1f58Sgm209912 		media = media->m_next;
819*a93a1f58Sgm209912 	}
820*a93a1f58Sgm209912 	return (len);
821*a93a1f58Sgm209912 }
822*a93a1f58Sgm209912 
823*a93a1f58Sgm209912 /*
824*a93a1f58Sgm209912  * Given a session structure it clones (deep copy) and returns the cloned copy
825*a93a1f58Sgm209912  */
826*a93a1f58Sgm209912 sdp_session_t *
827*a93a1f58Sgm209912 sdp_clone_session(const sdp_session_t *session)
828*a93a1f58Sgm209912 {
829*a93a1f58Sgm209912 	sdp_session_t		*new_sess;
830*a93a1f58Sgm209912 	sdp_origin_t		*origin;
831*a93a1f58Sgm209912 	sdp_list_t		*list;
832*a93a1f58Sgm209912 	sdp_time_t		*time;
833*a93a1f58Sgm209912 	sdp_time_t		*new_time;
834*a93a1f58Sgm209912 	sdp_repeat_t		*repeat;
835*a93a1f58Sgm209912 	sdp_media_t		*media;
836*a93a1f58Sgm209912 	sdp_media_t		*new_media;
837*a93a1f58Sgm209912 	sdp_conn_t		*conn;
838*a93a1f58Sgm209912 	sdp_bandwidth_t		*bw;
839*a93a1f58Sgm209912 	sdp_attr_t		*attr;
840*a93a1f58Sgm209912 	sdp_zone_t		*zone;
841*a93a1f58Sgm209912 	char			*offset = NULL;
842*a93a1f58Sgm209912 	char			*format = NULL;
843*a93a1f58Sgm209912 
844*a93a1f58Sgm209912 	if (session == NULL)
845*a93a1f58Sgm209912 		return (NULL);
846*a93a1f58Sgm209912 	new_sess = calloc(1, sizeof (sdp_session_t));
847*a93a1f58Sgm209912 	if (new_sess == NULL)
848*a93a1f58Sgm209912 		return (NULL);
849*a93a1f58Sgm209912 	new_sess->sdp_session_version = session->sdp_session_version;
850*a93a1f58Sgm209912 	new_sess->s_version = session->s_version;
851*a93a1f58Sgm209912 	origin = session->s_origin;
852*a93a1f58Sgm209912 	if (origin != NULL && (sdp_add_origin(new_sess, origin->o_username,
853*a93a1f58Sgm209912 	    origin->o_id, origin->o_version, origin->o_nettype, origin->
854*a93a1f58Sgm209912 	    o_addrtype, origin->o_address) != 0)) {
855*a93a1f58Sgm209912 		goto err_ret;
856*a93a1f58Sgm209912 	}
857*a93a1f58Sgm209912 	if (session->s_name != NULL && sdp_add_name(new_sess, session->
858*a93a1f58Sgm209912 	    s_name) != 0) {
859*a93a1f58Sgm209912 		goto err_ret;
860*a93a1f58Sgm209912 	}
861*a93a1f58Sgm209912 	if (session->s_info != NULL && sdp_add_information(&new_sess->
862*a93a1f58Sgm209912 	    s_info, session->s_info) != 0) {
863*a93a1f58Sgm209912 		goto err_ret;
864*a93a1f58Sgm209912 	}
865*a93a1f58Sgm209912 	if (session->s_uri != NULL && sdp_add_uri(new_sess, session->
866*a93a1f58Sgm209912 	    s_uri) != 0) {
867*a93a1f58Sgm209912 		goto err_ret;
868*a93a1f58Sgm209912 	}
869*a93a1f58Sgm209912 	list = session->s_email;
870*a93a1f58Sgm209912 	while (list != NULL) {
871*a93a1f58Sgm209912 		if (sdp_add_email(new_sess, (char *)list->value) != 0)
872*a93a1f58Sgm209912 			goto err_ret;
873*a93a1f58Sgm209912 		list = list->next;
874*a93a1f58Sgm209912 	}
875*a93a1f58Sgm209912 	list = session->s_phone;
876*a93a1f58Sgm209912 	while (list != NULL) {
877*a93a1f58Sgm209912 		if (sdp_add_phone(new_sess, (char *)list->value) != 0)
878*a93a1f58Sgm209912 			goto err_ret;
879*a93a1f58Sgm209912 		list = list->next;
880*a93a1f58Sgm209912 	}
881*a93a1f58Sgm209912 	conn = session->s_conn;
882*a93a1f58Sgm209912 	SDP_ADD_CONNECTION(new_sess->s_conn, conn);
883*a93a1f58Sgm209912 	bw = session->s_bw;
884*a93a1f58Sgm209912 	SDP_ADD_BANDWIDTH(new_sess->s_bw, bw);
885*a93a1f58Sgm209912 	time = session->s_time;
886*a93a1f58Sgm209912 	while (time != NULL) {
887*a93a1f58Sgm209912 		if (sdp_add_time(new_sess, time->t_start, time->t_stop,
888*a93a1f58Sgm209912 		    &new_time) != 0) {
889*a93a1f58Sgm209912 			goto err_ret;
890*a93a1f58Sgm209912 		}
891*a93a1f58Sgm209912 		repeat = time->t_repeat;
892*a93a1f58Sgm209912 		while (repeat != NULL) {
893*a93a1f58Sgm209912 			if (sdp_list_to_str(repeat->r_offset, &offset,
894*a93a1f58Sgm209912 			    B_FALSE) != 0) {
895*a93a1f58Sgm209912 				goto err_ret;
896*a93a1f58Sgm209912 			}
897*a93a1f58Sgm209912 			if (sdp_add_repeat(new_time, repeat->r_interval,
898*a93a1f58Sgm209912 			    repeat->r_duration, offset) != 0) {
899*a93a1f58Sgm209912 				free(offset);
900*a93a1f58Sgm209912 				goto err_ret;
901*a93a1f58Sgm209912 			}
902*a93a1f58Sgm209912 			free(offset);
903*a93a1f58Sgm209912 			repeat = repeat->r_next;
904*a93a1f58Sgm209912 		}
905*a93a1f58Sgm209912 		time = time->t_next;
906*a93a1f58Sgm209912 	}
907*a93a1f58Sgm209912 	zone = session->s_zone;
908*a93a1f58Sgm209912 	while (zone != NULL) {
909*a93a1f58Sgm209912 		if (sdp_add_zone(new_sess, zone->z_time, zone->z_offset) != 0)
910*a93a1f58Sgm209912 			goto err_ret;
911*a93a1f58Sgm209912 		zone = zone->z_next;
912*a93a1f58Sgm209912 	}
913*a93a1f58Sgm209912 	SDP_ADD_KEY(new_sess->s_key, session->s_key);
914*a93a1f58Sgm209912 	attr = session->s_attr;
915*a93a1f58Sgm209912 	SDP_ADD_ATTRIBUTE(new_sess->s_attr, attr);
916*a93a1f58Sgm209912 	media = session->s_media;
917*a93a1f58Sgm209912 	while (media != NULL) {
918*a93a1f58Sgm209912 		if (sdp_list_to_str(media->m_format, &format, B_TRUE) != 0)
919*a93a1f58Sgm209912 			goto err_ret;
920*a93a1f58Sgm209912 		if (sdp_add_media(new_sess, media->m_name,
921*a93a1f58Sgm209912 		    media->m_port, media->m_portcount, media->m_proto,
922*a93a1f58Sgm209912 		    format, &new_media) != 0) {
923*a93a1f58Sgm209912 			free(format);
924*a93a1f58Sgm209912 			goto err_ret;
925*a93a1f58Sgm209912 		}
926*a93a1f58Sgm209912 		free(format);
927*a93a1f58Sgm209912 		if (media->m_info != NULL) {
928*a93a1f58Sgm209912 			if (sdp_add_information(&new_media->m_info,
929*a93a1f58Sgm209912 			    media->m_info) != 0) {
930*a93a1f58Sgm209912 				goto err_ret;
931*a93a1f58Sgm209912 			}
932*a93a1f58Sgm209912 		}
933*a93a1f58Sgm209912 		conn = media->m_conn;
934*a93a1f58Sgm209912 		SDP_ADD_CONNECTION(new_media->m_conn, conn);
935*a93a1f58Sgm209912 		bw = media->m_bw;
936*a93a1f58Sgm209912 		SDP_ADD_BANDWIDTH(new_media->m_bw, bw);
937*a93a1f58Sgm209912 		SDP_ADD_KEY(new_media->m_key, media->m_key);
938*a93a1f58Sgm209912 		attr = media->m_attr;
939*a93a1f58Sgm209912 		SDP_ADD_ATTRIBUTE(new_media->m_attr, attr);
940*a93a1f58Sgm209912 		new_media->m_session = new_sess;
941*a93a1f58Sgm209912 		media = media->m_next;
942*a93a1f58Sgm209912 	}
943*a93a1f58Sgm209912 	return (new_sess);
944*a93a1f58Sgm209912 err_ret:
945*a93a1f58Sgm209912 	sdp_free_session(new_sess);
946*a93a1f58Sgm209912 	return (NULL);
947*a93a1f58Sgm209912 }
948*a93a1f58Sgm209912 
949*a93a1f58Sgm209912 /*
950*a93a1f58Sgm209912  * should i check if individual members are NULL, if not snprintf
951*a93a1f58Sgm209912  * will core dump.
952*a93a1f58Sgm209912  */
953*a93a1f58Sgm209912 /*
954*a93a1f58Sgm209912  * Given a session structure, this API converts it into character
955*a93a1f58Sgm209912  * buffer, which will be used as a payload later on.
956*a93a1f58Sgm209912  */
957*a93a1f58Sgm209912 char *
958*a93a1f58Sgm209912 sdp_session_to_str(const sdp_session_t *session, int *error)
959*a93a1f58Sgm209912 {
960*a93a1f58Sgm209912 	char			*ret = NULL;
961*a93a1f58Sgm209912 	char			*buf = NULL;
962*a93a1f58Sgm209912 	int			len = 0;
963*a93a1f58Sgm209912 	int			s_len = 0;
964*a93a1f58Sgm209912 	int			wrote = 0;
965*a93a1f58Sgm209912 	sdp_origin_t		*origin;
966*a93a1f58Sgm209912 	sdp_list_t		*list;
967*a93a1f58Sgm209912 	sdp_conn_t		*conn;
968*a93a1f58Sgm209912 	sdp_attr_t		*attr;
969*a93a1f58Sgm209912 	sdp_bandwidth_t		*bw;
970*a93a1f58Sgm209912 	sdp_time_t		*time;
971*a93a1f58Sgm209912 	sdp_repeat_t		*repeat;
972*a93a1f58Sgm209912 	sdp_zone_t		*zone;
973*a93a1f58Sgm209912 	sdp_media_t		*media;
974*a93a1f58Sgm209912 
975*a93a1f58Sgm209912 	if (error != NULL)
976*a93a1f58Sgm209912 		*error = 0;
977*a93a1f58Sgm209912 	if (session == NULL) {
978*a93a1f58Sgm209912 		if (error != NULL)
979*a93a1f58Sgm209912 			*error = EINVAL;
980*a93a1f58Sgm209912 		return (NULL);
981*a93a1f58Sgm209912 	}
982*a93a1f58Sgm209912 	s_len = sdp_get_length(session);
983*a93a1f58Sgm209912 	ret = malloc(s_len + 1);
984*a93a1f58Sgm209912 	if (ret == NULL) {
985*a93a1f58Sgm209912 		if (error != NULL)
986*a93a1f58Sgm209912 			*error = ENOMEM;
987*a93a1f58Sgm209912 		return (NULL);
988*a93a1f58Sgm209912 	}
989*a93a1f58Sgm209912 	buf = ret;
990*a93a1f58Sgm209912 	len = s_len + 1;
991*a93a1f58Sgm209912 	wrote = snprintf(buf, len, "v=%d%s", session->s_version, COMMP_CRLF);
992*a93a1f58Sgm209912 	len = len - wrote;
993*a93a1f58Sgm209912 	buf = buf + wrote;
994*a93a1f58Sgm209912 	origin = session->s_origin;
995*a93a1f58Sgm209912 	if (origin != NULL) {
996*a93a1f58Sgm209912 		wrote = snprintf(buf, len, "o=%s %llu %llu %s %s %s%s",
997*a93a1f58Sgm209912 		    origin->o_username, origin->o_id, origin->o_version,
998*a93a1f58Sgm209912 		    origin->o_nettype, origin->o_addrtype, origin->o_address,
999*a93a1f58Sgm209912 		    COMMP_CRLF);
1000*a93a1f58Sgm209912 		len = len - wrote;
1001*a93a1f58Sgm209912 		buf = buf + wrote;
1002*a93a1f58Sgm209912 	}
1003*a93a1f58Sgm209912 	if (session->s_name != NULL) {
1004*a93a1f58Sgm209912 		wrote = snprintf(buf, len, "s=%s%s", session->s_name,
1005*a93a1f58Sgm209912 		    COMMP_CRLF);
1006*a93a1f58Sgm209912 		len = len - wrote;
1007*a93a1f58Sgm209912 		buf = buf + wrote;
1008*a93a1f58Sgm209912 	}
1009*a93a1f58Sgm209912 	SDP_INFORMATION_TO_STR(session->s_info);
1010*a93a1f58Sgm209912 	if (session->s_uri != NULL) {
1011*a93a1f58Sgm209912 		wrote = snprintf(buf, len, "u=%s%s", session->s_uri,
1012*a93a1f58Sgm209912 		    COMMP_CRLF);
1013*a93a1f58Sgm209912 		len = len - wrote;
1014*a93a1f58Sgm209912 		buf = buf + wrote;
1015*a93a1f58Sgm209912 	}
1016*a93a1f58Sgm209912 	list = session->s_email;
1017*a93a1f58Sgm209912 	while (list != NULL) {
1018*a93a1f58Sgm209912 		wrote = snprintf(buf, len, "e=%s%s", (char *)list->value,
1019*a93a1f58Sgm209912 		    COMMP_CRLF);
1020*a93a1f58Sgm209912 		len = len - wrote;
1021*a93a1f58Sgm209912 		buf = buf + wrote;
1022*a93a1f58Sgm209912 		list = list->next;
1023*a93a1f58Sgm209912 	}
1024*a93a1f58Sgm209912 	list = session->s_phone;
1025*a93a1f58Sgm209912 	while (list != NULL) {
1026*a93a1f58Sgm209912 		wrote = snprintf(buf, len, "p=%s%s", (char *)list->value,
1027*a93a1f58Sgm209912 		    COMMP_CRLF);
1028*a93a1f58Sgm209912 		len = len - wrote;
1029*a93a1f58Sgm209912 		buf = buf + wrote;
1030*a93a1f58Sgm209912 		list = list->next;
1031*a93a1f58Sgm209912 	}
1032*a93a1f58Sgm209912 	conn = session->s_conn;
1033*a93a1f58Sgm209912 	SDP_CONNECTION_TO_STR(conn);
1034*a93a1f58Sgm209912 	bw = session->s_bw;
1035*a93a1f58Sgm209912 	SDP_BANDWIDTH_TO_STR(bw);
1036*a93a1f58Sgm209912 	time = session->s_time;
1037*a93a1f58Sgm209912 	while (time != NULL) {
1038*a93a1f58Sgm209912 		wrote = snprintf(buf, len, "t=%llu %llu%s", time->t_start,
1039*a93a1f58Sgm209912 		    time->t_stop, COMMP_CRLF);
1040*a93a1f58Sgm209912 		len = len - wrote;
1041*a93a1f58Sgm209912 		buf = buf + wrote;
1042*a93a1f58Sgm209912 		repeat = time->t_repeat;
1043*a93a1f58Sgm209912 		while (repeat != NULL) {
1044*a93a1f58Sgm209912 			wrote = snprintf(buf, len, "r=%llu %llu", repeat->
1045*a93a1f58Sgm209912 			    r_interval, repeat->r_duration);
1046*a93a1f58Sgm209912 			len = len - wrote;
1047*a93a1f58Sgm209912 			buf = buf + wrote;
1048*a93a1f58Sgm209912 			list = repeat->r_offset;
1049*a93a1f58Sgm209912 			while (list != NULL) {
1050*a93a1f58Sgm209912 				wrote = snprintf(buf, len, " %llu",
1051*a93a1f58Sgm209912 				    *(uint64_t *)list->value);
1052*a93a1f58Sgm209912 				len = len - wrote;
1053*a93a1f58Sgm209912 				buf = buf + wrote;
1054*a93a1f58Sgm209912 				list = list->next;
1055*a93a1f58Sgm209912 			}
1056*a93a1f58Sgm209912 			wrote = snprintf(buf, len, "%s", COMMP_CRLF);
1057*a93a1f58Sgm209912 			len = len - wrote;
1058*a93a1f58Sgm209912 			buf = buf + wrote;
1059*a93a1f58Sgm209912 			repeat = repeat->r_next;
1060*a93a1f58Sgm209912 		}
1061*a93a1f58Sgm209912 		time = time->t_next;
1062*a93a1f58Sgm209912 	}
1063*a93a1f58Sgm209912 	zone = session->s_zone;
1064*a93a1f58Sgm209912 	if (zone != NULL) {
1065*a93a1f58Sgm209912 		wrote = snprintf(buf, len, "z=%llu %s", zone->z_time,
1066*a93a1f58Sgm209912 		    zone->z_offset);
1067*a93a1f58Sgm209912 		len = len - wrote;
1068*a93a1f58Sgm209912 		buf = buf + wrote;
1069*a93a1f58Sgm209912 		zone = zone->z_next;
1070*a93a1f58Sgm209912 		while (zone != NULL) {
1071*a93a1f58Sgm209912 			wrote = snprintf(buf, len, " %llu %s", zone->z_time,
1072*a93a1f58Sgm209912 			    zone->z_offset);
1073*a93a1f58Sgm209912 			len = len - wrote;
1074*a93a1f58Sgm209912 			buf = buf + wrote;
1075*a93a1f58Sgm209912 			zone = zone->z_next;
1076*a93a1f58Sgm209912 		}
1077*a93a1f58Sgm209912 		wrote = snprintf(buf, len, "%s", COMMP_CRLF);
1078*a93a1f58Sgm209912 		len = len - wrote;
1079*a93a1f58Sgm209912 		buf = buf + wrote;
1080*a93a1f58Sgm209912 	}
1081*a93a1f58Sgm209912 	SDP_KEY_TO_STR(session->s_key);
1082*a93a1f58Sgm209912 	attr = session->s_attr;
1083*a93a1f58Sgm209912 	SDP_ATTR_TO_STR(attr);
1084*a93a1f58Sgm209912 	media = session->s_media;
1085*a93a1f58Sgm209912 	while (media != NULL) {
1086*a93a1f58Sgm209912 		if (media->m_portcount == 1) {
1087*a93a1f58Sgm209912 			wrote = snprintf(buf, len, "m=%s %d %s", media->m_name,
1088*a93a1f58Sgm209912 			    media->m_port, media->m_proto);
1089*a93a1f58Sgm209912 		} else {
1090*a93a1f58Sgm209912 			wrote = snprintf(buf, len, "m=%s %d/%d %s", media->
1091*a93a1f58Sgm209912 			    m_name, media->m_port, media->m_portcount, media->
1092*a93a1f58Sgm209912 			    m_proto);
1093*a93a1f58Sgm209912 		}
1094*a93a1f58Sgm209912 		len = len - wrote;
1095*a93a1f58Sgm209912 		buf = buf + wrote;
1096*a93a1f58Sgm209912 		list = media->m_format;
1097*a93a1f58Sgm209912 		while (list != NULL) {
1098*a93a1f58Sgm209912 			wrote = snprintf(buf, len, " %s", (char *)list->value);
1099*a93a1f58Sgm209912 			len = len - wrote;
1100*a93a1f58Sgm209912 			buf = buf + wrote;
1101*a93a1f58Sgm209912 			list = list->next;
1102*a93a1f58Sgm209912 		}
1103*a93a1f58Sgm209912 		wrote = snprintf(buf, len, "%s", COMMP_CRLF);
1104*a93a1f58Sgm209912 		len = len - wrote;
1105*a93a1f58Sgm209912 		buf = buf + wrote;
1106*a93a1f58Sgm209912 		SDP_INFORMATION_TO_STR(media->m_info);
1107*a93a1f58Sgm209912 		conn = media->m_conn;
1108*a93a1f58Sgm209912 		SDP_CONNECTION_TO_STR(conn);
1109*a93a1f58Sgm209912 		bw = media->m_bw;
1110*a93a1f58Sgm209912 		SDP_BANDWIDTH_TO_STR(bw);
1111*a93a1f58Sgm209912 		SDP_KEY_TO_STR(media->m_key);
1112*a93a1f58Sgm209912 		attr = media->m_attr;
1113*a93a1f58Sgm209912 		SDP_ATTR_TO_STR(attr);
1114*a93a1f58Sgm209912 		media = media->m_next;
1115*a93a1f58Sgm209912 	}
1116*a93a1f58Sgm209912 	assert(len >= 1);
1117*a93a1f58Sgm209912 	*buf = '\0';
1118*a93a1f58Sgm209912 	return (ret);
1119*a93a1f58Sgm209912 }
1120*a93a1f58Sgm209912 
1121*a93a1f58Sgm209912 /*
1122*a93a1f58Sgm209912  * Given a session structure and the field ('v', 'o', 's', et al), this API
1123*a93a1f58Sgm209912  * deletes the corresponding structure element. It frees the memory and sets the
1124*a93a1f58Sgm209912  * pointer to NULL
1125*a93a1f58Sgm209912  */
1126*a93a1f58Sgm209912 int
1127*a93a1f58Sgm209912 sdp_delete_all_field(sdp_session_t *session, const char field)
1128*a93a1f58Sgm209912 {
1129*a93a1f58Sgm209912 	if (session == NULL)
1130*a93a1f58Sgm209912 		return (EINVAL);
1131*a93a1f58Sgm209912 	switch (field) {
1132*a93a1f58Sgm209912 		case SDP_ORIGIN_FIELD:
1133*a93a1f58Sgm209912 			sdp_free_origin(session->s_origin);
1134*a93a1f58Sgm209912 			session->s_origin = NULL;
1135*a93a1f58Sgm209912 			break;
1136*a93a1f58Sgm209912 		case SDP_NAME_FIELD:
1137*a93a1f58Sgm209912 			free(session->s_name);
1138*a93a1f58Sgm209912 			session->s_name = NULL;
1139*a93a1f58Sgm209912 			break;
1140*a93a1f58Sgm209912 		case SDP_INFO_FIELD:
1141*a93a1f58Sgm209912 			free(session->s_info);
1142*a93a1f58Sgm209912 			session->s_info = NULL;
1143*a93a1f58Sgm209912 			break;
1144*a93a1f58Sgm209912 		case SDP_URI_FIELD:
1145*a93a1f58Sgm209912 			free(session->s_uri);
1146*a93a1f58Sgm209912 			session->s_uri = NULL;
1147*a93a1f58Sgm209912 			break;
1148*a93a1f58Sgm209912 		case SDP_EMAIL_FIELD:
1149*a93a1f58Sgm209912 			sdp_free_list(session->s_email);
1150*a93a1f58Sgm209912 			session->s_email = NULL;
1151*a93a1f58Sgm209912 			break;
1152*a93a1f58Sgm209912 		case SDP_PHONE_FIELD:
1153*a93a1f58Sgm209912 			sdp_free_list(session->s_phone);
1154*a93a1f58Sgm209912 			session->s_phone = NULL;
1155*a93a1f58Sgm209912 			break;
1156*a93a1f58Sgm209912 		case SDP_CONNECTION_FIELD:
1157*a93a1f58Sgm209912 			sdp_free_connection(session->s_conn);
1158*a93a1f58Sgm209912 			session->s_conn = NULL;
1159*a93a1f58Sgm209912 			break;
1160*a93a1f58Sgm209912 		case SDP_BANDWIDTH_FIELD:
1161*a93a1f58Sgm209912 			sdp_free_bandwidth(session->s_bw);
1162*a93a1f58Sgm209912 			session->s_bw = NULL;
1163*a93a1f58Sgm209912 			break;
1164*a93a1f58Sgm209912 		case SDP_TIME_FIELD:
1165*a93a1f58Sgm209912 			sdp_free_time(session->s_time);
1166*a93a1f58Sgm209912 			session->s_time = NULL;
1167*a93a1f58Sgm209912 			break;
1168*a93a1f58Sgm209912 		case SDP_ZONE_FIELD:
1169*a93a1f58Sgm209912 			sdp_free_zone(session->s_zone);
1170*a93a1f58Sgm209912 			session->s_zone = NULL;
1171*a93a1f58Sgm209912 			break;
1172*a93a1f58Sgm209912 		case SDP_KEY_FIELD:
1173*a93a1f58Sgm209912 			sdp_free_key(session->s_key);
1174*a93a1f58Sgm209912 			session->s_key = NULL;
1175*a93a1f58Sgm209912 			break;
1176*a93a1f58Sgm209912 		case SDP_ATTRIBUTE_FIELD:
1177*a93a1f58Sgm209912 			sdp_free_attribute(session->s_attr);
1178*a93a1f58Sgm209912 			session->s_attr = NULL;
1179*a93a1f58Sgm209912 			break;
1180*a93a1f58Sgm209912 		case SDP_MEDIA_FIELD:
1181*a93a1f58Sgm209912 			sdp_free_media(session->s_media);
1182*a93a1f58Sgm209912 			session->s_media = NULL;
1183*a93a1f58Sgm209912 			break;
1184*a93a1f58Sgm209912 		default:
1185*a93a1f58Sgm209912 			return (EINVAL);
1186*a93a1f58Sgm209912 	}
1187*a93a1f58Sgm209912 	return (0);
1188*a93a1f58Sgm209912 }
1189*a93a1f58Sgm209912 
1190*a93a1f58Sgm209912 /*
1191*a93a1f58Sgm209912  * Given a media structure and the field ('i', 'b', 'c', et al), this API
1192*a93a1f58Sgm209912  * deletes the corresponding structure element. It frees the memory and sets
1193*a93a1f58Sgm209912  * the pointer to NULL.
1194*a93a1f58Sgm209912  */
1195*a93a1f58Sgm209912 int
1196*a93a1f58Sgm209912 sdp_delete_all_media_field(sdp_media_t *media, const char field)
1197*a93a1f58Sgm209912 {
1198*a93a1f58Sgm209912 	if (media == NULL)
1199*a93a1f58Sgm209912 		return (EINVAL);
1200*a93a1f58Sgm209912 	switch (field) {
1201*a93a1f58Sgm209912 		case SDP_INFO_FIELD:
1202*a93a1f58Sgm209912 			free(media->m_info);
1203*a93a1f58Sgm209912 			media->m_info = NULL;
1204*a93a1f58Sgm209912 			break;
1205*a93a1f58Sgm209912 		case SDP_CONNECTION_FIELD:
1206*a93a1f58Sgm209912 			sdp_free_connection(media->m_conn);
1207*a93a1f58Sgm209912 			media->m_conn = NULL;
1208*a93a1f58Sgm209912 			break;
1209*a93a1f58Sgm209912 		case SDP_BANDWIDTH_FIELD:
1210*a93a1f58Sgm209912 			sdp_free_bandwidth(media->m_bw);
1211*a93a1f58Sgm209912 			media->m_bw = NULL;
1212*a93a1f58Sgm209912 			break;
1213*a93a1f58Sgm209912 		case SDP_KEY_FIELD:
1214*a93a1f58Sgm209912 			sdp_free_key(media->m_key);
1215*a93a1f58Sgm209912 			media->m_key = NULL;
1216*a93a1f58Sgm209912 			break;
1217*a93a1f58Sgm209912 		case SDP_ATTRIBUTE_FIELD:
1218*a93a1f58Sgm209912 			sdp_free_attribute(media->m_attr);
1219*a93a1f58Sgm209912 			media->m_attr = NULL;
1220*a93a1f58Sgm209912 			break;
1221*a93a1f58Sgm209912 		default:
1222*a93a1f58Sgm209912 			return (EINVAL);
1223*a93a1f58Sgm209912 	}
1224*a93a1f58Sgm209912 	return (0);
1225*a93a1f58Sgm209912 }
1226*a93a1f58Sgm209912 
1227*a93a1f58Sgm209912 /*
1228*a93a1f58Sgm209912  * Given a media list and the media, this API deletes that media from the
1229*a93a1f58Sgm209912  * list. It frees the memory corresponding to that media.
1230*a93a1f58Sgm209912  */
1231*a93a1f58Sgm209912 int
1232*a93a1f58Sgm209912 sdp_delete_media(sdp_media_t **l_media, sdp_media_t *media)
1233*a93a1f58Sgm209912 {
1234*a93a1f58Sgm209912 	sdp_media_t		*cur;
1235*a93a1f58Sgm209912 	sdp_media_t		*prev;
1236*a93a1f58Sgm209912 
1237*a93a1f58Sgm209912 	if (l_media == NULL || *l_media == NULL || media == NULL)
1238*a93a1f58Sgm209912 		return (EINVAL);
1239*a93a1f58Sgm209912 	cur = *l_media;
1240*a93a1f58Sgm209912 	prev = NULL;
1241*a93a1f58Sgm209912 	while (cur != NULL && cur != media) {
1242*a93a1f58Sgm209912 		prev = cur;
1243*a93a1f58Sgm209912 		cur = cur->m_next;
1244*a93a1f58Sgm209912 	}
1245*a93a1f58Sgm209912 	if (cur == NULL)
1246*a93a1f58Sgm209912 		return (EINVAL);
1247*a93a1f58Sgm209912 	if (cur == *l_media)
1248*a93a1f58Sgm209912 		*l_media = cur->m_next;
1249*a93a1f58Sgm209912 	else
1250*a93a1f58Sgm209912 		prev->m_next = cur->m_next;
1251*a93a1f58Sgm209912 	cur->m_next = NULL;
1252*a93a1f58Sgm209912 	sdp_free_media(cur);
1253*a93a1f58Sgm209912 	return (0);
1254*a93a1f58Sgm209912 }
1255*a93a1f58Sgm209912 
1256*a93a1f58Sgm209912 /*
1257*a93a1f58Sgm209912  * Given an attribute list and an attribute, this API deletes that attribue
1258*a93a1f58Sgm209912  * from the list. It frees the memory corresponding to that attribute.
1259*a93a1f58Sgm209912  */
1260*a93a1f58Sgm209912 int
1261*a93a1f58Sgm209912 sdp_delete_attribute(sdp_attr_t **l_attr, sdp_attr_t *attr)
1262*a93a1f58Sgm209912 {
1263*a93a1f58Sgm209912 	sdp_attr_t		*cur;
1264*a93a1f58Sgm209912 	sdp_attr_t		*prev;
1265*a93a1f58Sgm209912 
1266*a93a1f58Sgm209912 	if (l_attr == NULL || *l_attr == NULL || attr == NULL)
1267*a93a1f58Sgm209912 		return (EINVAL);
1268*a93a1f58Sgm209912 	cur = *l_attr;
1269*a93a1f58Sgm209912 	prev = NULL;
1270*a93a1f58Sgm209912 	while (cur != NULL && cur != attr) {
1271*a93a1f58Sgm209912 		prev = cur;
1272*a93a1f58Sgm209912 		cur = cur->a_next;
1273*a93a1f58Sgm209912 	}
1274*a93a1f58Sgm209912 	if (cur == NULL)
1275*a93a1f58Sgm209912 		return (EINVAL);
1276*a93a1f58Sgm209912 	if (cur == *l_attr)
1277*a93a1f58Sgm209912 		*l_attr = cur->a_next;
1278*a93a1f58Sgm209912 	else
1279*a93a1f58Sgm209912 		prev->a_next = cur->a_next;
1280*a93a1f58Sgm209912 	cur->a_next = NULL;
1281*a93a1f58Sgm209912 	sdp_free_attribute(cur);
1282*a93a1f58Sgm209912 	return (0);
1283*a93a1f58Sgm209912 }
1284*a93a1f58Sgm209912 
1285*a93a1f58Sgm209912 /*
1286*a93a1f58Sgm209912  * Allocates a new sdp session structure and assigns a version number to it.
1287*a93a1f58Sgm209912  * Currently one version is defined and it is 1. This will be useful in future
1288*a93a1f58Sgm209912  * in the unlikely need to change the structure.
1289*a93a1f58Sgm209912  */
1290*a93a1f58Sgm209912 sdp_session_t *
1291*a93a1f58Sgm209912 sdp_new_session()
1292*a93a1f58Sgm209912 {
1293*a93a1f58Sgm209912 	sdp_session_t	*session = NULL;
1294*a93a1f58Sgm209912 
1295*a93a1f58Sgm209912 	session = calloc(1, sizeof (sdp_session_t));
1296*a93a1f58Sgm209912 	if (session != NULL)
1297*a93a1f58Sgm209912 		session->sdp_session_version = SDP_SESSION_VERSION_1;
1298*a93a1f58Sgm209912 	return (session);
1299*a93a1f58Sgm209912 }
1300