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