xref: /onnv-gate/usr/src/lib/libcommputil/common/sdp_parse.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  * Parses the SDP description as per the SDP grammar defined in Section 9 of
31*5306Sgm209912  * RFC 4566
32*5306Sgm209912  */
33*5306Sgm209912 
34*5306Sgm209912 #include <errno.h>
35*5306Sgm209912 #include <stdlib.h>
36*5306Sgm209912 #include <string.h>
37*5306Sgm209912 #include <ctype.h>
38*5306Sgm209912 #include <sdp.h>
39*5306Sgm209912 
40*5306Sgm209912 #include "sdp_parse.h"
41*5306Sgm209912 #include "commp_util.h"
42*5306Sgm209912 
43*5306Sgm209912 /*
44*5306Sgm209912  * proto-version-field (v=)
45*5306Sgm209912  * %x76 "=" 1*DIGIT CRLF
46*5306Sgm209912  */
47*5306Sgm209912 static void
sdp_parse_version(int * version,const char * begin,const char * end,uint_t * p_error)48*5306Sgm209912 sdp_parse_version(int *version, const char *begin, const char *end,
49*5306Sgm209912     uint_t *p_error)
50*5306Sgm209912 {
51*5306Sgm209912 	if (*begin++ != COMMP_EQUALS || commp_atoi(begin, end, version) != 0)
52*5306Sgm209912 		*p_error |= SDP_VERSION_ERROR;
53*5306Sgm209912 }
54*5306Sgm209912 
55*5306Sgm209912 /*
56*5306Sgm209912  * session-name-field (s=)
57*5306Sgm209912  * %x73 "=" text CRLF
58*5306Sgm209912  * text = byte-string
59*5306Sgm209912  * byte-string = 1*(%x01-09/%x0B-0C/%x0E-FF)
60*5306Sgm209912  *               ;any byte except NUL, CR, or LF
61*5306Sgm209912  */
62*5306Sgm209912 static void
sdp_parse_name(char ** name,const char * begin,const char * end,uint_t * p_error)63*5306Sgm209912 sdp_parse_name(char **name, const char *begin, const char *end,
64*5306Sgm209912     uint_t *p_error)
65*5306Sgm209912 {
66*5306Sgm209912 	int	len;
67*5306Sgm209912 
68*5306Sgm209912 	if (*begin++ != COMMP_EQUALS) {
69*5306Sgm209912 		*p_error |= SDP_NAME_ERROR;
70*5306Sgm209912 		return;
71*5306Sgm209912 	}
72*5306Sgm209912 	/* there can be only one name field */
73*5306Sgm209912 	if (*name != NULL)
74*5306Sgm209912 		return;
75*5306Sgm209912 	len = end - begin;
76*5306Sgm209912 	if (len < 1) {
77*5306Sgm209912 		*p_error |= SDP_NAME_ERROR;
78*5306Sgm209912 	} else {
79*5306Sgm209912 		COMMP_COPY_STR(*name, begin, len);
80*5306Sgm209912 		if (*name == NULL) {
81*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
82*5306Sgm209912 			return;
83*5306Sgm209912 		}
84*5306Sgm209912 	}
85*5306Sgm209912 }
86*5306Sgm209912 
87*5306Sgm209912 /*
88*5306Sgm209912  * information-field (i=)
89*5306Sgm209912  * [%x69 "=" text CRLF]
90*5306Sgm209912  * text = byte-string
91*5306Sgm209912  * byte-string = 1*(%x01-09/%x0B-0C/%x0E-FF)
92*5306Sgm209912  *			any byte except NUL, CR, or LF
93*5306Sgm209912  */
94*5306Sgm209912 static void
sdp_parse_info(char ** info,const char * begin,const char * end,uint_t * p_error)95*5306Sgm209912 sdp_parse_info(char **info, const char *begin, const char *end,
96*5306Sgm209912     uint_t *p_error)
97*5306Sgm209912 {
98*5306Sgm209912 	int 	len;
99*5306Sgm209912 
100*5306Sgm209912 	if (*begin++ != COMMP_EQUALS) {
101*5306Sgm209912 		*p_error |= SDP_INFO_ERROR;
102*5306Sgm209912 		return;
103*5306Sgm209912 	}
104*5306Sgm209912 	/* There can be only one info field */
105*5306Sgm209912 	if (*info != NULL)
106*5306Sgm209912 		return;
107*5306Sgm209912 	len = end - begin;
108*5306Sgm209912 	if (len < 1) {
109*5306Sgm209912 		*p_error |= SDP_INFO_ERROR;
110*5306Sgm209912 	} else {
111*5306Sgm209912 		COMMP_COPY_STR(*info, begin, len);
112*5306Sgm209912 		if (*info == NULL) {
113*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
114*5306Sgm209912 			return;
115*5306Sgm209912 		}
116*5306Sgm209912 	}
117*5306Sgm209912 }
118*5306Sgm209912 
119*5306Sgm209912 /*
120*5306Sgm209912  * uri-field (u=)
121*5306Sgm209912  * [%x75 "=" uri CRLF]
122*5306Sgm209912  * anything between "=" and "CRLF" is considered to be URI.
123*5306Sgm209912  */
124*5306Sgm209912 static void
sdp_parse_uri(char ** uri,const char * begin,const char * end,uint_t * p_error)125*5306Sgm209912 sdp_parse_uri(char **uri, const char *begin, const char *end, uint_t *p_error)
126*5306Sgm209912 {
127*5306Sgm209912 	int 	len;
128*5306Sgm209912 
129*5306Sgm209912 	if (*begin++ != COMMP_EQUALS) {
130*5306Sgm209912 		*p_error |= SDP_URI_ERROR;
131*5306Sgm209912 		return;
132*5306Sgm209912 	}
133*5306Sgm209912 	/* There can be only one uri field */
134*5306Sgm209912 	if (*uri != NULL)
135*5306Sgm209912 		return;
136*5306Sgm209912 	len = end - begin;
137*5306Sgm209912 	if (len < 1 || isspace(*begin) || isspace (*(end - 1))) {
138*5306Sgm209912 		*p_error |= SDP_URI_ERROR;
139*5306Sgm209912 	} else {
140*5306Sgm209912 		COMMP_COPY_STR(*uri, begin, len);
141*5306Sgm209912 		if (*uri == NULL) {
142*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
143*5306Sgm209912 			return;
144*5306Sgm209912 		}
145*5306Sgm209912 	}
146*5306Sgm209912 }
147*5306Sgm209912 
148*5306Sgm209912 /*
149*5306Sgm209912  * phone-fields (p=)
150*5306Sgm209912  * *(%x70 "=" phone-number CRLF)
151*5306Sgm209912  * anything between "=" and "CRLF" is considered to be phone-number
152*5306Sgm209912  */
153*5306Sgm209912 static void
sdp_parse_phone(sdp_list_t ** phone,const char * begin,const char * end,uint_t * p_error)154*5306Sgm209912 sdp_parse_phone(sdp_list_t **phone, const char *begin, const char *end,
155*5306Sgm209912     uint_t *p_error)
156*5306Sgm209912 {
157*5306Sgm209912 	int 		len;
158*5306Sgm209912 	sdp_list_t	*new_phone = NULL;
159*5306Sgm209912 	sdp_list_t	*tmp = NULL;
160*5306Sgm209912 
161*5306Sgm209912 	if (*begin++ != COMMP_EQUALS) {
162*5306Sgm209912 		*p_error |= SDP_PHONE_ERROR;
163*5306Sgm209912 		return;
164*5306Sgm209912 	}
165*5306Sgm209912 	len = end - begin;
166*5306Sgm209912 	if (len < 1 || isspace(*begin) || isspace(*(end - 1))) {
167*5306Sgm209912 		*p_error |= SDP_PHONE_ERROR;
168*5306Sgm209912 	} else {
169*5306Sgm209912 		new_phone = calloc(1, sizeof (sdp_list_t));
170*5306Sgm209912 		if (new_phone == NULL) {
171*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
172*5306Sgm209912 			return;
173*5306Sgm209912 		}
174*5306Sgm209912 		COMMP_COPY_STR(new_phone->value, begin, len);
175*5306Sgm209912 		if (new_phone->value == NULL) {
176*5306Sgm209912 			free(new_phone);
177*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
178*5306Sgm209912 			return;
179*5306Sgm209912 		}
180*5306Sgm209912 		if (*phone == NULL) {
181*5306Sgm209912 			*phone = new_phone;
182*5306Sgm209912 		} else {
183*5306Sgm209912 			tmp = *phone;
184*5306Sgm209912 			while (tmp->next != NULL)
185*5306Sgm209912 				tmp = tmp->next;
186*5306Sgm209912 			tmp->next = new_phone;
187*5306Sgm209912 		}
188*5306Sgm209912 	}
189*5306Sgm209912 }
190*5306Sgm209912 
191*5306Sgm209912 /*
192*5306Sgm209912  * email-fields (e=)
193*5306Sgm209912  * *(%x65 "=" email-address CRLF)
194*5306Sgm209912  * anything between "=" and "CRLF" is considered to be email-address
195*5306Sgm209912  */
196*5306Sgm209912 static void
sdp_parse_email(sdp_list_t ** email,const char * begin,const char * end,uint_t * p_error)197*5306Sgm209912 sdp_parse_email(sdp_list_t **email, const char *begin, const char *end,
198*5306Sgm209912     uint_t *p_error)
199*5306Sgm209912 {
200*5306Sgm209912 	int 		len;
201*5306Sgm209912 	sdp_list_t	*new_email = NULL;
202*5306Sgm209912 	sdp_list_t	*tmp = NULL;
203*5306Sgm209912 
204*5306Sgm209912 	if (*begin++ != COMMP_EQUALS) {
205*5306Sgm209912 		*p_error |= SDP_EMAIL_ERROR;
206*5306Sgm209912 		return;
207*5306Sgm209912 	}
208*5306Sgm209912 	len = end - begin;
209*5306Sgm209912 	if (len < 1 || isspace(*begin) || isspace(*(end - 1))) {
210*5306Sgm209912 		*p_error |= SDP_EMAIL_ERROR;
211*5306Sgm209912 	} else {
212*5306Sgm209912 		new_email = calloc(1, sizeof (sdp_list_t));
213*5306Sgm209912 		if (new_email == NULL) {
214*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
215*5306Sgm209912 			return;
216*5306Sgm209912 		}
217*5306Sgm209912 		COMMP_COPY_STR(new_email->value, begin, len);
218*5306Sgm209912 		if (new_email->value == NULL) {
219*5306Sgm209912 			free(new_email);
220*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
221*5306Sgm209912 			return;
222*5306Sgm209912 		}
223*5306Sgm209912 		if (*email == NULL) {
224*5306Sgm209912 			*email = new_email;
225*5306Sgm209912 		} else {
226*5306Sgm209912 			tmp = *email;
227*5306Sgm209912 			while (tmp->next != NULL)
228*5306Sgm209912 				tmp = tmp->next;
229*5306Sgm209912 			tmp->next = new_email;
230*5306Sgm209912 		}
231*5306Sgm209912 	}
232*5306Sgm209912 }
233*5306Sgm209912 
234*5306Sgm209912 /*
235*5306Sgm209912  * origin-field (o=)
236*5306Sgm209912  * %x6f "=" username SP sess-id SP sess-version SP nettype SP addrtype SP
237*5306Sgm209912  * unicast-address CRLF
238*5306Sgm209912  *
239*5306Sgm209912  * username = non-ws-string
240*5306Sgm209912  * sess-id = 1*DIGIT
241*5306Sgm209912  * sess-version = 1*DIGIT
242*5306Sgm209912  * nettype = token
243*5306Sgm209912  * addrtype = token
244*5306Sgm209912  * token = 1*(token-char)
245*5306Sgm209912  * token-char = %x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39 / %x41-5A / %x5E-7E
246*5306Sgm209912  * i.e. no space in token-char
247*5306Sgm209912  */
248*5306Sgm209912 static void
sdp_parse_origin(sdp_origin_t ** origin,const char * begin,const char * end,uint_t * p_error)249*5306Sgm209912 sdp_parse_origin(sdp_origin_t **origin, const char *begin, const char *end,
250*5306Sgm209912     uint_t *p_error)
251*5306Sgm209912 {
252*5306Sgm209912 	const char	*current = NULL;
253*5306Sgm209912 	sdp_origin_t	*new_origin = NULL;
254*5306Sgm209912 
255*5306Sgm209912 	if (*begin++ != COMMP_EQUALS) {
256*5306Sgm209912 		*p_error |= SDP_ORIGIN_ERROR;
257*5306Sgm209912 		return;
258*5306Sgm209912 	}
259*5306Sgm209912 	/* There can be only one origin field */
260*5306Sgm209912 	if (*origin != NULL)
261*5306Sgm209912 		return;
262*5306Sgm209912 	new_origin = calloc(1, sizeof (sdp_origin_t));
263*5306Sgm209912 	if (new_origin == NULL) {
264*5306Sgm209912 		*p_error |= SDP_MEMORY_ERROR;
265*5306Sgm209912 		return;
266*5306Sgm209912 	}
267*5306Sgm209912 	/* Get username */
268*5306Sgm209912 	current = begin;
269*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_SP, B_FALSE) != 0) {
270*5306Sgm209912 		goto err_ret;
271*5306Sgm209912 	} else {
272*5306Sgm209912 		COMMP_COPY_STR(new_origin->o_username, begin, current - begin);
273*5306Sgm209912 		if (new_origin->o_username == NULL) {
274*5306Sgm209912 			sdp_free_origin(new_origin);
275*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
276*5306Sgm209912 			return;
277*5306Sgm209912 		}
278*5306Sgm209912 	}
279*5306Sgm209912 	/* Get Session-ID */
280*5306Sgm209912 	begin = ++current;
281*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_SP, B_FALSE) != 0)
282*5306Sgm209912 		goto err_ret;
283*5306Sgm209912 	if (commp_strtoull(begin, current, &new_origin->o_id) != 0)
284*5306Sgm209912 		goto err_ret;
285*5306Sgm209912 	/* Get Version */
286*5306Sgm209912 	begin = ++current;
287*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_SP, B_FALSE) != 0)
288*5306Sgm209912 		goto err_ret;
289*5306Sgm209912 	if (commp_strtoull(begin, current, &new_origin->o_version) != 0)
290*5306Sgm209912 		goto err_ret;
291*5306Sgm209912 	/* Get nettype */
292*5306Sgm209912 	begin = ++current;
293*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_SP, B_FALSE) != 0) {
294*5306Sgm209912 		goto err_ret;
295*5306Sgm209912 	} else {
296*5306Sgm209912 		COMMP_COPY_STR(new_origin->o_nettype, begin, current - begin);
297*5306Sgm209912 		if (new_origin->o_nettype == NULL) {
298*5306Sgm209912 			sdp_free_origin(new_origin);
299*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
300*5306Sgm209912 			return;
301*5306Sgm209912 		}
302*5306Sgm209912 	}
303*5306Sgm209912 	/* Get addrtype */
304*5306Sgm209912 	begin = ++current;
305*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_SP, B_FALSE) != 0) {
306*5306Sgm209912 		goto err_ret;
307*5306Sgm209912 	} else {
308*5306Sgm209912 		COMMP_COPY_STR(new_origin->o_addrtype, begin, current - begin);
309*5306Sgm209912 		if (new_origin->o_addrtype == NULL) {
310*5306Sgm209912 			sdp_free_origin(new_origin);
311*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
312*5306Sgm209912 			return;
313*5306Sgm209912 		}
314*5306Sgm209912 	}
315*5306Sgm209912 	/* Get address. Its the last sub-field */
316*5306Sgm209912 	begin = ++current;
317*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_SP, B_TRUE) != 0)
318*5306Sgm209912 		goto err_ret;
319*5306Sgm209912 	COMMP_COPY_STR(new_origin->o_address, begin, current - begin);
320*5306Sgm209912 	if (new_origin->o_address == NULL) {
321*5306Sgm209912 		sdp_free_origin(new_origin);
322*5306Sgm209912 		*p_error |= SDP_MEMORY_ERROR;
323*5306Sgm209912 		return;
324*5306Sgm209912 	}
325*5306Sgm209912 	*origin = new_origin;
326*5306Sgm209912 	return;
327*5306Sgm209912 err_ret:
328*5306Sgm209912 	*p_error |= SDP_ORIGIN_ERROR;
329*5306Sgm209912 	sdp_free_origin(new_origin);
330*5306Sgm209912 }
331*5306Sgm209912 
332*5306Sgm209912 /*
333*5306Sgm209912  * time-fields (t=)
334*5306Sgm209912  * 1*( %x74 "=" start-time SP stop-time CRLF)
335*5306Sgm209912  * start-time = time / "0"
336*5306Sgm209912  * stop-time = time / "0"
337*5306Sgm209912  * time = POS-DIGIT 9*DIGIT
338*5306Sgm209912  * POS-DIGIT = %x31-39 ; 1 - 9
339*5306Sgm209912  */
340*5306Sgm209912 static sdp_time_t *
sdp_parse_time(sdp_time_t ** time,const char * begin,const char * end,uint_t * p_error)341*5306Sgm209912 sdp_parse_time(sdp_time_t **time, const char *begin, const char *end,
342*5306Sgm209912     uint_t *p_error)
343*5306Sgm209912 {
344*5306Sgm209912 	const char	*current;
345*5306Sgm209912 	sdp_time_t	*new_time;
346*5306Sgm209912 	sdp_time_t	*tmp;
347*5306Sgm209912 
348*5306Sgm209912 	if (*begin++ != COMMP_EQUALS) {
349*5306Sgm209912 		*p_error |= SDP_TIME_ERROR;
350*5306Sgm209912 		return (NULL);
351*5306Sgm209912 	}
352*5306Sgm209912 	new_time = calloc(1, sizeof (sdp_time_t));
353*5306Sgm209912 	if (new_time == NULL) {
354*5306Sgm209912 		*p_error |= SDP_MEMORY_ERROR;
355*5306Sgm209912 		return (NULL);
356*5306Sgm209912 	}
357*5306Sgm209912 	/* Get start-time */
358*5306Sgm209912 	current = begin;
359*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_SP, B_FALSE) != 0)
360*5306Sgm209912 		goto err_ret;
361*5306Sgm209912 	if (commp_strtoull(begin, current, &new_time->t_start) != 0)
362*5306Sgm209912 		goto err_ret;
363*5306Sgm209912 	/* Get stop-time */
364*5306Sgm209912 	begin = ++current;
365*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_SP, B_TRUE) != 0)
366*5306Sgm209912 		goto err_ret;
367*5306Sgm209912 	if (commp_strtoull(begin, current, &new_time->t_stop) != 0)
368*5306Sgm209912 		goto err_ret;
369*5306Sgm209912 	/* Now assign time to session structure */
370*5306Sgm209912 	if (*time == NULL) {
371*5306Sgm209912 		*time = new_time;
372*5306Sgm209912 	} else {
373*5306Sgm209912 		tmp = *time;
374*5306Sgm209912 		while (tmp->t_next != NULL)
375*5306Sgm209912 			tmp = tmp->t_next;
376*5306Sgm209912 		tmp->t_next = new_time;
377*5306Sgm209912 	}
378*5306Sgm209912 	return (new_time);
379*5306Sgm209912 err_ret:
380*5306Sgm209912 	*p_error |= SDP_TIME_ERROR;
381*5306Sgm209912 	sdp_free_time(new_time);
382*5306Sgm209912 	return (NULL);
383*5306Sgm209912 }
384*5306Sgm209912 
385*5306Sgm209912 /*
386*5306Sgm209912  * connection-field (c=)
387*5306Sgm209912  * [%x63 "=" nettype SP addrtype SP connection-address CRLF]
388*5306Sgm209912  * nettype = token
389*5306Sgm209912  * addrtype = token
390*5306Sgm209912  * connection-address =  multicast-address / unicast-address
391*5306Sgm209912  * here, connection-address is parsed as a string.
392*5306Sgm209912  */
393*5306Sgm209912 static void
sdp_parse_connection(sdp_conn_t ** conn,const char * begin,const char * end,uint_t * p_error)394*5306Sgm209912 sdp_parse_connection(sdp_conn_t **conn, const char *begin, const char *end,
395*5306Sgm209912     uint_t *p_error)
396*5306Sgm209912 {
397*5306Sgm209912 	const char	*current;
398*5306Sgm209912 	const char	*t_begin;
399*5306Sgm209912 	const char	*t_current;
400*5306Sgm209912 	sdp_conn_t	*new_conn;
401*5306Sgm209912 	sdp_conn_t	*tmp;
402*5306Sgm209912 	boolean_t	is_IP4 = B_FALSE;
403*5306Sgm209912 	boolean_t	is_IP6 = B_FALSE;
404*5306Sgm209912 
405*5306Sgm209912 	if (*begin++ != COMMP_EQUALS) {
406*5306Sgm209912 		*p_error |= SDP_CONNECTION_ERROR;
407*5306Sgm209912 		return;
408*5306Sgm209912 	}
409*5306Sgm209912 	new_conn = calloc(1, sizeof (sdp_conn_t));
410*5306Sgm209912 	if (new_conn == NULL) {
411*5306Sgm209912 		*p_error |= SDP_MEMORY_ERROR;
412*5306Sgm209912 		return;
413*5306Sgm209912 	}
414*5306Sgm209912 	/* Get NetworkType */
415*5306Sgm209912 	current = begin;
416*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_SP, B_FALSE) != 0) {
417*5306Sgm209912 		goto err_ret;
418*5306Sgm209912 	} else {
419*5306Sgm209912 		COMMP_COPY_STR(new_conn->c_nettype, begin, current - begin);
420*5306Sgm209912 		if (new_conn->c_nettype == NULL) {
421*5306Sgm209912 			sdp_free_connection(new_conn);
422*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
423*5306Sgm209912 			return;
424*5306Sgm209912 		}
425*5306Sgm209912 	}
426*5306Sgm209912 	/* Get AddressType */
427*5306Sgm209912 	begin = ++current;
428*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_SP, B_FALSE) != 0) {
429*5306Sgm209912 		goto err_ret;
430*5306Sgm209912 	} else {
431*5306Sgm209912 		COMMP_COPY_STR(new_conn->c_addrtype, begin, current - begin);
432*5306Sgm209912 		if (new_conn->c_addrtype == NULL) {
433*5306Sgm209912 			sdp_free_connection(new_conn);
434*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
435*5306Sgm209912 			return;
436*5306Sgm209912 		}
437*5306Sgm209912 	}
438*5306Sgm209912 	if ((strlen(COMMP_ADDRTYPE_IP4) == strlen(new_conn->c_addrtype)) &&
439*5306Sgm209912 	    (strncasecmp(new_conn->c_addrtype, COMMP_ADDRTYPE_IP4,
440*5306Sgm209912 	    strlen(COMMP_ADDRTYPE_IP4)) == 0)) {
441*5306Sgm209912 		is_IP4 = B_TRUE;
442*5306Sgm209912 	} else if ((strlen(COMMP_ADDRTYPE_IP6) == strlen(new_conn->
443*5306Sgm209912 	    c_addrtype)) && (strncasecmp(new_conn->c_addrtype,
444*5306Sgm209912 	    COMMP_ADDRTYPE_IP6, strlen(COMMP_ADDRTYPE_IP6)) == 0)) {
445*5306Sgm209912 		is_IP6 = B_TRUE;
446*5306Sgm209912 	}
447*5306Sgm209912 	/* Get Address. Parsing depends if its IP4,IP6 or something else */
448*5306Sgm209912 	begin = ++current;
449*5306Sgm209912 	if (!is_IP4 && !is_IP6) {
450*5306Sgm209912 		if (commp_find_token(&begin, &current, end, COMMP_SP,
451*5306Sgm209912 		    B_TRUE) != 0) {
452*5306Sgm209912 			goto err_ret;
453*5306Sgm209912 		}
454*5306Sgm209912 	} else {
455*5306Sgm209912 		if (commp_find_token(&begin, &current, end, COMMP_SLASH,
456*5306Sgm209912 		    B_FALSE) != 0) {
457*5306Sgm209912 			goto err_ret;
458*5306Sgm209912 		}
459*5306Sgm209912 		if (current != end) {
460*5306Sgm209912 			/* SLASH is present. Needs further parsing */
461*5306Sgm209912 			t_current = current;
462*5306Sgm209912 			t_begin = ++t_current;
463*5306Sgm209912 			if (commp_find_token(&t_begin, &t_current, end,
464*5306Sgm209912 			    COMMP_SLASH, B_FALSE) != 0) {
465*5306Sgm209912 				goto err_ret;
466*5306Sgm209912 			}
467*5306Sgm209912 			if (t_current != end) {
468*5306Sgm209912 				/*
469*5306Sgm209912 				 * Another SLASH present. If is_IP4 true then
470*5306Sgm209912 				 * this is Address count. If is_IP6 true then
471*5306Sgm209912 				 * incorrect field as per RFC.
472*5306Sgm209912 				 */
473*5306Sgm209912 				if (is_IP6) {
474*5306Sgm209912 					goto err_ret;
475*5306Sgm209912 				} else {
476*5306Sgm209912 					if (commp_atoi((t_current + 1), end,
477*5306Sgm209912 					    &new_conn->c_addrcount) != 0) {
478*5306Sgm209912 						goto err_ret;
479*5306Sgm209912 					}
480*5306Sgm209912 				}
481*5306Sgm209912 			}
482*5306Sgm209912 			if (is_IP6) {
483*5306Sgm209912 				if (commp_atoi((current + 1), t_current,
484*5306Sgm209912 				    &new_conn->c_addrcount) != 0) {
485*5306Sgm209912 					goto err_ret;
486*5306Sgm209912 				}
487*5306Sgm209912 			} else {
488*5306Sgm209912 				if (commp_strtoub((current + 1), t_current,
489*5306Sgm209912 				    &new_conn->c_ttl) != 0) {
490*5306Sgm209912 					goto err_ret;
491*5306Sgm209912 				}
492*5306Sgm209912 				if (new_conn->c_addrcount == 0)
493*5306Sgm209912 					new_conn->c_addrcount = 1;
494*5306Sgm209912 			}
495*5306Sgm209912 		}
496*5306Sgm209912 	}
497*5306Sgm209912 	COMMP_COPY_STR(new_conn->c_address, begin, current - begin);
498*5306Sgm209912 	if (new_conn->c_address == NULL) {
499*5306Sgm209912 		sdp_free_connection(new_conn);
500*5306Sgm209912 		*p_error |= SDP_MEMORY_ERROR;
501*5306Sgm209912 		return;
502*5306Sgm209912 	}
503*5306Sgm209912 	if (*conn == NULL) {
504*5306Sgm209912 		*conn = new_conn;
505*5306Sgm209912 	} else {
506*5306Sgm209912 		tmp = *conn;
507*5306Sgm209912 		while (tmp->c_next != NULL)
508*5306Sgm209912 			tmp = tmp->c_next;
509*5306Sgm209912 		tmp->c_next = new_conn;
510*5306Sgm209912 	}
511*5306Sgm209912 	return;
512*5306Sgm209912 err_ret:
513*5306Sgm209912 	*p_error |= SDP_CONNECTION_ERROR;
514*5306Sgm209912 	sdp_free_connection(new_conn);
515*5306Sgm209912 }
516*5306Sgm209912 
517*5306Sgm209912 /*
518*5306Sgm209912  * bandwidth-fields (b=)
519*5306Sgm209912  * *(%x62 "=" bwtype ":" bandwidth CRLF)
520*5306Sgm209912  * bwtype = token
521*5306Sgm209912  * bandwidth = 1*DIGIT
522*5306Sgm209912  */
523*5306Sgm209912 static void
sdp_parse_bandwidth(sdp_bandwidth_t ** bw,const char * begin,const char * end,uint_t * p_error)524*5306Sgm209912 sdp_parse_bandwidth(sdp_bandwidth_t **bw, const char *begin, const char *end,
525*5306Sgm209912     uint_t *p_error)
526*5306Sgm209912 {
527*5306Sgm209912 	const char		*current;
528*5306Sgm209912 	sdp_bandwidth_t		*new_bw = NULL;
529*5306Sgm209912 	sdp_bandwidth_t		*tmp = NULL;
530*5306Sgm209912 
531*5306Sgm209912 	if (*begin++ != COMMP_EQUALS) {
532*5306Sgm209912 		*p_error |= SDP_BANDWIDTH_ERROR;
533*5306Sgm209912 		return;
534*5306Sgm209912 	}
535*5306Sgm209912 	new_bw = calloc(1, sizeof (sdp_bandwidth_t));
536*5306Sgm209912 	if (new_bw == NULL) {
537*5306Sgm209912 		*p_error |= SDP_MEMORY_ERROR;
538*5306Sgm209912 		return;
539*5306Sgm209912 	}
540*5306Sgm209912 	current = begin;
541*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_COLON,
542*5306Sgm209912 	    B_FALSE) != 0) {
543*5306Sgm209912 		goto err_ret;
544*5306Sgm209912 	} else {
545*5306Sgm209912 		COMMP_COPY_STR(new_bw->b_type, begin, current - begin);
546*5306Sgm209912 		if (new_bw->b_type == NULL) {
547*5306Sgm209912 			sdp_free_bandwidth(new_bw);
548*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
549*5306Sgm209912 			return;
550*5306Sgm209912 		}
551*5306Sgm209912 	}
552*5306Sgm209912 	if (current == end)
553*5306Sgm209912 		goto err_ret;
554*5306Sgm209912 	begin = ++current;
555*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_SP, B_TRUE) != 0)
556*5306Sgm209912 		goto err_ret;
557*5306Sgm209912 	if (commp_strtoull(begin, current, &new_bw->b_value) != 0)
558*5306Sgm209912 		goto err_ret;
559*5306Sgm209912 	if (*bw == NULL) {
560*5306Sgm209912 		*bw = new_bw;
561*5306Sgm209912 	} else {
562*5306Sgm209912 		tmp = *bw;
563*5306Sgm209912 		while (tmp->b_next != NULL)
564*5306Sgm209912 			tmp = tmp->b_next;
565*5306Sgm209912 		tmp->b_next = new_bw;
566*5306Sgm209912 	}
567*5306Sgm209912 	return;
568*5306Sgm209912 err_ret:
569*5306Sgm209912 	*p_error |= SDP_BANDWIDTH_ERROR;
570*5306Sgm209912 	sdp_free_bandwidth(new_bw);
571*5306Sgm209912 }
572*5306Sgm209912 
573*5306Sgm209912 /*
574*5306Sgm209912  * repeat-fields (r=)
575*5306Sgm209912  * Not stand-alone. One or more repeat field appear after time field.
576*5306Sgm209912  * %x72 "=" repeat-interval SP typed-time 1*(SP typed-time)
577*5306Sgm209912  * repeat-interval = POS-DIGIT *DIGIT [fixed-len-time-unit]
578*5306Sgm209912  * typed-time = 1*DIGIT [fixed-len-time-unit]
579*5306Sgm209912  * fixed-len-time-unit = %x64 / %x68 / %x6d / %x73
580*5306Sgm209912  */
581*5306Sgm209912 static void
sdp_parse_repeat(sdp_time_t * time,const char * begin,const char * end,uint_t * p_error)582*5306Sgm209912 sdp_parse_repeat(sdp_time_t *time, const char *begin, const char *end,
583*5306Sgm209912     uint_t *p_error)
584*5306Sgm209912 {
585*5306Sgm209912 	const char	*current;
586*5306Sgm209912 	sdp_repeat_t	*repeat;
587*5306Sgm209912 	sdp_repeat_t	*new_repeat;
588*5306Sgm209912 	int		ret;
589*5306Sgm209912 
590*5306Sgm209912 	if (*begin++ != COMMP_EQUALS) {
591*5306Sgm209912 		*p_error |= SDP_REPEAT_TIME_ERROR;
592*5306Sgm209912 		return;
593*5306Sgm209912 	}
594*5306Sgm209912 	/*
595*5306Sgm209912 	 * A time field should be present before this field can occur, if
596*5306Sgm209912 	 * time is NULL then repeat field has occured before time field and
597*5306Sgm209912 	 * hence fields are out of order.
598*5306Sgm209912 	 */
599*5306Sgm209912 	if (time == NULL)
600*5306Sgm209912 		return;
601*5306Sgm209912 	/*
602*5306Sgm209912 	 * Get the latest time field and associate this repeat field
603*5306Sgm209912 	 * with it.
604*5306Sgm209912 	 */
605*5306Sgm209912 	while (time->t_next != NULL)
606*5306Sgm209912 		time = time->t_next;
607*5306Sgm209912 	new_repeat = calloc(1, sizeof (sdp_repeat_t));
608*5306Sgm209912 	if (new_repeat == NULL) {
609*5306Sgm209912 		*p_error |= SDP_MEMORY_ERROR;
610*5306Sgm209912 		return;
611*5306Sgm209912 	}
612*5306Sgm209912 	/*
613*5306Sgm209912 	 * for a given time field, there could be several repeat fields
614*5306Sgm209912 	 * add the new repeat field at the end of it.
615*5306Sgm209912 	 */
616*5306Sgm209912 	repeat = time->t_repeat;
617*5306Sgm209912 	if (repeat == NULL) {
618*5306Sgm209912 		time->t_repeat = new_repeat;
619*5306Sgm209912 	} else {
620*5306Sgm209912 		while (repeat->r_next != NULL)
621*5306Sgm209912 			repeat = repeat->r_next;
622*5306Sgm209912 		repeat->r_next = new_repeat;
623*5306Sgm209912 	}
624*5306Sgm209912 	/*
625*5306Sgm209912 	 * Populate the elements of sdp_repeat.
626*5306Sgm209912 	 * Get time-interval
627*5306Sgm209912 	 */
628*5306Sgm209912 	current = begin;
629*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_SP, B_FALSE) != 0)
630*5306Sgm209912 		goto err_ret;
631*5306Sgm209912 	if (commp_time_to_secs(begin, current, &new_repeat->r_interval) != 0)
632*5306Sgm209912 		goto err_ret;
633*5306Sgm209912 	/* Get duration. It could be the last sub-field */
634*5306Sgm209912 	begin = ++current;
635*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_SP, B_FALSE) != 0)
636*5306Sgm209912 		goto err_ret;
637*5306Sgm209912 	if (commp_time_to_secs(begin, current, &new_repeat->r_duration) != 0)
638*5306Sgm209912 		goto err_ret;
639*5306Sgm209912 	++current;
640*5306Sgm209912 	/* Get offsets into sdp_list */
641*5306Sgm209912 	if (current >= end)
642*5306Sgm209912 		goto err_ret;
643*5306Sgm209912 	while (current < end) {
644*5306Sgm209912 		begin = current;
645*5306Sgm209912 		if (commp_find_token(&begin, &current, end, COMMP_SP,
646*5306Sgm209912 		    B_FALSE) != 0) {
647*5306Sgm209912 			goto err_ret;
648*5306Sgm209912 		}
649*5306Sgm209912 		if ((ret = add_value_to_list(&new_repeat->r_offset, begin,
650*5306Sgm209912 		    current - begin, B_FALSE)) != 0) {
651*5306Sgm209912 			if (ret == ENOMEM) {
652*5306Sgm209912 				*p_error |= SDP_MEMORY_ERROR;
653*5306Sgm209912 				return;
654*5306Sgm209912 			} else {
655*5306Sgm209912 				goto err_ret;
656*5306Sgm209912 			}
657*5306Sgm209912 		}
658*5306Sgm209912 		++current;
659*5306Sgm209912 	}
660*5306Sgm209912 	/* check for trailing white space character. */
661*5306Sgm209912 	if (isspace(*(end - 1)))
662*5306Sgm209912 		goto err_ret;
663*5306Sgm209912 	return;
664*5306Sgm209912 err_ret:
665*5306Sgm209912 	*p_error |= SDP_REPEAT_TIME_ERROR;
666*5306Sgm209912 	if (repeat != NULL)
667*5306Sgm209912 		repeat->r_next = NULL;
668*5306Sgm209912 	else
669*5306Sgm209912 		time->t_repeat = NULL;
670*5306Sgm209912 	sdp_free_repeat(new_repeat);
671*5306Sgm209912 }
672*5306Sgm209912 
673*5306Sgm209912 /*
674*5306Sgm209912  * zone-adjustments (z=)
675*5306Sgm209912  * %x7a "=" time SP ["-"] typed-time *(SP time SP ["-"] typed-time)
676*5306Sgm209912  */
677*5306Sgm209912 static void
sdp_parse_zone(sdp_zone_t ** zone,const char * begin,const char * end,uint_t * p_error)678*5306Sgm209912 sdp_parse_zone(sdp_zone_t **zone, const char *begin, const char *end,
679*5306Sgm209912     uint_t *p_error)
680*5306Sgm209912 {
681*5306Sgm209912 	const char	*current;
682*5306Sgm209912 	sdp_zone_t	*new_zone = NULL;
683*5306Sgm209912 	sdp_zone_t	*tmp = NULL;
684*5306Sgm209912 
685*5306Sgm209912 	if (*begin++ != COMMP_EQUALS) {
686*5306Sgm209912 		*p_error |= SDP_ZONE_ERROR;
687*5306Sgm209912 		return;
688*5306Sgm209912 	}
689*5306Sgm209912 	/* There can be atmost one zone field. */
690*5306Sgm209912 	if (*zone != NULL)
691*5306Sgm209912 		return;
692*5306Sgm209912 	/* Get time and offset */
693*5306Sgm209912 	current = begin;
694*5306Sgm209912 	while (current < end) {
695*5306Sgm209912 		new_zone = calloc(1, sizeof (sdp_zone_t));
696*5306Sgm209912 		if (new_zone == NULL) {
697*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
698*5306Sgm209912 			return;
699*5306Sgm209912 		}
700*5306Sgm209912 		if (*zone == NULL) {
701*5306Sgm209912 			*zone = new_zone;
702*5306Sgm209912 			tmp = *zone;
703*5306Sgm209912 		} else {
704*5306Sgm209912 			tmp->z_next = new_zone;
705*5306Sgm209912 			tmp = new_zone;
706*5306Sgm209912 		}
707*5306Sgm209912 		begin = current;
708*5306Sgm209912 		if (commp_find_token(&begin, &current, end, COMMP_SP,
709*5306Sgm209912 		    B_FALSE) != 0) {
710*5306Sgm209912 			goto err_ret;
711*5306Sgm209912 		}
712*5306Sgm209912 		if (commp_strtoull(begin, current, &new_zone->z_time) != 0)
713*5306Sgm209912 			goto err_ret;
714*5306Sgm209912 		begin = ++current;
715*5306Sgm209912 		if (commp_find_token(&begin, &current, end, COMMP_SP,
716*5306Sgm209912 		    B_FALSE) != 0) {
717*5306Sgm209912 			goto err_ret;
718*5306Sgm209912 		} else {
719*5306Sgm209912 			COMMP_COPY_STR(new_zone->z_offset, begin, current -
720*5306Sgm209912 			    begin);
721*5306Sgm209912 			if (new_zone->z_offset == NULL) {
722*5306Sgm209912 				*p_error |= SDP_MEMORY_ERROR;
723*5306Sgm209912 				return;
724*5306Sgm209912 			}
725*5306Sgm209912 
726*5306Sgm209912 		}
727*5306Sgm209912 		++current;
728*5306Sgm209912 	}
729*5306Sgm209912 	if (isspace(*(end - 1)))
730*5306Sgm209912 		goto err_ret;
731*5306Sgm209912 	return;
732*5306Sgm209912 err_ret:
733*5306Sgm209912 	*p_error |= SDP_ZONE_ERROR;
734*5306Sgm209912 	sdp_free_zone(*zone);
735*5306Sgm209912 	*zone = NULL;
736*5306Sgm209912 }
737*5306Sgm209912 
738*5306Sgm209912 /*
739*5306Sgm209912  * key-field (k=)
740*5306Sgm209912  * [%x6b "=" key-type CRLF]
741*5306Sgm209912  * key-type = %x70 %x72 %x6f %x6d %x70 %x74 /     ; "prompt"
742*5306Sgm209912  *            %x63 %x6c %x65 %x61 %x72 ":" text / ; "clear:"
743*5306Sgm209912  *            %x62 %x61 %x73 %x65 "64:" base64 /  ; "base64:"
744*5306Sgm209912  *            %x75 %x72 %x69 ":" uri              ; "uri:"
745*5306Sgm209912  */
746*5306Sgm209912 static void
sdp_parse_key(sdp_key_t ** key,const char * begin,const char * end,uint_t * p_error)747*5306Sgm209912 sdp_parse_key(sdp_key_t **key, const char *begin, const char *end,
748*5306Sgm209912     uint_t *p_error)
749*5306Sgm209912 {
750*5306Sgm209912 	const char	*current;
751*5306Sgm209912 	sdp_key_t	*new_key;
752*5306Sgm209912 
753*5306Sgm209912 	if (*begin++ != COMMP_EQUALS) {
754*5306Sgm209912 		*p_error |= SDP_KEY_ERROR;
755*5306Sgm209912 		return;
756*5306Sgm209912 	}
757*5306Sgm209912 	/* There can be only one key field */
758*5306Sgm209912 	if (*key != NULL)
759*5306Sgm209912 		return;
760*5306Sgm209912 	new_key = calloc(1, sizeof (sdp_key_t));
761*5306Sgm209912 	if (new_key == NULL) {
762*5306Sgm209912 		*p_error |= SDP_MEMORY_ERROR;
763*5306Sgm209912 		return;
764*5306Sgm209912 	}
765*5306Sgm209912 	/* Get Method name */
766*5306Sgm209912 	current = begin;
767*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_COLON,
768*5306Sgm209912 	    B_FALSE) != 0) {
769*5306Sgm209912 		goto err_ret;
770*5306Sgm209912 	} else {
771*5306Sgm209912 		COMMP_COPY_STR(new_key->k_method, begin, current - begin);
772*5306Sgm209912 		if (new_key->k_method == NULL) {
773*5306Sgm209912 			sdp_free_key(new_key);
774*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
775*5306Sgm209912 			return;
776*5306Sgm209912 		}
777*5306Sgm209912 	}
778*5306Sgm209912 	/* Get key, if exists. */
779*5306Sgm209912 	if (*current == COMMP_COLON) {
780*5306Sgm209912 		++current;
781*5306Sgm209912 		if (current == end)
782*5306Sgm209912 			goto err_ret;
783*5306Sgm209912 		COMMP_COPY_STR(new_key->k_enckey, current, end - current);
784*5306Sgm209912 		if (new_key->k_enckey == NULL) {
785*5306Sgm209912 			sdp_free_key(new_key);
786*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
787*5306Sgm209912 			return;
788*5306Sgm209912 		}
789*5306Sgm209912 	}
790*5306Sgm209912 	*key = new_key;
791*5306Sgm209912 	return;
792*5306Sgm209912 err_ret:
793*5306Sgm209912 	*p_error |= SDP_KEY_ERROR;
794*5306Sgm209912 	sdp_free_key(new_key);
795*5306Sgm209912 }
796*5306Sgm209912 
797*5306Sgm209912 /*
798*5306Sgm209912  * attribute-fields (a=)
799*5306Sgm209912  * *(%x61 "=" attribute CRLF)
800*5306Sgm209912  * attribute = (att-field ":" att-value) / att-field
801*5306Sgm209912  * att-field = token
802*5306Sgm209912  * att-value = byte-string
803*5306Sgm209912  */
804*5306Sgm209912 static void
sdp_parse_attribute(sdp_attr_t ** attr,const char * begin,const char * end,uint_t * p_error)805*5306Sgm209912 sdp_parse_attribute(sdp_attr_t **attr, const char *begin, const char *end,
806*5306Sgm209912     uint_t *p_error)
807*5306Sgm209912 {
808*5306Sgm209912 	const char	*current;
809*5306Sgm209912 	sdp_attr_t	*new_attr;
810*5306Sgm209912 	sdp_attr_t	*tmp;
811*5306Sgm209912 
812*5306Sgm209912 	if (*begin++ != COMMP_EQUALS) {
813*5306Sgm209912 		*p_error |= SDP_ATTRIBUTE_ERROR;
814*5306Sgm209912 		return;
815*5306Sgm209912 	}
816*5306Sgm209912 	new_attr = calloc(1, sizeof (sdp_attr_t));
817*5306Sgm209912 	if (new_attr == NULL) {
818*5306Sgm209912 		*p_error |= SDP_MEMORY_ERROR;
819*5306Sgm209912 		return;
820*5306Sgm209912 	}
821*5306Sgm209912 	/* Get Attribute Name */
822*5306Sgm209912 	current = begin;
823*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_COLON,
824*5306Sgm209912 	    B_FALSE) != 0) {
825*5306Sgm209912 		goto err_ret;
826*5306Sgm209912 	} else {
827*5306Sgm209912 		COMMP_COPY_STR(new_attr->a_name, begin, current - begin);
828*5306Sgm209912 		if (new_attr->a_name == NULL) {
829*5306Sgm209912 			sdp_free_attribute(new_attr);
830*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
831*5306Sgm209912 			return;
832*5306Sgm209912 		}
833*5306Sgm209912 	}
834*5306Sgm209912 	/* Get Attribute Value */
835*5306Sgm209912 	if (*current == COMMP_COLON) {
836*5306Sgm209912 		++current;
837*5306Sgm209912 		if (current == end)
838*5306Sgm209912 			goto err_ret;
839*5306Sgm209912 		COMMP_COPY_STR(new_attr->a_value, current, end - current);
840*5306Sgm209912 		if (new_attr->a_value == NULL) {
841*5306Sgm209912 			sdp_free_attribute(new_attr);
842*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
843*5306Sgm209912 			return;
844*5306Sgm209912 		}
845*5306Sgm209912 	}
846*5306Sgm209912 	if (*attr == NULL) {
847*5306Sgm209912 		*attr = new_attr;
848*5306Sgm209912 	} else {
849*5306Sgm209912 		tmp = *attr;
850*5306Sgm209912 		while (tmp->a_next != NULL)
851*5306Sgm209912 			tmp = tmp->a_next;
852*5306Sgm209912 		tmp->a_next = new_attr;
853*5306Sgm209912 	}
854*5306Sgm209912 	return;
855*5306Sgm209912 err_ret:
856*5306Sgm209912 	*p_error |= SDP_ATTRIBUTE_ERROR;
857*5306Sgm209912 	sdp_free_attribute(new_attr);
858*5306Sgm209912 }
859*5306Sgm209912 
860*5306Sgm209912 /*
861*5306Sgm209912  * media-field (m=)
862*5306Sgm209912  * %x6d "=" media SP port ["/" integer] SP proto 1*(SP fmt) CRLF
863*5306Sgm209912  */
864*5306Sgm209912 static sdp_media_t *
sdp_parse_media(sdp_session_t * session,const char * begin,const char * end,uint_t * p_error)865*5306Sgm209912 sdp_parse_media(sdp_session_t *session, const char *begin, const char *end,
866*5306Sgm209912     uint_t *p_error)
867*5306Sgm209912 {
868*5306Sgm209912 	const char	*current;
869*5306Sgm209912 	const char	*fake_end;
870*5306Sgm209912 	sdp_media_t	*new_media;
871*5306Sgm209912 	sdp_media_t	*tmp;
872*5306Sgm209912 
873*5306Sgm209912 	if (*begin++ != COMMP_EQUALS) {
874*5306Sgm209912 		*p_error |= SDP_MEDIA_ERROR;
875*5306Sgm209912 		return (NULL);
876*5306Sgm209912 	}
877*5306Sgm209912 
878*5306Sgm209912 	new_media = calloc(1, sizeof (sdp_media_t));
879*5306Sgm209912 	if (new_media == NULL) {
880*5306Sgm209912 		*p_error |= SDP_MEMORY_ERROR;
881*5306Sgm209912 		return (NULL);
882*5306Sgm209912 	}
883*5306Sgm209912 	new_media->m_session = session;
884*5306Sgm209912 	/* Get media name */
885*5306Sgm209912 	current = begin;
886*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_SP, B_FALSE) != 0) {
887*5306Sgm209912 		goto err_ret;
888*5306Sgm209912 	} else {
889*5306Sgm209912 		COMMP_COPY_STR(new_media->m_name, begin, current - begin);
890*5306Sgm209912 		if (new_media->m_name == NULL) {
891*5306Sgm209912 			sdp_free_media(new_media);
892*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
893*5306Sgm209912 			return (NULL);
894*5306Sgm209912 		}
895*5306Sgm209912 	}
896*5306Sgm209912 	/* Get port */
897*5306Sgm209912 	begin = ++current;
898*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_SP, B_FALSE) != 0)
899*5306Sgm209912 		goto err_ret;
900*5306Sgm209912 	fake_end = current;
901*5306Sgm209912 	current = begin;
902*5306Sgm209912 	if (commp_find_token(&begin, &current, fake_end, COMMP_SLASH,
903*5306Sgm209912 	    B_FALSE) != 0) {
904*5306Sgm209912 		goto err_ret;
905*5306Sgm209912 	}
906*5306Sgm209912 	if (commp_atoui(begin, current, &new_media->m_port) != 0)
907*5306Sgm209912 		goto err_ret;
908*5306Sgm209912 	/* Get portcount */
909*5306Sgm209912 	if (*current == COMMP_SLASH) {
910*5306Sgm209912 		begin = ++current;
911*5306Sgm209912 		if (commp_find_token(&begin, &current, fake_end, COMMP_SP,
912*5306Sgm209912 		    B_FALSE) != 0) {
913*5306Sgm209912 			goto err_ret;
914*5306Sgm209912 		}
915*5306Sgm209912 		if (commp_atoi(begin, current, &new_media->m_portcount) != 0)
916*5306Sgm209912 			goto err_ret;
917*5306Sgm209912 	} else {
918*5306Sgm209912 		new_media->m_portcount = 1;
919*5306Sgm209912 	}
920*5306Sgm209912 	/* Get Protocol */
921*5306Sgm209912 	begin = ++current;
922*5306Sgm209912 	if (commp_find_token(&begin, &current, end, COMMP_SP, B_FALSE) != 0) {
923*5306Sgm209912 		goto err_ret;
924*5306Sgm209912 	} else {
925*5306Sgm209912 		COMMP_COPY_STR(new_media->m_proto, begin, current - begin);
926*5306Sgm209912 		if (new_media->m_proto == NULL) {
927*5306Sgm209912 			sdp_free_media(new_media);
928*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
929*5306Sgm209912 			return (NULL);
930*5306Sgm209912 		}
931*5306Sgm209912 	}
932*5306Sgm209912 	++current;
933*5306Sgm209912 	/* Get format list */
934*5306Sgm209912 	if (current >= end)
935*5306Sgm209912 		goto err_ret;
936*5306Sgm209912 	while (current < end) {
937*5306Sgm209912 		begin = current;
938*5306Sgm209912 		if (commp_find_token(&begin, &current, end, COMMP_SP,
939*5306Sgm209912 		    B_FALSE) != 0) {
940*5306Sgm209912 			goto err_ret;
941*5306Sgm209912 		}
942*5306Sgm209912 		if (add_value_to_list(&new_media->m_format, begin,
943*5306Sgm209912 		    current - begin, B_TRUE) != 0) {
944*5306Sgm209912 			sdp_free_media(new_media);
945*5306Sgm209912 			*p_error |= SDP_MEMORY_ERROR;
946*5306Sgm209912 			return (NULL);
947*5306Sgm209912 		}
948*5306Sgm209912 		++current;
949*5306Sgm209912 	}
950*5306Sgm209912 	/* check for trailing white space character. */
951*5306Sgm209912 	if (isspace(*(end - 1)))
952*5306Sgm209912 		goto err_ret;
953*5306Sgm209912 	/* Assign new media to the media list */
954*5306Sgm209912 	tmp = session->s_media;
955*5306Sgm209912 	if (tmp == NULL) {
956*5306Sgm209912 		session->s_media = new_media;
957*5306Sgm209912 	} else {
958*5306Sgm209912 		while (tmp->m_next != NULL)
959*5306Sgm209912 			tmp = tmp->m_next;
960*5306Sgm209912 		tmp->m_next = new_media;
961*5306Sgm209912 	}
962*5306Sgm209912 	return (new_media);
963*5306Sgm209912 err_ret:
964*5306Sgm209912 	*p_error |= SDP_MEDIA_ERROR;
965*5306Sgm209912 	sdp_free_media(new_media);
966*5306Sgm209912 	return (NULL);
967*5306Sgm209912 }
968*5306Sgm209912 
969*5306Sgm209912 /*
970*5306Sgm209912  * This function ensures that a field is in the right order in SDP descripton.
971*5306Sgm209912  * It also identifies cases where a field ('v', 'o, 'i', et al) that must occur
972*5306Sgm209912  * once but occurs several times in SDP description. error cannot be NULL.
973*5306Sgm209912  */
974*5306Sgm209912 static void
sdp_check_order(char prev,char * order,int * error)975*5306Sgm209912 sdp_check_order(char prev, char *order, int *error)
976*5306Sgm209912 {
977*5306Sgm209912 	*error = 0;
978*5306Sgm209912 	while (*order != '\0') {
979*5306Sgm209912 		if (*order++ == prev)
980*5306Sgm209912 			return;
981*5306Sgm209912 	}
982*5306Sgm209912 	*error = 1;
983*5306Sgm209912 }
984*5306Sgm209912 
985*5306Sgm209912 /*
986*5306Sgm209912  * This function determines the SDP field and calls the appropriate parse
987*5306Sgm209912  * function. It also ensures that the SDP fields are in strict order.
988*5306Sgm209912  */
989*5306Sgm209912 static void
sdp_handle_fields(sdp_description_t * description,sdp_session_t * _session,const char * begin,const char * end)990*5306Sgm209912 sdp_handle_fields(sdp_description_t *description, sdp_session_t *_session,
991*5306Sgm209912     const char *begin, const char *end)
992*5306Sgm209912 {
993*5306Sgm209912 	boolean_t	u_field = B_FALSE;
994*5306Sgm209912 	int		error = 0;			/* fields order error */
995*5306Sgm209912 	char		prev = description->d_prev;
996*5306Sgm209912 	char		m_prev = description->d_mprev;
997*5306Sgm209912 
998*5306Sgm209912 	switch (*begin) {
999*5306Sgm209912 		case SDP_VERSION_FIELD:
1000*5306Sgm209912 			sdp_check_order(prev, SDP_VERSION_ORDER, &error);
1001*5306Sgm209912 			description->d_version = B_TRUE;
1002*5306Sgm209912 			sdp_parse_version(&_session->s_version, begin + 1, end,
1003*5306Sgm209912 			    &description->d_perror);
1004*5306Sgm209912 			break;
1005*5306Sgm209912 		case SDP_ORIGIN_FIELD:
1006*5306Sgm209912 			sdp_check_order(prev, SDP_ORIGIN_ORDER, &error);
1007*5306Sgm209912 			description->d_origin = B_TRUE;
1008*5306Sgm209912 			sdp_parse_origin(&_session->s_origin, begin + 1, end,
1009*5306Sgm209912 			    &description->d_perror);
1010*5306Sgm209912 			break;
1011*5306Sgm209912 		case SDP_NAME_FIELD:
1012*5306Sgm209912 			sdp_check_order(prev, SDP_NAME_ORDER, &error);
1013*5306Sgm209912 			description->d_name = B_TRUE;
1014*5306Sgm209912 			sdp_parse_name(&_session->s_name, begin + 1, end,
1015*5306Sgm209912 			    &description->d_perror);
1016*5306Sgm209912 			break;
1017*5306Sgm209912 		case SDP_INFO_FIELD:
1018*5306Sgm209912 			if (description->d_mparsed) {
1019*5306Sgm209912 				sdp_check_order(m_prev, SDP_M_INFO_ORDER,
1020*5306Sgm209912 				    &error);
1021*5306Sgm209912 				if (description->d_lmedia == NULL)
1022*5306Sgm209912 					break;
1023*5306Sgm209912 				sdp_parse_info(&(description->d_lmedia->
1024*5306Sgm209912 				    m_info), begin + 1, end, &description->
1025*5306Sgm209912 				    d_perror);
1026*5306Sgm209912 			} else {
1027*5306Sgm209912 				sdp_check_order(prev, SDP_INFO_ORDER, &error);
1028*5306Sgm209912 				sdp_parse_info(&_session->s_info, begin + 1,
1029*5306Sgm209912 				    end, &description->d_perror);
1030*5306Sgm209912 			}
1031*5306Sgm209912 			break;
1032*5306Sgm209912 		case SDP_URI_FIELD:
1033*5306Sgm209912 			sdp_check_order(prev, SDP_URI_ORDER, &error);
1034*5306Sgm209912 			sdp_parse_uri(&_session->s_uri, begin + 1, end,
1035*5306Sgm209912 			    &description->d_perror);
1036*5306Sgm209912 			break;
1037*5306Sgm209912 		case SDP_EMAIL_FIELD:
1038*5306Sgm209912 			sdp_check_order(prev, SDP_EMAIL_ORDER, &error);
1039*5306Sgm209912 			sdp_parse_email(&_session->s_email, begin + 1, end,
1040*5306Sgm209912 			    &description->d_perror);
1041*5306Sgm209912 			break;
1042*5306Sgm209912 		case SDP_PHONE_FIELD:
1043*5306Sgm209912 			sdp_check_order(prev, SDP_PHONE_ORDER, &error);
1044*5306Sgm209912 			sdp_parse_phone(&_session->s_phone, begin + 1, end,
1045*5306Sgm209912 			    &description->d_perror);
1046*5306Sgm209912 			break;
1047*5306Sgm209912 		case SDP_CONNECTION_FIELD:
1048*5306Sgm209912 			if (description->d_mparsed) {
1049*5306Sgm209912 				sdp_check_order(m_prev, SDP_M_CONN_ORDER,
1050*5306Sgm209912 				    &error);
1051*5306Sgm209912 				--description->d_mccount;
1052*5306Sgm209912 				if (description->d_lmedia == NULL)
1053*5306Sgm209912 					break;
1054*5306Sgm209912 				sdp_parse_connection(&(description->d_lmedia->
1055*5306Sgm209912 				    m_conn), begin + 1, end,
1056*5306Sgm209912 				    &description->d_perror);
1057*5306Sgm209912 			} else {
1058*5306Sgm209912 				/*
1059*5306Sgm209912 				 * RFC - 4566 says that session section  should
1060*5306Sgm209912 				 * have only one connection field, while media
1061*5306Sgm209912 				 * section can have many
1062*5306Sgm209912 				 */
1063*5306Sgm209912 				sdp_check_order(prev, SDP_CONN_ORDER, &error);
1064*5306Sgm209912 				description->d_conn = B_TRUE;
1065*5306Sgm209912 				if (_session->s_conn != NULL)
1066*5306Sgm209912 					break;
1067*5306Sgm209912 				sdp_parse_connection(&_session->s_conn,
1068*5306Sgm209912 				    begin + 1, end, &description->d_perror);
1069*5306Sgm209912 			}
1070*5306Sgm209912 			break;
1071*5306Sgm209912 		case SDP_BANDWIDTH_FIELD:
1072*5306Sgm209912 			if (description->d_mparsed) {
1073*5306Sgm209912 				sdp_check_order(m_prev, SDP_M_BW_ORDER, &error);
1074*5306Sgm209912 				if (description->d_lmedia == NULL)
1075*5306Sgm209912 					break;
1076*5306Sgm209912 				sdp_parse_bandwidth(&(description->d_lmedia->
1077*5306Sgm209912 				    m_bw), begin + 1, end,
1078*5306Sgm209912 				    &description->d_perror);
1079*5306Sgm209912 			} else {
1080*5306Sgm209912 				sdp_check_order(prev, SDP_BW_ORDER, &error);
1081*5306Sgm209912 				sdp_parse_bandwidth(&_session->s_bw,
1082*5306Sgm209912 				    begin + 1, end, &description->d_perror);
1083*5306Sgm209912 			}
1084*5306Sgm209912 			break;
1085*5306Sgm209912 		case SDP_TIME_FIELD:
1086*5306Sgm209912 			if (!description->d_tparsed || description->d_prev !=
1087*5306Sgm209912 			    SDP_REPEAT_FIELD) {
1088*5306Sgm209912 				sdp_check_order(prev, SDP_TIME_ORDER, &error);
1089*5306Sgm209912 			}
1090*5306Sgm209912 			description->d_tparsed = B_TRUE;
1091*5306Sgm209912 			description->d_ltime = sdp_parse_time(&_session->
1092*5306Sgm209912 			    s_time, begin + 1, end, &description->d_perror);
1093*5306Sgm209912 			break;
1094*5306Sgm209912 		case SDP_REPEAT_FIELD:
1095*5306Sgm209912 			sdp_check_order(prev, SDP_REPEAT_ORDER, &error);
1096*5306Sgm209912 			if (description->d_ltime == NULL)
1097*5306Sgm209912 				break;
1098*5306Sgm209912 			/* we pass time, as repeat is associated with time */
1099*5306Sgm209912 			sdp_parse_repeat(description->d_ltime, begin + 1, end,
1100*5306Sgm209912 			    &description->d_perror);
1101*5306Sgm209912 			break;
1102*5306Sgm209912 		case SDP_ZONE_FIELD:
1103*5306Sgm209912 			sdp_check_order(prev, SDP_ZONE_ORDER, &error);
1104*5306Sgm209912 			sdp_parse_zone(&_session->s_zone, begin + 1, end,
1105*5306Sgm209912 			    &description->d_perror);
1106*5306Sgm209912 			break;
1107*5306Sgm209912 		case SDP_KEY_FIELD:
1108*5306Sgm209912 			if (description->d_mparsed) {
1109*5306Sgm209912 				sdp_check_order(m_prev, SDP_M_KEY_ORDER,
1110*5306Sgm209912 				    &error);
1111*5306Sgm209912 				if (description->d_lmedia == NULL)
1112*5306Sgm209912 					break;
1113*5306Sgm209912 				sdp_parse_key(&(description->d_lmedia->m_key),
1114*5306Sgm209912 				    begin + 1, end, &description->d_perror);
1115*5306Sgm209912 			} else {
1116*5306Sgm209912 				sdp_check_order(prev, SDP_KEY_ORDER, &error);
1117*5306Sgm209912 				sdp_parse_key(&_session->s_key, begin + 1, end,
1118*5306Sgm209912 				    &description->d_perror);
1119*5306Sgm209912 			}
1120*5306Sgm209912 			break;
1121*5306Sgm209912 		case SDP_ATTRIBUTE_FIELD:
1122*5306Sgm209912 			if (description->d_mparsed) {
1123*5306Sgm209912 				sdp_check_order(m_prev, SDP_M_ATTR_ORDER,
1124*5306Sgm209912 				    &error);
1125*5306Sgm209912 				if (description->d_lmedia == NULL)
1126*5306Sgm209912 					break;
1127*5306Sgm209912 				sdp_parse_attribute(&(description->d_lmedia->
1128*5306Sgm209912 				    m_attr), begin + 1, end,
1129*5306Sgm209912 				    &description->d_perror);
1130*5306Sgm209912 			} else {
1131*5306Sgm209912 				sdp_check_order(prev, SDP_ATTR_ORDER, &error);
1132*5306Sgm209912 				sdp_parse_attribute(&_session->s_attr,
1133*5306Sgm209912 				    begin + 1, end, &description->d_perror);
1134*5306Sgm209912 			}
1135*5306Sgm209912 			break;
1136*5306Sgm209912 		case SDP_MEDIA_FIELD:
1137*5306Sgm209912 			if (!description->d_mparsed) {
1138*5306Sgm209912 				sdp_check_order(prev, SDP_MEDIA_ORDER, &error);
1139*5306Sgm209912 				description->d_mccount = 1;
1140*5306Sgm209912 			} else {
1141*5306Sgm209912 				if (description->d_mccount == 1)
1142*5306Sgm209912 					description->d_mconn = B_FALSE;
1143*5306Sgm209912 				description->d_mccount = 1;
1144*5306Sgm209912 			}
1145*5306Sgm209912 			description->d_mparsed = B_TRUE;
1146*5306Sgm209912 			description->d_lmedia = sdp_parse_media(_session,
1147*5306Sgm209912 			    begin + 1, end, &description->d_perror);
1148*5306Sgm209912 			break;
1149*5306Sgm209912 		default:
1150*5306Sgm209912 			/* Unknown field type. Ignore it */
1151*5306Sgm209912 			u_field = B_TRUE;
1152*5306Sgm209912 			break;
1153*5306Sgm209912 	}
1154*5306Sgm209912 	if (error)
1155*5306Sgm209912 		description->d_perror |= SDP_FIELDS_ORDER_ERROR;
1156*5306Sgm209912 	if (!u_field) {
1157*5306Sgm209912 		if (!description->d_mparsed)
1158*5306Sgm209912 			description->d_prev = *begin;
1159*5306Sgm209912 		else
1160*5306Sgm209912 			description->d_mprev = *begin;
1161*5306Sgm209912 	}
1162*5306Sgm209912 }
1163*5306Sgm209912 
1164*5306Sgm209912 /*
1165*5306Sgm209912  * Parses the SDP info
1166*5306Sgm209912  */
1167*5306Sgm209912 int
sdp_parse(const char * sdp_info,int len,int flags,sdp_session_t ** session,uint_t * p_error)1168*5306Sgm209912 sdp_parse(const char *sdp_info, int len, int flags, sdp_session_t **session,
1169*5306Sgm209912     uint_t *p_error)
1170*5306Sgm209912 {
1171*5306Sgm209912 
1172*5306Sgm209912 	const char		*f_begin;
1173*5306Sgm209912 	const char		*f_end;
1174*5306Sgm209912 	sdp_description_t	*description;
1175*5306Sgm209912 	const char		*start;
1176*5306Sgm209912 	const char		*end;
1177*5306Sgm209912 	const char		*current;
1178*5306Sgm209912 
1179*5306Sgm209912 	if (sdp_info == NULL || len == 0 || p_error == NULL || flags != 0 ||
1180*5306Sgm209912 	    session == NULL) {
1181*5306Sgm209912 		if (session != NULL)
1182*5306Sgm209912 			*session = NULL;
1183*5306Sgm209912 		return (EINVAL);
1184*5306Sgm209912 	}
1185*5306Sgm209912 	*session = NULL;
1186*5306Sgm209912 	*p_error = 0;
1187*5306Sgm209912 	description = calloc(1, sizeof (sdp_description_t));
1188*5306Sgm209912 	if (description == NULL) {
1189*5306Sgm209912 		return (ENOMEM);
1190*5306Sgm209912 	}
1191*5306Sgm209912 	/* Needed later to check for mandatory fields */
1192*5306Sgm209912 	description->d_prev = COMMP_SP;
1193*5306Sgm209912 	description->d_mconn = B_TRUE;
1194*5306Sgm209912 	*session = sdp_new_session();
1195*5306Sgm209912 	if (*session == NULL) {
1196*5306Sgm209912 		free(description);
1197*5306Sgm209912 		return (ENOMEM);
1198*5306Sgm209912 	}
1199*5306Sgm209912 	start = sdp_info;
1200*5306Sgm209912 	end = start + len;
1201*5306Sgm209912 	if (commp_skip_white_space(&start, end) != 0) {
1202*5306Sgm209912 		free(description);
1203*5306Sgm209912 		free(*session);
1204*5306Sgm209912 		*session = NULL;
1205*5306Sgm209912 		return (EINVAL);
1206*5306Sgm209912 	}
1207*5306Sgm209912 	current = start;
1208*5306Sgm209912 	f_begin = current;
1209*5306Sgm209912 	while ((current < end) && !(description->d_perror &
1210*5306Sgm209912 	    SDP_MEMORY_ERROR)) {
1211*5306Sgm209912 		/*
1212*5306Sgm209912 		 * RFC says parser SHOULD be tolerant to records ending
1213*5306Sgm209912 		 * with a single newline character too.
1214*5306Sgm209912 		 */
1215*5306Sgm209912 		if (strncmp(COMMP_CRLF, current, strlen(COMMP_CRLF)) == 0) {
1216*5306Sgm209912 			f_end = current;
1217*5306Sgm209912 			sdp_handle_fields(description, *session, f_begin,
1218*5306Sgm209912 			    f_end);
1219*5306Sgm209912 			COMMP_SKIP_CRLF(current);
1220*5306Sgm209912 			(void) commp_skip_white_space(&current, end);
1221*5306Sgm209912 			f_begin = current;
1222*5306Sgm209912 		} else if (strncmp(COMMP_LF, current, strlen(COMMP_LF)) == 0) {
1223*5306Sgm209912 			f_end = current;
1224*5306Sgm209912 			sdp_handle_fields(description, *session, f_begin,
1225*5306Sgm209912 			    f_end);
1226*5306Sgm209912 			COMMP_SKIP_LF(current);
1227*5306Sgm209912 			(void) commp_skip_white_space(&current, end);
1228*5306Sgm209912 			f_begin = current;
1229*5306Sgm209912 		} else {
1230*5306Sgm209912 			current++;
1231*5306Sgm209912 		}
1232*5306Sgm209912 	}
1233*5306Sgm209912 	if (description->d_perror & SDP_MEMORY_ERROR) {
1234*5306Sgm209912 		free(description);
1235*5306Sgm209912 		sdp_free_session(*session);
1236*5306Sgm209912 		*session = NULL;
1237*5306Sgm209912 		return (ENOMEM);
1238*5306Sgm209912 	}
1239*5306Sgm209912 	/*
1240*5306Sgm209912 	 * Check for mandatory fields v, o, s, t fields. For connection field,
1241*5306Sgm209912 	 * RFC says; a connection field must be present in every media
1242*5306Sgm209912 	 * description or at the session-level
1243*5306Sgm209912 	 */
1244*5306Sgm209912 	if (description->d_mccount == 1)
1245*5306Sgm209912 		description->d_mconn = B_FALSE;
1246*5306Sgm209912 	if (!(description->d_version && description->d_origin &&
1247*5306Sgm209912 	    description->d_name && description->d_tparsed &&
1248*5306Sgm209912 	    (description->d_conn || (description->d_mparsed &&
1249*5306Sgm209912 	    description->d_mconn)))) {
1250*5306Sgm209912 		description->d_perror |= SDP_MISSING_FIELDS;
1251*5306Sgm209912 	}
1252*5306Sgm209912 	*p_error = description->d_perror;
1253*5306Sgm209912 	free(description);
1254*5306Sgm209912 	return (0);
1255*5306Sgm209912 }
1256