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