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