xref: /onnv-gate/usr/src/lib/libsip/common/sip_parse_hdrs.c (revision 2882:5f4abbf1f03e)
1*2882Svi117747 /*
2*2882Svi117747  * CDDL HEADER START
3*2882Svi117747  *
4*2882Svi117747  * The contents of this file are subject to the terms of the
5*2882Svi117747  * Common Development and Distribution License (the "License").
6*2882Svi117747  * You may not use this file except in compliance with the License.
7*2882Svi117747  *
8*2882Svi117747  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*2882Svi117747  * or http://www.opensolaris.org/os/licensing.
10*2882Svi117747  * See the License for the specific language governing permissions
11*2882Svi117747  * and limitations under the License.
12*2882Svi117747  *
13*2882Svi117747  * When distributing Covered Code, include this CDDL HEADER in each
14*2882Svi117747  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*2882Svi117747  * If applicable, add the following below this CDDL HEADER, with the
16*2882Svi117747  * fields enclosed by brackets "[]" replaced with your own identifying
17*2882Svi117747  * information: Portions Copyright [yyyy] [name of copyright owner]
18*2882Svi117747  *
19*2882Svi117747  * CDDL HEADER END
20*2882Svi117747  */
21*2882Svi117747 
22*2882Svi117747 /*
23*2882Svi117747  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*2882Svi117747  * Use is subject to license terms.
25*2882Svi117747  */
26*2882Svi117747 
27*2882Svi117747 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*2882Svi117747 
29*2882Svi117747 #include "sip_parse_uri.h"
30*2882Svi117747 #include "sip_msg.h"
31*2882Svi117747 #include "sip_miscdefs.h"
32*2882Svi117747 #include "sip_parse_generic.h"
33*2882Svi117747 
34*2882Svi117747 /*
35*2882Svi117747  * Accept = "Accept" HCOLON [ accept-range *(COMMA accept-range) ]
36*2882Svi117747  * accept-range = media-range *(SEMI accept-param)
37*2882Svi117747  * media-range = ("* / *" |  (m-type SLASH "*") | (m-type SLASH m-subtype))
38*2882Svi117747  *		*(SEMI m-param)
39*2882Svi117747  * accept-param = ("q" EQUAL qvalue) | generic-param
40*2882Svi117747  * qvalue = ("0" ["." 0*3DIGIT]) | ("1" ["." 0*3DIGIT])
41*2882Svi117747  * generic-param = token [ EQUAL gen-value]
42*2882Svi117747  * gen-value = token | host | quoted-str
43*2882Svi117747  */
44*2882Svi117747 int
45*2882Svi117747 sip_parse_acpt_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
46*2882Svi117747 {
47*2882Svi117747 	if (sip_is_empty_hdr(sip_header))
48*2882Svi117747 		return (sip_parse_hdr_empty(sip_header, header));
49*2882Svi117747 	return (sip_parse_hdr_parser1(sip_header, header, SIP_SLASH));
50*2882Svi117747 }
51*2882Svi117747 
52*2882Svi117747 /*
53*2882Svi117747  * Accept-Encoding = "Accept-Encoding" ":" 1#(codings [ ";" "q" "=" qval])
54*2882Svi117747  * codings = (content-coding | "*")
55*2882Svi117747  * content-coding = token
56*2882Svi117747  */
57*2882Svi117747 int
58*2882Svi117747 sip_parse_acpt_encode_header(_sip_header_t *sip_header,
59*2882Svi117747 	sip_parsed_header_t **header)
60*2882Svi117747 {
61*2882Svi117747 	return (sip_parse_hdr_parser1(sip_header, header, (char)NULL));
62*2882Svi117747 }
63*2882Svi117747 
64*2882Svi117747 /*
65*2882Svi117747  * Accept-Language = "Accept-Language" ":" [ lang * (COMMA lang) ]
66*2882Svi117747  * lang = lang-range *(SEMI accept-param)
67*2882Svi117747  * lang-range = ((1*8ALPHA * ("-" 1*8ALPHA)) | "*"
68*2882Svi117747  */
69*2882Svi117747 int
70*2882Svi117747 sip_parse_acpt_lang_header(_sip_header_t *sip_header,
71*2882Svi117747 	sip_parsed_header_t **header)
72*2882Svi117747 {
73*2882Svi117747 	if (sip_is_empty_hdr(sip_header))
74*2882Svi117747 		return (sip_parse_hdr_empty(sip_header, header));
75*2882Svi117747 	return (sip_parse_hdr_parser1(sip_header, header, (char)NULL));
76*2882Svi117747 }
77*2882Svi117747 
78*2882Svi117747 /*
79*2882Svi117747  * Alert-Info = "Alert-Info" ":" alert-param *(COMMA alert-param)
80*2882Svi117747  * alert-param = LAQUOT absoluteURI RAQUOT * (SEMI generic-param)
81*2882Svi117747  */
82*2882Svi117747 int
83*2882Svi117747 sip_parse_alert_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
84*2882Svi117747 {
85*2882Svi117747 	return (sip_parse_hdr_parser3(sip_header, header, SIP_STR_VAL, B_TRUE));
86*2882Svi117747 }
87*2882Svi117747 
88*2882Svi117747 /*
89*2882Svi117747  * Allow = "Allow" ":" method-name1[, method-name2..]
90*2882Svi117747  */
91*2882Svi117747 int
92*2882Svi117747 sip_parse_allow_header(_sip_header_t *hdr, sip_parsed_header_t **phdr)
93*2882Svi117747 {
94*2882Svi117747 	sip_parsed_header_t	*parsed_header;
95*2882Svi117747 	sip_hdr_value_t		*value = NULL;
96*2882Svi117747 	sip_hdr_value_t		*last_value = NULL;
97*2882Svi117747 	int			len;
98*2882Svi117747 	int			i;
99*2882Svi117747 	int			ret;
100*2882Svi117747 	boolean_t		multi_value = B_FALSE;
101*2882Svi117747 
102*2882Svi117747 	if ((ret = sip_prim_parsers(hdr, phdr)) != 0)
103*2882Svi117747 		return (ret);
104*2882Svi117747 
105*2882Svi117747 	if (*phdr != NULL)
106*2882Svi117747 		return (0);
107*2882Svi117747 
108*2882Svi117747 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
109*2882Svi117747 	if (parsed_header == NULL)
110*2882Svi117747 		return (ENOMEM);
111*2882Svi117747 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
112*2882Svi117747 	parsed_header->sip_header = hdr;
113*2882Svi117747 
114*2882Svi117747 	while (hdr->sip_hdr_current < hdr->sip_hdr_end) {
115*2882Svi117747 		value = calloc(1, sizeof (sip_hdr_value_t));
116*2882Svi117747 		if (value == NULL) {
117*2882Svi117747 			sip_free_phdr(parsed_header);
118*2882Svi117747 			return (ENOMEM);
119*2882Svi117747 		}
120*2882Svi117747 		if (last_value != NULL)
121*2882Svi117747 			last_value->sip_next_value = value;
122*2882Svi117747 		else
123*2882Svi117747 			parsed_header->value = (sip_value_t *)value;
124*2882Svi117747 
125*2882Svi117747 		value->sip_value_start = hdr->sip_hdr_current;
126*2882Svi117747 		value->sip_value_header = parsed_header;
127*2882Svi117747 
128*2882Svi117747 		if (sip_find_separator(hdr, SIP_COMMA, (char)NULL,
129*2882Svi117747 		    (char)NULL) == 0) {
130*2882Svi117747 			multi_value = B_TRUE;
131*2882Svi117747 		}
132*2882Svi117747 
133*2882Svi117747 		len = hdr->sip_hdr_current - value->sip_value_start;
134*2882Svi117747 		for (i = 1; i < MAX_SIP_METHODS; i++) {
135*2882Svi117747 			if (strncmp(sip_methods[i].name, value->sip_value_start,
136*2882Svi117747 			    len) == 0) {
137*2882Svi117747 				break;
138*2882Svi117747 			}
139*2882Svi117747 		}
140*2882Svi117747 		if (i >= MAX_SIP_METHODS) {
141*2882Svi117747 			value->int_val = 0;
142*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
143*2882Svi117747 			if (multi_value)
144*2882Svi117747 				goto next_val;
145*2882Svi117747 			else
146*2882Svi117747 				goto end;
147*2882Svi117747 		}
148*2882Svi117747 		value->int_val = i;
149*2882Svi117747 		if (!multi_value)
150*2882Svi117747 			goto end;
151*2882Svi117747 	next_val:
152*2882Svi117747 		if (sip_find_token(hdr, SIP_COMMA) != 0)
153*2882Svi117747 			break;
154*2882Svi117747 		value->sip_value_end = hdr->sip_hdr_current - 1;
155*2882Svi117747 		last_value = value;
156*2882Svi117747 		(void) sip_skip_white_space(hdr);
157*2882Svi117747 	}
158*2882Svi117747 
159*2882Svi117747 end:
160*2882Svi117747 	*phdr = parsed_header;
161*2882Svi117747 	return (0);
162*2882Svi117747 }
163*2882Svi117747 
164*2882Svi117747 
165*2882Svi117747 /*
166*2882Svi117747  * Call-Info = "Call-Info" HCOLON info * (COMMA info)
167*2882Svi117747  * info = LAQUOT absoluteURI RAQUOT * (SEMI info-param)
168*2882Svi117747  * info-param = ("purpose" EQUAL ("icon" | "info" | "card" | token)) |
169*2882Svi117747  *		 generic-param
170*2882Svi117747  */
171*2882Svi117747 int
172*2882Svi117747 sip_parse_callinfo_header(_sip_header_t *sip_header,
173*2882Svi117747     sip_parsed_header_t **header)
174*2882Svi117747 {
175*2882Svi117747 	return (sip_parse_hdr_parser3(sip_header, header, SIP_STR_VAL, B_TRUE));
176*2882Svi117747 }
177*2882Svi117747 
178*2882Svi117747 /*
179*2882Svi117747  * Content-Disposition = "Content-Disposition" HCOLON disp-type *
180*2882Svi117747  *			(SEMI disp-param)
181*2882Svi117747  * disp-type = "render" | "session" | "icon" | "alert" | disp-ext-token
182*2882Svi117747  * disp-param = handling-param | generic-param
183*2882Svi117747  * handling-param = "handling" EQUAL("optional" | "required" | other-handling)
184*2882Svi117747  * other-handling = token
185*2882Svi117747  * disp-ext-token = token
186*2882Svi117747  *
187*2882Svi117747  */
188*2882Svi117747 int
189*2882Svi117747 sip_parse_contentdis_header(_sip_header_t *sip_header,
190*2882Svi117747     sip_parsed_header_t **header)
191*2882Svi117747 {
192*2882Svi117747 	return (sip_parse_hdr_parser1(sip_header, header, (char)NULL));
193*2882Svi117747 }
194*2882Svi117747 
195*2882Svi117747 /*
196*2882Svi117747  * Content-Encoding = ("Content-Encoding" | "e") HCOLON content-coding *
197*2882Svi117747  *			(COMMA content-coding)
198*2882Svi117747  */
199*2882Svi117747 int
200*2882Svi117747 sip_parse_contentencode_header(_sip_header_t *sip_header,
201*2882Svi117747     sip_parsed_header_t **header)
202*2882Svi117747 {
203*2882Svi117747 	return (sip_parse_hdr_parser1(sip_header, header, (char)NULL));
204*2882Svi117747 }
205*2882Svi117747 
206*2882Svi117747 /*
207*2882Svi117747  * Content-Language = ("Content-Language" | "l") HCOLON lang-tag *
208*2882Svi117747  *		 (COMMA lang-tag)
209*2882Svi117747  * lang-tag = primary-tag *("-" subtag)
210*2882Svi117747  * prmary-tag = 1*8ALPHA
211*2882Svi117747  * subtag = 1*8ALPHA
212*2882Svi117747  */
213*2882Svi117747 int
214*2882Svi117747 sip_parse_contentlang_header(_sip_header_t *sip_header,
215*2882Svi117747     sip_parsed_header_t **header)
216*2882Svi117747 {
217*2882Svi117747 	return (sip_parse_hdr_parser1(sip_header, header, (char)NULL));
218*2882Svi117747 }
219*2882Svi117747 
220*2882Svi117747 /*
221*2882Svi117747  * Date = "Date" HCOLON SIPdate
222*2882Svi117747  * SIPdate = wkday "," SP date1 SP time SP "GMT"
223*2882Svi117747  * date1 = 2DIGIT SP mnth SP 4DIGIT; day month year
224*2882Svi117747  * time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
225*2882Svi117747  * wkday = "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun"
226*2882Svi117747  * month = "Jan" | "Feb" etc
227*2882Svi117747  */
228*2882Svi117747 int
229*2882Svi117747 sip_parse_date_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
230*2882Svi117747 {
231*2882Svi117747 	sip_parsed_header_t	*parsed_header;
232*2882Svi117747 	int			 r;
233*2882Svi117747 	sip_hdr_value_t		*value = NULL;
234*2882Svi117747 
235*2882Svi117747 	if ((r = sip_prim_parsers(sip_header, header)) != 0)
236*2882Svi117747 		return (r);
237*2882Svi117747 
238*2882Svi117747 	if (*header != NULL)
239*2882Svi117747 		return (0);
240*2882Svi117747 
241*2882Svi117747 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
242*2882Svi117747 	if (parsed_header == NULL)
243*2882Svi117747 		return (ENOMEM);
244*2882Svi117747 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
245*2882Svi117747 	parsed_header->sip_header = sip_header;
246*2882Svi117747 
247*2882Svi117747 	value = calloc(1, sizeof (sip_hdr_value_t));
248*2882Svi117747 	if (value == NULL) {
249*2882Svi117747 		sip_free_phdr(parsed_header);
250*2882Svi117747 		return (ENOMEM);
251*2882Svi117747 	}
252*2882Svi117747 	parsed_header->value = (sip_value_t *)value;
253*2882Svi117747 
254*2882Svi117747 	value->sip_value_start = sip_header->sip_hdr_current;
255*2882Svi117747 	value->sip_value_header = parsed_header;
256*2882Svi117747 	value->date_wd_ptr = sip_header->sip_hdr_current;
257*2882Svi117747 	if (sip_find_token(sip_header, SIP_COMMA) == 0) {
258*2882Svi117747 		value->date_wd_len = sip_header->sip_hdr_current -
259*2882Svi117747 		    value->date_wd_ptr - 1;
260*2882Svi117747 		sip_header->sip_hdr_current++;
261*2882Svi117747 		if (sip_skip_white_space(sip_header) != 0) {
262*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
263*2882Svi117747 			return (EPROTO);
264*2882Svi117747 		}
265*2882Svi117747 	} else {
266*2882Svi117747 		value->sip_value_state = SIP_VALUE_BAD;
267*2882Svi117747 		return (EPROTO);
268*2882Svi117747 	}
269*2882Svi117747 
270*2882Svi117747 	if (sip_skip_white_space(sip_header) != 0) {
271*2882Svi117747 		value->sip_value_state = SIP_VALUE_BAD;
272*2882Svi117747 		return (EPROTO);
273*2882Svi117747 	}
274*2882Svi117747 	r = sip_atoi(sip_header, &value->date_d);
275*2882Svi117747 	if (r != 0 || value->date_d < 0 || value->date_d > 31) {
276*2882Svi117747 		value->sip_value_state = SIP_VALUE_BAD;
277*2882Svi117747 		return (EPROTO);
278*2882Svi117747 	}
279*2882Svi117747 	if (sip_skip_white_space(sip_header) != 0) {
280*2882Svi117747 		value->sip_value_state = SIP_VALUE_BAD;
281*2882Svi117747 		return (EPROTO);
282*2882Svi117747 	}
283*2882Svi117747 	value->date_m_ptr = sip_header->sip_hdr_current;
284*2882Svi117747 	if (sip_find_token(sip_header, SIP_SP) == 0) {
285*2882Svi117747 		value->date_m_len = sip_header->sip_hdr_current -
286*2882Svi117747 		    value->date_m_ptr - 1;
287*2882Svi117747 	} else {
288*2882Svi117747 		value->sip_value_state = SIP_VALUE_BAD;
289*2882Svi117747 		return (EPROTO);
290*2882Svi117747 	}
291*2882Svi117747 
292*2882Svi117747 	r = sip_atoi(sip_header, &value->date_y);
293*2882Svi117747 	if (r != 0 || value->date_y < 0) {
294*2882Svi117747 		value->sip_value_state = SIP_VALUE_BAD;
295*2882Svi117747 		return (EPROTO);
296*2882Svi117747 	}
297*2882Svi117747 	if (sip_skip_white_space(sip_header) != 0) {
298*2882Svi117747 		value->sip_value_state = SIP_VALUE_BAD;
299*2882Svi117747 		return (EPROTO);
300*2882Svi117747 	}
301*2882Svi117747 	value->date_t_ptr = sip_header->sip_hdr_current;
302*2882Svi117747 	if (sip_find_token(sip_header, SIP_SP) == 0) {
303*2882Svi117747 		value->date_t_len = sip_header->sip_hdr_current -
304*2882Svi117747 		    value->date_t_ptr - 1;
305*2882Svi117747 	} else {
306*2882Svi117747 		value->sip_value_state = SIP_VALUE_BAD;
307*2882Svi117747 		return (EPROTO);
308*2882Svi117747 	}
309*2882Svi117747 
310*2882Svi117747 	value->date_tz_ptr =  sip_header->sip_hdr_current;
311*2882Svi117747 	/*
312*2882Svi117747 	 * minus 2 to get rid of the CRLF
313*2882Svi117747 	 */
314*2882Svi117747 	value->date_tz_len = sip_header->sip_hdr_end -
315*2882Svi117747 	    sip_header->sip_hdr_current - 2;
316*2882Svi117747 
317*2882Svi117747 	*header = parsed_header;
318*2882Svi117747 
319*2882Svi117747 	sip_header->sip_hdr_parsed = *header;
320*2882Svi117747 	return (0);
321*2882Svi117747 }
322*2882Svi117747 
323*2882Svi117747 /*
324*2882Svi117747  * Error-Info = "Error-Info" HCOLON error-uri *(COMMA error-uri)
325*2882Svi117747  * error-uri = LAQUOT absoluteURI RAQUOT *(SEMI generic-param)
326*2882Svi117747  */
327*2882Svi117747 int
328*2882Svi117747 sip_parse_errorinfo_header(_sip_header_t *sip_header,
329*2882Svi117747     sip_parsed_header_t **header)
330*2882Svi117747 {
331*2882Svi117747 	return (sip_parse_hdr_parser3(sip_header, header, SIP_STR_VAL, B_TRUE));
332*2882Svi117747 }
333*2882Svi117747 
334*2882Svi117747 /*
335*2882Svi117747  * Expires = "Expires" HCOLON delta-seconds
336*2882Svi117747  */
337*2882Svi117747 int
338*2882Svi117747 sip_parse_expire_header(_sip_header_t *sip_header,
339*2882Svi117747     sip_parsed_header_t **header)
340*2882Svi117747 {
341*2882Svi117747 	return (sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL));
342*2882Svi117747 }
343*2882Svi117747 
344*2882Svi117747 /*
345*2882Svi117747  * In-Reply-To = "In-Reply-To" HCOLON callid *(COMMA callid)
346*2882Svi117747  */
347*2882Svi117747 int
348*2882Svi117747 sip_parse_inreplyto_header(_sip_header_t *sip_header,
349*2882Svi117747     sip_parsed_header_t **header)
350*2882Svi117747 {
351*2882Svi117747 	return (sip_parse_hdr_parser1(sip_header, header, (char)NULL));
352*2882Svi117747 }
353*2882Svi117747 
354*2882Svi117747 /*
355*2882Svi117747  * RSeq = "RSeq" HCOLON response-num
356*2882Svi117747  */
357*2882Svi117747 int
358*2882Svi117747 sip_parse_rseq(_sip_header_t *sip_header, sip_parsed_header_t **header)
359*2882Svi117747 {
360*2882Svi117747 	int		r;
361*2882Svi117747 	sip_hdr_value_t	*rseq_value;
362*2882Svi117747 
363*2882Svi117747 	r = sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL);
364*2882Svi117747 	/*
365*2882Svi117747 	 * Additionally, a value of 0 is bad_value
366*2882Svi117747 	 */
367*2882Svi117747 	if (sip_header->sip_hdr_parsed != NULL &&
368*2882Svi117747 	    sip_header->sip_hdr_parsed->value != NULL) {
369*2882Svi117747 		rseq_value = (sip_hdr_value_t *)
370*2882Svi117747 		    sip_header->sip_hdr_parsed->value;
371*2882Svi117747 		if (rseq_value->int_val == 0)
372*2882Svi117747 			rseq_value->sip_value_state = SIP_VALUE_BAD;
373*2882Svi117747 	}
374*2882Svi117747 	return (r);
375*2882Svi117747 }
376*2882Svi117747 
377*2882Svi117747 /*
378*2882Svi117747  * Min-Expires  =  "Min-Expires" HCOLON delta-seconds
379*2882Svi117747  */
380*2882Svi117747 int
381*2882Svi117747 sip_parse_minexpire_header(_sip_header_t *sip_header,
382*2882Svi117747     sip_parsed_header_t **header)
383*2882Svi117747 {
384*2882Svi117747 	return (sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL));
385*2882Svi117747 }
386*2882Svi117747 
387*2882Svi117747 /*
388*2882Svi117747  * MIME-Version = "MIME-Version" HCOLON 1*DIGIT "." 1*DIGIT
389*2882Svi117747  */
390*2882Svi117747 int
391*2882Svi117747 sip_parse_mimeversion_header(_sip_header_t *sip_header,
392*2882Svi117747     sip_parsed_header_t **header)
393*2882Svi117747 {
394*2882Svi117747 	return (sip_parse_hdr_parser4(sip_header, header));
395*2882Svi117747 }
396*2882Svi117747 
397*2882Svi117747 /*
398*2882Svi117747  * Organization = "Organization" HCOLON [TEXT-UTF8-TRIM]
399*2882Svi117747  */
400*2882Svi117747 int
401*2882Svi117747 sip_parse_org_header(_sip_header_t *sip_header,
402*2882Svi117747     sip_parsed_header_t **header)
403*2882Svi117747 {
404*2882Svi117747 	if (sip_is_empty_hdr(sip_header))
405*2882Svi117747 		return (sip_parse_hdr_empty(sip_header, header));
406*2882Svi117747 	return (sip_parse_hdr_parser4(sip_header, header));
407*2882Svi117747 }
408*2882Svi117747 
409*2882Svi117747 /*
410*2882Svi117747  * Priority = "Priority" HCOLON priority-val
411*2882Svi117747  * priority-val = "emergency" | "urgent" | "normal" | "non-urgent" | other
412*2882Svi117747  * other = token
413*2882Svi117747  */
414*2882Svi117747 int
415*2882Svi117747 sip_parse_priority_header(_sip_header_t *sip_header,
416*2882Svi117747     sip_parsed_header_t **header)
417*2882Svi117747 {
418*2882Svi117747 	return (sip_parse_hdr_parser4(sip_header, header));
419*2882Svi117747 }
420*2882Svi117747 
421*2882Svi117747 /*
422*2882Svi117747  * Reply-To = "Reply-To" HCOLON rplyto-spec
423*2882Svi117747  * rplyto-spec = (name-addr | addr-spec) *(SEMI rplyto-param)
424*2882Svi117747  * rplyto-param = generic-param
425*2882Svi117747  * name-addr = [ display-name ] LAQUOT addr-spec RAQUOT
426*2882Svi117747  * addr-spec = SIP-URI | SIPS-URI | absolute URI
427*2882Svi117747  */
428*2882Svi117747 int
429*2882Svi117747 sip_parse_replyto_header(_sip_header_t *sip_header,
430*2882Svi117747     sip_parsed_header_t **header)
431*2882Svi117747 {
432*2882Svi117747 	return (sip_parse_hdr_parser3(sip_header, header, SIP_STRS_VAL,
433*2882Svi117747 	    B_TRUE));
434*2882Svi117747 }
435*2882Svi117747 
436*2882Svi117747 /*
437*2882Svi117747  * PRIVACY = "Privacy" HCOLON priv-value *(COMMA priv-value)
438*2882Svi117747  * priv-value   =   "header" / "session" / "user" / "none" / "critical"
439*2882Svi117747  *                  / token / id
440*2882Svi117747  */
441*2882Svi117747 int
442*2882Svi117747 sip_parse_privacy_header(_sip_header_t *sip_header,
443*2882Svi117747     sip_parsed_header_t **header)
444*2882Svi117747 {
445*2882Svi117747 	return (sip_parse_hdr_parser1(sip_header, header, (char)NULL));
446*2882Svi117747 }
447*2882Svi117747 
448*2882Svi117747 
449*2882Svi117747 /*
450*2882Svi117747  * Require = "Require" HCOLON option-tag * (COMMA option-tag)
451*2882Svi117747  */
452*2882Svi117747 int
453*2882Svi117747 sip_parse_require_header(_sip_header_t *sip_header,
454*2882Svi117747     sip_parsed_header_t **header)
455*2882Svi117747 {
456*2882Svi117747 	return (sip_parse_hdr_parser1(sip_header, header, (char)NULL));
457*2882Svi117747 }
458*2882Svi117747 
459*2882Svi117747 /*
460*2882Svi117747  * Retry-After = "Retry-After" HCOLON delta-seconds [ comment ] *
461*2882Svi117747  *		(SEMI retry-param)
462*2882Svi117747  * retry-param = "duration" EQUAL delta-seconds
463*2882Svi117747  */
464*2882Svi117747 int
465*2882Svi117747 sip_parse_retryaft_header(_sip_header_t *sip_header,
466*2882Svi117747     sip_parsed_header_t **header)
467*2882Svi117747 {
468*2882Svi117747 	sip_parsed_header_t	*parsed_header;
469*2882Svi117747 	sip_hdr_value_t		*value = NULL;
470*2882Svi117747 	int			ret;
471*2882Svi117747 
472*2882Svi117747 	if ((ret = sip_prim_parsers(sip_header, header)) != 0)
473*2882Svi117747 		return (ret);
474*2882Svi117747 
475*2882Svi117747 	if (*header != NULL)
476*2882Svi117747 		return (0);
477*2882Svi117747 
478*2882Svi117747 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
479*2882Svi117747 	if (parsed_header == NULL)
480*2882Svi117747 		return (ENOMEM);
481*2882Svi117747 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
482*2882Svi117747 	parsed_header->sip_header = sip_header;
483*2882Svi117747 
484*2882Svi117747 	value = calloc(1, sizeof (sip_hdr_value_t));
485*2882Svi117747 	if (value == NULL) {
486*2882Svi117747 		sip_free_phdr(parsed_header);
487*2882Svi117747 		return (ENOMEM);
488*2882Svi117747 	}
489*2882Svi117747 
490*2882Svi117747 	parsed_header->value = (sip_value_t *)value;
491*2882Svi117747 	value->sip_value_start = sip_header->sip_hdr_current;
492*2882Svi117747 	value->sip_value_header = parsed_header;
493*2882Svi117747 
494*2882Svi117747 	ret = sip_atoi(sip_header, &(value->intstr_int));
495*2882Svi117747 	if (ret != 0)
496*2882Svi117747 		value->sip_value_state = SIP_VALUE_BAD;
497*2882Svi117747 	if (sip_find_token(sip_header, SIP_LPAR) == 0) {
498*2882Svi117747 		value->intstr_str_ptr = sip_header->sip_hdr_current;
499*2882Svi117747 		if (sip_find_token(sip_header, SIP_RPAR) == 0) {
500*2882Svi117747 			value->intstr_str_len =
501*2882Svi117747 			    sip_header->sip_hdr_current -
502*2882Svi117747 				value->intstr_str_ptr - 1;
503*2882Svi117747 			if (sip_find_token(sip_header, SIP_SEMI) == 0) {
504*2882Svi117747 				sip_header->sip_hdr_current--;
505*2882Svi117747 				(void) sip_parse_params(sip_header,
506*2882Svi117747 				    &(value->sip_param_list));
507*2882Svi117747 			}
508*2882Svi117747 		} else {
509*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
510*2882Svi117747 			return (EPROTO);
511*2882Svi117747 		}
512*2882Svi117747 	} else {
513*2882Svi117747 		value->intstr_str_ptr = NULL;
514*2882Svi117747 		value->intstr_str_len = 0;
515*2882Svi117747 
516*2882Svi117747 		/*
517*2882Svi117747 		 * from value start, search if parameter list
518*2882Svi117747 		 */
519*2882Svi117747 		sip_header->sip_hdr_current = value->sip_value_start;
520*2882Svi117747 		if (sip_find_token(sip_header, SIP_SEMI) == 0) {
521*2882Svi117747 			sip_header->sip_hdr_current--;
522*2882Svi117747 			(void) sip_parse_params(sip_header,
523*2882Svi117747 			    &(value->sip_param_list));
524*2882Svi117747 		}
525*2882Svi117747 	}
526*2882Svi117747 
527*2882Svi117747 	*header = parsed_header;
528*2882Svi117747 	sip_header->sip_hdr_parsed = *header;
529*2882Svi117747 	return (0);
530*2882Svi117747 }
531*2882Svi117747 
532*2882Svi117747 /*
533*2882Svi117747  * Server = "Server" HCOLON servel-val *(LWS server-val)
534*2882Svi117747  * servel-val = product|comment
535*2882Svi117747  * product = token [SLASH version]
536*2882Svi117747  * version = token
537*2882Svi117747  * Treated as one single string
538*2882Svi117747  */
539*2882Svi117747 int
540*2882Svi117747 sip_parse_server_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
541*2882Svi117747 {
542*2882Svi117747 	return (sip_parse_hdr_parser4(sip_header, header));
543*2882Svi117747 }
544*2882Svi117747 
545*2882Svi117747 /*
546*2882Svi117747  * Subject = ("Subject" | "s")HCOLON [TEXT-UTF8-TRIM]
547*2882Svi117747  */
548*2882Svi117747 int
549*2882Svi117747 sip_parse_subject_header(_sip_header_t *sip_header,
550*2882Svi117747     sip_parsed_header_t **header)
551*2882Svi117747 {
552*2882Svi117747 	if (sip_is_empty_hdr(sip_header))
553*2882Svi117747 		return (sip_parse_hdr_empty(sip_header, header));
554*2882Svi117747 	return (sip_parse_hdr_parser4(sip_header, header));
555*2882Svi117747 }
556*2882Svi117747 
557*2882Svi117747 /*
558*2882Svi117747  * Supported = ("Supported" | "k") HCOLON [option-tag * (COMMA option-tag) ]
559*2882Svi117747  */
560*2882Svi117747 int
561*2882Svi117747 sip_parse_support_header(_sip_header_t *sip_header,
562*2882Svi117747     sip_parsed_header_t **header)
563*2882Svi117747 {
564*2882Svi117747 	if (sip_is_empty_hdr(sip_header))
565*2882Svi117747 		return (sip_parse_hdr_empty(sip_header, header));
566*2882Svi117747 	return (sip_parse_hdr_parser1(sip_header, header, (char)NULL));
567*2882Svi117747 }
568*2882Svi117747 
569*2882Svi117747 /*
570*2882Svi117747  * Timestamp = "Timestamp" HCOLON 1*DIGIT ["." *(DIGIT)] [LWS delay]
571*2882Svi117747  */
572*2882Svi117747 int
573*2882Svi117747 sip_parse_timestamp_header(_sip_header_t *sip_header,
574*2882Svi117747     sip_parsed_header_t **header)
575*2882Svi117747 {
576*2882Svi117747 	sip_parsed_header_t	*parsed_header;
577*2882Svi117747 	sip_hdr_value_t		*value = NULL;
578*2882Svi117747 	int			ret;
579*2882Svi117747 
580*2882Svi117747 	if ((ret = sip_prim_parsers(sip_header, header)) != 0)
581*2882Svi117747 		return (ret);
582*2882Svi117747 
583*2882Svi117747 	if (*header != NULL)
584*2882Svi117747 		return (0);
585*2882Svi117747 
586*2882Svi117747 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
587*2882Svi117747 	if (parsed_header == NULL)
588*2882Svi117747 		return (ENOMEM);
589*2882Svi117747 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
590*2882Svi117747 	parsed_header->sip_header = sip_header;
591*2882Svi117747 
592*2882Svi117747 	value = calloc(1, sizeof (sip_hdr_value_t));
593*2882Svi117747 	if (value == NULL) {
594*2882Svi117747 		sip_free_phdr(parsed_header);
595*2882Svi117747 		return (ENOMEM);
596*2882Svi117747 	}
597*2882Svi117747 	parsed_header->value = (sip_value_t *)value;
598*2882Svi117747 
599*2882Svi117747 	value->sip_value_start = sip_header->sip_hdr_current;
600*2882Svi117747 	value->sip_value_header = parsed_header;
601*2882Svi117747 
602*2882Svi117747 	if (sip_skip_white_space(sip_header) != 0) {
603*2882Svi117747 		value->sip_value_state = SIP_VALUE_BAD;
604*2882Svi117747 		return (EPROTO);
605*2882Svi117747 	}
606*2882Svi117747 	value->strs1_val_ptr = sip_header->sip_hdr_current;
607*2882Svi117747 
608*2882Svi117747 	if (sip_find_white_space(sip_header) == 0) {
609*2882Svi117747 		/*
610*2882Svi117747 		 * timestamp and delay, timestamp in str1, delay in str2
611*2882Svi117747 		 */
612*2882Svi117747 		value->strs1_val_len = sip_header->sip_hdr_current -
613*2882Svi117747 		    value->strs1_val_ptr;
614*2882Svi117747 		(void) sip_skip_white_space(sip_header);
615*2882Svi117747 
616*2882Svi117747 		value->strs2_val_ptr = sip_header->sip_hdr_current;
617*2882Svi117747 		if (sip_find_cr(sip_header) != 0) {
618*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
619*2882Svi117747 			return (EPROTO);
620*2882Svi117747 		}
621*2882Svi117747 		if (sip_header->sip_hdr_current < value->strs2_val_ptr) {
622*2882Svi117747 			value->strs2_val_ptr = NULL;
623*2882Svi117747 			value->strs2_val_len = 0;
624*2882Svi117747 		} else {
625*2882Svi117747 			value->strs2_val_len = sip_header->sip_hdr_current -
626*2882Svi117747 			    value->strs2_val_ptr;
627*2882Svi117747 		}
628*2882Svi117747 	} else {
629*2882Svi117747 		/*
630*2882Svi117747 		 * no delay information
631*2882Svi117747 		 */
632*2882Svi117747 		value->strs1_val_len = sip_header->sip_hdr_current
633*2882Svi117747 		    - value->strs1_val_ptr;
634*2882Svi117747 		value->strs2_val_ptr = NULL;
635*2882Svi117747 		value->strs2_val_len = 0;
636*2882Svi117747 	}
637*2882Svi117747 
638*2882Svi117747 	*header = parsed_header;
639*2882Svi117747 	sip_header->sip_hdr_parsed = *header;
640*2882Svi117747 
641*2882Svi117747 	return (0);
642*2882Svi117747 }
643*2882Svi117747 /*
644*2882Svi117747  * Unsupported = "Unsupported" HCOLON option-tag * (COMMA option-tag)
645*2882Svi117747  */
646*2882Svi117747 int
647*2882Svi117747 sip_parse_usupport_header(_sip_header_t *sip_header,
648*2882Svi117747     sip_parsed_header_t **header)
649*2882Svi117747 {
650*2882Svi117747 	return (sip_parse_hdr_parser1(sip_header, header, (char)NULL));
651*2882Svi117747 }
652*2882Svi117747 
653*2882Svi117747 /*
654*2882Svi117747  * User-Agent = "User-Agent" HCOLON server-val * (LWS server-val)
655*2882Svi117747  * servel-val = product |comment
656*2882Svi117747  * product = token [SLASH version]
657*2882Svi117747  * version = token
658*2882Svi117747  */
659*2882Svi117747 int
660*2882Svi117747 sip_parse_useragt_header(_sip_header_t *sip_header,
661*2882Svi117747     sip_parsed_header_t **header)
662*2882Svi117747 {
663*2882Svi117747 	return (sip_parse_hdr_parser4(sip_header, header));
664*2882Svi117747 }
665*2882Svi117747 
666*2882Svi117747 /*
667*2882Svi117747  * Warning = "Warning" HCOLON warning-value *(COMMA warning-value)
668*2882Svi117747  * warning-value = warn-code SP warn-agent SP warn-text
669*2882Svi117747  * warn-code = 3DIGIT
670*2882Svi117747  * warn-agent = hostport | pseudonym ;
671*2882Svi117747  *		 the name or pseudonym of the server adding;
672*2882Svi117747  *		 the Warning header, for use in debugging
673*2882Svi117747  * warn-text = quoted-string
674*2882Svi117747  * pseudonym = token
675*2882Svi117747  */
676*2882Svi117747 int
677*2882Svi117747 sip_parse_warn_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
678*2882Svi117747 {
679*2882Svi117747 	sip_parsed_header_t	*parsed_header;
680*2882Svi117747 	int			ret;
681*2882Svi117747 	sip_hdr_value_t		*value = NULL;
682*2882Svi117747 	sip_hdr_value_t		*last_value = NULL;
683*2882Svi117747 
684*2882Svi117747 	if ((ret = sip_prim_parsers(sip_header, header)) != 0)
685*2882Svi117747 		return (ret);
686*2882Svi117747 
687*2882Svi117747 	if (*header != NULL)
688*2882Svi117747 		return (0);
689*2882Svi117747 
690*2882Svi117747 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
691*2882Svi117747 	if (parsed_header == NULL)
692*2882Svi117747 		return (ENOMEM);
693*2882Svi117747 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
694*2882Svi117747 	parsed_header->sip_header = sip_header;
695*2882Svi117747 
696*2882Svi117747 	while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
697*2882Svi117747 		value = calloc(1, sizeof (sip_hdr_value_t));
698*2882Svi117747 		if (value == NULL) {
699*2882Svi117747 			sip_free_phdr(parsed_header);
700*2882Svi117747 			return (ENOMEM);
701*2882Svi117747 		}
702*2882Svi117747 
703*2882Svi117747 		if (last_value != NULL)
704*2882Svi117747 			last_value->sip_next_value = value;
705*2882Svi117747 		else
706*2882Svi117747 			parsed_header->value = (sip_value_t *)value;
707*2882Svi117747 
708*2882Svi117747 		value->sip_value_start = sip_header->sip_hdr_current;
709*2882Svi117747 		value->sip_value_header = parsed_header;
710*2882Svi117747 
711*2882Svi117747 		ret = sip_atoi(sip_header, &value->warn_code);
712*2882Svi117747 		if (ret != 0 || value->warn_code < 100 ||
713*2882Svi117747 		    value->warn_code > 999) {
714*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
715*2882Svi117747 			goto get_next_val;
716*2882Svi117747 		}
717*2882Svi117747 		if (sip_skip_white_space(sip_header) != 0) {
718*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
719*2882Svi117747 			goto get_next_val;
720*2882Svi117747 		}
721*2882Svi117747 		value->warn_agt_ptr = sip_header->sip_hdr_current;
722*2882Svi117747 
723*2882Svi117747 		if (sip_find_token(sip_header, SIP_QUOTE) == 0) {
724*2882Svi117747 			/*
725*2882Svi117747 			 * get warning agent
726*2882Svi117747 			 */
727*2882Svi117747 			sip_header->sip_hdr_current--;
728*2882Svi117747 			(void) sip_reverse_skip_white_space(sip_header);
729*2882Svi117747 			value->warn_agt_len = sip_header->sip_hdr_current -
730*2882Svi117747 			    value->warn_agt_ptr - 1;
731*2882Svi117747 			if (value->warn_agt_len <= 0) {
732*2882Svi117747 				value->warn_agt_ptr = NULL;
733*2882Svi117747 				value->sip_value_state = SIP_VALUE_BAD;
734*2882Svi117747 			}
735*2882Svi117747 
736*2882Svi117747 			/*
737*2882Svi117747 			 * We will have a  SIP_QUOTE here
738*2882Svi117747 			 */
739*2882Svi117747 			(void) sip_find_token(sip_header, SIP_QUOTE);
740*2882Svi117747 
741*2882Svi117747 			value->warn_text_ptr =  sip_header->sip_hdr_current;
742*2882Svi117747 			if (sip_find_token(sip_header, SIP_QUOTE) == 0) {
743*2882Svi117747 				value->warn_text_len =
744*2882Svi117747 				    sip_header->sip_hdr_current -
745*2882Svi117747 					value->warn_text_ptr - 1;
746*2882Svi117747 			} else {
747*2882Svi117747 				value->sip_value_state = SIP_VALUE_BAD;
748*2882Svi117747 				goto get_next_val;
749*2882Svi117747 			}
750*2882Svi117747 		} else
751*2882Svi117747 			/*
752*2882Svi117747 			 * warning text must present
753*2882Svi117747 			 */
754*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
755*2882Svi117747 
756*2882Svi117747 get_next_val:
757*2882Svi117747 		if (sip_find_token(sip_header, SIP_COMMA) != 0)
758*2882Svi117747 			break;
759*2882Svi117747 		value->sip_value_end = sip_header->sip_hdr_current - 1;
760*2882Svi117747 		last_value = value;
761*2882Svi117747 		(void) sip_skip_white_space(sip_header);
762*2882Svi117747 	}
763*2882Svi117747 
764*2882Svi117747 	*header = parsed_header;
765*2882Svi117747 
766*2882Svi117747 	sip_header->sip_hdr_parsed = *header;
767*2882Svi117747 	return (0);
768*2882Svi117747 }
769*2882Svi117747 
770*2882Svi117747 /*
771*2882Svi117747  * Parse RAck header
772*2882Svi117747  * "RAck" HCOLON response-num LWS CSeq-num LWS Method
773*2882Svi117747  * response-num  =  1*DIGIT
774*2882Svi117747  * CSeq-num      =  1*DIGIT
775*2882Svi117747  */
776*2882Svi117747 int
777*2882Svi117747 sip_parse_rack(_sip_header_t *sip_header, sip_parsed_header_t **header)
778*2882Svi117747 {
779*2882Svi117747 	sip_parsed_header_t	*parsed_header;
780*2882Svi117747 	sip_hdr_value_t		*rack_value;
781*2882Svi117747 	int			len;
782*2882Svi117747 	char			*tmp_ptr;
783*2882Svi117747 	int			i;
784*2882Svi117747 	int			ret;
785*2882Svi117747 
786*2882Svi117747 	if ((ret = sip_prim_parsers(sip_header, header)) != 0)
787*2882Svi117747 		return (ret);
788*2882Svi117747 
789*2882Svi117747 	if (*header != NULL)
790*2882Svi117747 		return (0);
791*2882Svi117747 
792*2882Svi117747 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
793*2882Svi117747 	if (parsed_header == NULL)
794*2882Svi117747 		return (ENOMEM);
795*2882Svi117747 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
796*2882Svi117747 	parsed_header->sip_header = sip_header;
797*2882Svi117747 
798*2882Svi117747 	parsed_header->value =  calloc(1, sizeof (sip_hdr_value_t));
799*2882Svi117747 	if (parsed_header->value == NULL) {
800*2882Svi117747 		free(parsed_header);
801*2882Svi117747 		return (ENOMEM);
802*2882Svi117747 	}
803*2882Svi117747 	rack_value = (sip_hdr_value_t *)parsed_header->value;
804*2882Svi117747 	rack_value->sip_value_version = SIP_VALUE_VERSION_1;
805*2882Svi117747 	rack_value->sip_value_start = sip_header->sip_hdr_current;
806*2882Svi117747 	rack_value->sip_value_header = parsed_header;
807*2882Svi117747 	if (sip_atoi(sip_header, &rack_value->rack_resp) ||
808*2882Svi117747 	    rack_value->rack_resp == 0) {
809*2882Svi117747 		rack_value->sip_value_state = SIP_VALUE_BAD;
810*2882Svi117747 		rack_value->sip_value_end = sip_header->sip_hdr_end - 2;
811*2882Svi117747 		goto rack_parse_done;
812*2882Svi117747 	}
813*2882Svi117747 	rack_value->sip_value_header = parsed_header;
814*2882Svi117747 	/*
815*2882Svi117747 	 * Get cseq.
816*2882Svi117747 	 */
817*2882Svi117747 	if (sip_skip_white_space(sip_header) != 0) {
818*2882Svi117747 		rack_value->sip_value_state = SIP_VALUE_BAD;
819*2882Svi117747 		rack_value->sip_value_end = sip_header->sip_hdr_end - 2;
820*2882Svi117747 		goto rack_parse_done;
821*2882Svi117747 	}
822*2882Svi117747 	if (sip_atoi(sip_header, &rack_value->rack_cseq)) {
823*2882Svi117747 		rack_value->sip_value_state = SIP_VALUE_BAD;
824*2882Svi117747 		rack_value->sip_value_end = sip_header->sip_hdr_end - 2;
825*2882Svi117747 		goto rack_parse_done;
826*2882Svi117747 	}
827*2882Svi117747 	/*
828*2882Svi117747 	 * Get method.
829*2882Svi117747 	 */
830*2882Svi117747 	if (sip_skip_white_space(sip_header) != 0) {
831*2882Svi117747 		rack_value->sip_value_state = SIP_VALUE_BAD;
832*2882Svi117747 		rack_value->sip_value_end = sip_header->sip_hdr_end - 2;
833*2882Svi117747 		goto rack_parse_done;
834*2882Svi117747 	}
835*2882Svi117747 
836*2882Svi117747 	tmp_ptr = sip_header->sip_hdr_current;
837*2882Svi117747 	if (sip_find_white_space(sip_header)) {
838*2882Svi117747 		rack_value->sip_value_state = SIP_VALUE_BAD;
839*2882Svi117747 		rack_value->sip_value_end = sip_header->sip_hdr_end - 2;
840*2882Svi117747 		goto rack_parse_done;
841*2882Svi117747 	}
842*2882Svi117747 
843*2882Svi117747 	len = sip_header->sip_hdr_current - tmp_ptr;
844*2882Svi117747 
845*2882Svi117747 	for (i = 1; i < MAX_SIP_METHODS; i++) {
846*2882Svi117747 		if (strncmp(sip_methods[i].name, tmp_ptr, len) == 0)
847*2882Svi117747 			break;
848*2882Svi117747 	}
849*2882Svi117747 
850*2882Svi117747 	if (i >= MAX_SIP_METHODS) {
851*2882Svi117747 		rack_value->sip_value_state = SIP_VALUE_BAD;
852*2882Svi117747 		rack_value->sip_value_end = sip_header->sip_hdr_end - 2;
853*2882Svi117747 		goto rack_parse_done;
854*2882Svi117747 	}
855*2882Svi117747 
856*2882Svi117747 	rack_value->rack_method = i;
857*2882Svi117747 	rack_value->sip_value_end = sip_header->sip_hdr_current;
858*2882Svi117747 
859*2882Svi117747 rack_parse_done:
860*2882Svi117747 	sip_header->sip_hdr_parsed = parsed_header;
861*2882Svi117747 
862*2882Svi117747 	*header = parsed_header;
863*2882Svi117747 	return (0);
864*2882Svi117747 }
865*2882Svi117747 
866*2882Svi117747 /*
867*2882Svi117747  * Allow  =  "Allow" HCOLON [Method *(COMMA Method)]
868*2882Svi117747  */
869*2882Svi117747 int
870*2882Svi117747 sip_parse_allow_events_header(_sip_header_t *sip_header,
871*2882Svi117747     sip_parsed_header_t **header)
872*2882Svi117747 {
873*2882Svi117747 	return (sip_parse_hdr_parser1(sip_header, header, (char)NULL));
874*2882Svi117747 }
875*2882Svi117747 
876*2882Svi117747 /*
877*2882Svi117747  * Event             =  ( "Event" / "o" ) HCOLON event-type
878*2882Svi117747  *			*( SEMI event-param )
879*2882Svi117747  * event-type        =  event-package *( "." event-template )
880*2882Svi117747  * event-package     =  token-nodot
881*2882Svi117747  * event-template    =  token-nodot
882*2882Svi117747  * token-nodot       =  1*( alphanum / "-"  / "!" / "%" / "*"
883*2882Svi117747  *			/ "_" / "+" / "`" / "'" / "~" )
884*2882Svi117747  * event-param       =  generic-param / ( "id" EQUAL token )
885*2882Svi117747  */
886*2882Svi117747 int
887*2882Svi117747 sip_parse_event_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
888*2882Svi117747 {
889*2882Svi117747 	return (sip_parse_hdr_parser1(sip_header, header, (char)NULL));
890*2882Svi117747 }
891*2882Svi117747 
892*2882Svi117747 /*
893*2882Svi117747  * Subscription-State   = "Subscription-State" HCOLON substate-value
894*2882Svi117747  * 			*( SEMI subexp-params )
895*2882Svi117747  * substate-value       = "active" / "pending" / "terminated"
896*2882Svi117747  *			/ extension-substate
897*2882Svi117747  * extension-substate   = token
898*2882Svi117747  * subexp-params        =   ("reason" EQUAL event-reason-value)
899*2882Svi117747  *			/ ("expires" EQUAL delta-seconds)*
900*2882Svi117747  * 			/ ("retry-after" EQUAL delta-seconds)
901*2882Svi117747  *			/ generic-param
902*2882Svi117747  * event-reason-value   =   "deactivated"
903*2882Svi117747  *				/ "probation"
904*2882Svi117747  *				/ "rejected"
905*2882Svi117747  *				/ "timeout"
906*2882Svi117747  *				/ "giveup"
907*2882Svi117747  *				/ "noresource"
908*2882Svi117747  *				/ event-reason-extension
909*2882Svi117747  * event-reason-extension = token
910*2882Svi117747  */
911*2882Svi117747 int
912*2882Svi117747 sip_parse_substate_header(_sip_header_t *sip_header,
913*2882Svi117747     sip_parsed_header_t **header)
914*2882Svi117747 {
915*2882Svi117747 	return (sip_parse_hdr_parser1(sip_header, header, (char)NULL));
916*2882Svi117747 }
917*2882Svi117747 
918*2882Svi117747 /*
919*2882Svi117747  * Authorization     =  "Authorization" HCOLON credentials
920*2882Svi117747  * credentials       =  ("Digest" LWS digest-response)
921*2882Svi117747  *			/ other-response
922*2882Svi117747  * digest-response   =  dig-resp *(COMMA dig-resp)
923*2882Svi117747  * dig-resp          =  username / realm / nonce / digest-uri
924*2882Svi117747  *			/ dresponse / algorithm / cnonce
925*2882Svi117747  *			/ opaque / message-qop
926*2882Svi117747  *			/ nonce-count / auth-param
927*2882Svi117747  * username          =  "username" EQUAL username-value
928*2882Svi117747  * username-value    =  quoted-string
929*2882Svi117747  * digest-uri        =  "uri" EQUAL LDQUOT digest-uri-value RDQUOT
930*2882Svi117747  * digest-uri-value  =  rquest-uri ; Equal to request-uri as specified
931*2882Svi117747  *			by HTTP/1.1
932*2882Svi117747  * message-qop       =  "qop" EQUAL qop-value
933*2882Svi117747  * cnonce            =  "cnonce" EQUAL cnonce-value
934*2882Svi117747  * cnonce-value      =  nonce-value
935*2882Svi117747  * nonce-count       =  "nc" EQUAL nc-value
936*2882Svi117747  * nc-value          =  8LHEX
937*2882Svi117747  * dresponse         =  "response" EQUAL request-digest
938*2882Svi117747  * request-digest    =  LDQUOT 32LHEX RDQUOT
939*2882Svi117747  * auth-param        =  auth-param-name EQUAL
940*2882Svi117747  * 			( token / quoted-string )
941*2882Svi117747  * auth-param-name   =  token
942*2882Svi117747  * other-response    =  auth-scheme LWS auth-param
943*2882Svi117747  *			*(COMMA auth-param)
944*2882Svi117747  * auth-scheme       =  token
945*2882Svi117747  */
946*2882Svi117747 int
947*2882Svi117747 sip_parse_author_header(_sip_header_t *sip_header,
948*2882Svi117747     sip_parsed_header_t **header)
949*2882Svi117747 {
950*2882Svi117747 	return (sip_parse_hdr_parser5(sip_header, header, B_TRUE));
951*2882Svi117747 }
952*2882Svi117747 
953*2882Svi117747 /*
954*2882Svi117747  * Authentication-Info  =  "Authentication-Info" HCOLON ainfo
955*2882Svi117747  *				*(COMMA ainfo)
956*2882Svi117747  * ainfo                =  nextnonce / message-qop
957*2882Svi117747  *				/ response-auth / cnonce
958*2882Svi117747  *				/ nonce-count
959*2882Svi117747  * nextnonce            =  "nextnonce" EQUAL nonce-value
960*2882Svi117747  * response-auth        =  "rspauth" EQUAL response-digest
961*2882Svi117747  * response-digest      =  LDQUOT *LHEX RDQUOT
962*2882Svi117747  *
963*2882Svi117747  */
964*2882Svi117747 int
965*2882Svi117747 sip_parse_ainfo_header(_sip_header_t *sip_header,
966*2882Svi117747     sip_parsed_header_t **header)
967*2882Svi117747 {
968*2882Svi117747 	return (sip_parse_hdr_parser1(sip_header, header, (char)NULL));
969*2882Svi117747 }
970*2882Svi117747 
971*2882Svi117747 /*
972*2882Svi117747  * Proxy-Authenticate  =  "Proxy-Authenticate" HCOLON challenge
973*2882Svi117747  * challenge           =  ("Digest" LWS digest-cln *(COMMA digest-cln))
974*2882Svi117747  *				/ other-challenge
975*2882Svi117747  * other-challenge     =  auth-scheme LWS auth-param
976*2882Svi117747  * 				*(COMMA auth-param)
977*2882Svi117747  * digest-cln          =  realm / domain / nonce
978*2882Svi117747  *				/ opaque / stale / algorithm
979*2882Svi117747  *				/ qop-options / auth-param
980*2882Svi117747  * realm               =  "realm" EQUAL realm-value
981*2882Svi117747  * realm-value         =  quoted-string
982*2882Svi117747  * domain              =  "domain" EQUAL LDQUOT URI
983*2882Svi117747  *				*( 1*SP URI ) RDQUOT
984*2882Svi117747  * URI                 =  absoluteURI / abs-path
985*2882Svi117747  * nonce               =  "nonce" EQUAL nonce-value
986*2882Svi117747  * nonce-value         =  quoted-string
987*2882Svi117747  * opaque              =  "opaque" EQUAL quoted-string
988*2882Svi117747  * stale               =  "stale" EQUAL ( "true" / "false" )
989*2882Svi117747  * algorithm           =  "algorithm" EQUAL ( "MD5" / "MD5-sess"
990*2882Svi117747  *			/ token )
991*2882Svi117747  * qop-options         =  "qop" EQUAL LDQUOT qop-value
992*2882Svi117747  *			*("," qop-value) RDQUOT
993*2882Svi117747  * qop-value           =  "auth" / "auth-int" / token
994*2882Svi117747  *
995*2882Svi117747  */
996*2882Svi117747 int
997*2882Svi117747 sip_parse_pauthen_header(_sip_header_t *sip_header,
998*2882Svi117747     sip_parsed_header_t **header)
999*2882Svi117747 {
1000*2882Svi117747 	return (sip_parse_hdr_parser5(sip_header, header, B_TRUE));
1001*2882Svi117747 }
1002*2882Svi117747 
1003*2882Svi117747 /*
1004*2882Svi117747  * Proxy-Authorization  =  "Proxy-Authorization" HCOLON credentials
1005*2882Svi117747  */
1006*2882Svi117747 int
1007*2882Svi117747 sip_parse_pauthor_header(_sip_header_t *sip_header,
1008*2882Svi117747     sip_parsed_header_t **header)
1009*2882Svi117747 {
1010*2882Svi117747 	return (sip_parse_hdr_parser5(sip_header, header, B_TRUE));
1011*2882Svi117747 }
1012*2882Svi117747 
1013*2882Svi117747 /*
1014*2882Svi117747  * Proxy-Require  =  "Proxy-Require" HCOLON option-tag
1015*2882Svi117747  *			*(COMMA option-tag)
1016*2882Svi117747  * option-tag     =  token
1017*2882Svi117747  */
1018*2882Svi117747 int
1019*2882Svi117747 sip_parse_preq_header(_sip_header_t *sip_header,
1020*2882Svi117747     sip_parsed_header_t **header)
1021*2882Svi117747 {
1022*2882Svi117747 	return (sip_parse_hdr_parser1(sip_header, header, (char)NULL));
1023*2882Svi117747 }
1024*2882Svi117747 
1025*2882Svi117747 /*
1026*2882Svi117747  * WWW-Authenticate  =  "WWW-Authenticate" HCOLON challenge
1027*2882Svi117747  * extension-header  =  header-name HCOLON header-value
1028*2882Svi117747  * header-name       =  token
1029*2882Svi117747  * header-value      =  *(TEXT-UTF8char / UTF8-CONT / LWS)
1030*2882Svi117747  * message-body  =  *OCTET
1031*2882Svi117747  *
1032*2882Svi117747  */
1033*2882Svi117747 int
1034*2882Svi117747 sip_parse_wauthen_header(_sip_header_t *sip_header,
1035*2882Svi117747     sip_parsed_header_t **header)
1036*2882Svi117747 {
1037*2882Svi117747 	return (sip_parse_hdr_parser5(sip_header, header, B_TRUE));
1038*2882Svi117747 }
1039*2882Svi117747 
1040*2882Svi117747 /*
1041*2882Svi117747  * Call-ID  =  ( "Call-ID" / "i" ) HCOLON callid
1042*2882Svi117747  */
1043*2882Svi117747 int
1044*2882Svi117747 sip_parse_cid_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
1045*2882Svi117747 {
1046*2882Svi117747 	return (sip_parse_hdr_parser4(sip_header, header));
1047*2882Svi117747 }
1048*2882Svi117747 
1049*2882Svi117747 /*
1050*2882Svi117747  * CSeq  =  "CSeq" HCOLON 1*DIGIT LWS Method
1051*2882Svi117747  */
1052*2882Svi117747 int
1053*2882Svi117747 sip_parse_cseq_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
1054*2882Svi117747 {
1055*2882Svi117747 	sip_parsed_header_t	*parsed_header;
1056*2882Svi117747 	sip_hdr_value_t		*cseq_value;
1057*2882Svi117747 	int			len;
1058*2882Svi117747 	char			*tmp_ptr;
1059*2882Svi117747 	int			i;
1060*2882Svi117747 	int			ret;
1061*2882Svi117747 
1062*2882Svi117747 	if ((ret = sip_prim_parsers(sip_header, header)) != 0)
1063*2882Svi117747 		return (ret);
1064*2882Svi117747 
1065*2882Svi117747 	if (*header != NULL)
1066*2882Svi117747 		return (0);
1067*2882Svi117747 
1068*2882Svi117747 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
1069*2882Svi117747 	if (parsed_header == NULL)
1070*2882Svi117747 		return (ENOMEM);
1071*2882Svi117747 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
1072*2882Svi117747 	parsed_header->sip_header = sip_header;
1073*2882Svi117747 
1074*2882Svi117747 	parsed_header->value =  calloc(1, sizeof (sip_hdr_value_t));
1075*2882Svi117747 	if (parsed_header->value == NULL) {
1076*2882Svi117747 		free(parsed_header);
1077*2882Svi117747 		return (ENOMEM);
1078*2882Svi117747 	}
1079*2882Svi117747 	cseq_value = (sip_hdr_value_t *)parsed_header->value;
1080*2882Svi117747 	cseq_value->sip_value_version = SIP_VALUE_VERSION_1;
1081*2882Svi117747 	cseq_value->sip_value_start = sip_header->sip_hdr_current;
1082*2882Svi117747 	if (sip_atoi(sip_header, &cseq_value->cseq_num)) {
1083*2882Svi117747 		cseq_value->sip_value_state = SIP_VALUE_BAD;
1084*2882Svi117747 		cseq_value->sip_value_end = sip_header->sip_hdr_end - 2;
1085*2882Svi117747 		goto cseq_parse_done;
1086*2882Svi117747 	}
1087*2882Svi117747 	cseq_value->sip_value_header = parsed_header;
1088*2882Svi117747 	/*
1089*2882Svi117747 	 * Get method.
1090*2882Svi117747 	 */
1091*2882Svi117747 	if (sip_skip_white_space(sip_header) != 0) {
1092*2882Svi117747 		cseq_value->sip_value_state = SIP_VALUE_BAD;
1093*2882Svi117747 		cseq_value->sip_value_end = sip_header->sip_hdr_end - 2;
1094*2882Svi117747 		goto cseq_parse_done;
1095*2882Svi117747 	}
1096*2882Svi117747 
1097*2882Svi117747 	tmp_ptr = sip_header->sip_hdr_current;
1098*2882Svi117747 
1099*2882Svi117747 	if (sip_find_white_space(sip_header)) {
1100*2882Svi117747 		cseq_value->sip_value_state = SIP_VALUE_BAD;
1101*2882Svi117747 		cseq_value->sip_value_end = sip_header->sip_hdr_current;
1102*2882Svi117747 		goto cseq_parse_done;
1103*2882Svi117747 	}
1104*2882Svi117747 
1105*2882Svi117747 	len = sip_header->sip_hdr_current - tmp_ptr;
1106*2882Svi117747 
1107*2882Svi117747 	for (i = 1; i < MAX_SIP_METHODS; i++) {
1108*2882Svi117747 		if (strncmp(sip_methods[i].name, tmp_ptr, len) == 0)
1109*2882Svi117747 			break;
1110*2882Svi117747 	}
1111*2882Svi117747 
1112*2882Svi117747 	if (i >= MAX_SIP_METHODS) {
1113*2882Svi117747 		cseq_value->sip_value_state = SIP_VALUE_BAD;
1114*2882Svi117747 		cseq_value->sip_value_end = sip_header->sip_hdr_current;
1115*2882Svi117747 		goto cseq_parse_done;
1116*2882Svi117747 	}
1117*2882Svi117747 
1118*2882Svi117747 	cseq_value->cseq_method = i;
1119*2882Svi117747 	cseq_value->sip_value_end = sip_header->sip_hdr_current;
1120*2882Svi117747 cseq_parse_done:
1121*2882Svi117747 
1122*2882Svi117747 	sip_header->sip_hdr_parsed = parsed_header;
1123*2882Svi117747 
1124*2882Svi117747 	*header = parsed_header;
1125*2882Svi117747 	return (0);
1126*2882Svi117747 }
1127*2882Svi117747 
1128*2882Svi117747 
1129*2882Svi117747 /*
1130*2882Svi117747  * Via =  ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
1131*2882Svi117747  * via-parm          =  sent-protocol LWS sent-by *( SEMI via-params )
1132*2882Svi117747  * via-params        =  via-ttl / via-maddr
1133*2882Svi117747  *                      / via-received / via-branch
1134*2882Svi117747  *                      / via-extension
1135*2882Svi117747  * via-ttl           =  "ttl" EQUAL ttl
1136*2882Svi117747  * via-maddr         =  "maddr" EQUAL host
1137*2882Svi117747  * via-received      =  "received" EQUAL (IPv4address / IPv6address)
1138*2882Svi117747  * via-branch        =  "branch" EQUAL token
1139*2882Svi117747  * via-extension     =  generic-param
1140*2882Svi117747  * sent-protocol     =  protocol-name SLASH protocol-version
1141*2882Svi117747  *                      SLASH transport
1142*2882Svi117747  * protocol-name     =  "SIP" / token
1143*2882Svi117747  * protocol-version  =  token
1144*2882Svi117747  * transport         =  "UDP" / "TCP" / "TLS" / "SCTP"
1145*2882Svi117747  *                      / other-transport
1146*2882Svi117747  * sent-by           =  host [ COLON port ]
1147*2882Svi117747  * ttl               =  1*3DIGIT ; 0 to 255
1148*2882Svi117747  *
1149*2882Svi117747  * There can be multiple via headers we always append the header.
1150*2882Svi117747  */
1151*2882Svi117747 int
1152*2882Svi117747 sip_parse_via_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
1153*2882Svi117747 {
1154*2882Svi117747 	sip_parsed_header_t	*parsed_header;
1155*2882Svi117747 	int			ret;
1156*2882Svi117747 	sip_hdr_value_t		*value = NULL;
1157*2882Svi117747 	sip_hdr_value_t		*last_value = NULL;
1158*2882Svi117747 
1159*2882Svi117747 	if ((ret = sip_prim_parsers(sip_header, header)) != 0)
1160*2882Svi117747 		return (ret);
1161*2882Svi117747 
1162*2882Svi117747 	if (*header != NULL)
1163*2882Svi117747 		return (0);
1164*2882Svi117747 
1165*2882Svi117747 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
1166*2882Svi117747 	if (parsed_header == NULL)
1167*2882Svi117747 		return (ENOMEM);
1168*2882Svi117747 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
1169*2882Svi117747 	parsed_header->sip_header = sip_header;
1170*2882Svi117747 
1171*2882Svi117747 	while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
1172*2882Svi117747 
1173*2882Svi117747 		value = calloc(1, sizeof (sip_hdr_value_t));
1174*2882Svi117747 		if (value == NULL) {
1175*2882Svi117747 			sip_free_phdr(parsed_header);
1176*2882Svi117747 			return (ENOMEM);
1177*2882Svi117747 		}
1178*2882Svi117747 		if (last_value != NULL)
1179*2882Svi117747 			last_value->sip_next_value = value;
1180*2882Svi117747 		else
1181*2882Svi117747 			parsed_header->value = (sip_value_t *)value;
1182*2882Svi117747 
1183*2882Svi117747 		value->sip_value_version = SIP_VALUE_VERSION_1;
1184*2882Svi117747 		value->sip_value_start = sip_header->sip_hdr_current;
1185*2882Svi117747 		value->sip_value_header = parsed_header;
1186*2882Svi117747 		value->via_protocol_name.sip_str_ptr =
1187*2882Svi117747 		    sip_header->sip_hdr_current;
1188*2882Svi117747 
1189*2882Svi117747 		/*
1190*2882Svi117747 		 * Check to see if there is a version number
1191*2882Svi117747 		 */
1192*2882Svi117747 		if (sip_get_protocol_version(sip_header,
1193*2882Svi117747 		    &value->via_protocol) != 0) {
1194*2882Svi117747 			if (sip_goto_next_value(sip_header) != 0) {
1195*2882Svi117747 				sip_free_phdr(parsed_header);
1196*2882Svi117747 				return (EPROTO);
1197*2882Svi117747 			}
1198*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
1199*2882Svi117747 			goto get_next_via_value;
1200*2882Svi117747 		}
1201*2882Svi117747 
1202*2882Svi117747 		if (sip_find_token(sip_header, SIP_SLASH) != 0) {
1203*2882Svi117747 			if (sip_goto_next_value(sip_header) != 0) {
1204*2882Svi117747 				sip_free_phdr(parsed_header);
1205*2882Svi117747 				return (EPROTO);
1206*2882Svi117747 			}
1207*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
1208*2882Svi117747 			goto get_next_via_value;
1209*2882Svi117747 		}
1210*2882Svi117747 
1211*2882Svi117747 		if (sip_skip_white_space(sip_header) != 0) {
1212*2882Svi117747 			if (sip_goto_next_value(sip_header) != 0) {
1213*2882Svi117747 				sip_free_phdr(parsed_header);
1214*2882Svi117747 				return (EPROTO);
1215*2882Svi117747 			}
1216*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
1217*2882Svi117747 			goto get_next_via_value;
1218*2882Svi117747 		}
1219*2882Svi117747 
1220*2882Svi117747 		value->via_protocol_transport.sip_str_ptr =
1221*2882Svi117747 		    sip_header->sip_hdr_current;
1222*2882Svi117747 		if (sip_find_white_space(sip_header) != 0) {
1223*2882Svi117747 			if (sip_goto_next_value(sip_header) != 0) {
1224*2882Svi117747 				sip_free_phdr(parsed_header);
1225*2882Svi117747 				return (EPROTO);
1226*2882Svi117747 			}
1227*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
1228*2882Svi117747 			goto get_next_via_value;
1229*2882Svi117747 		}
1230*2882Svi117747 
1231*2882Svi117747 		value->via_protocol_transport.sip_str_len =
1232*2882Svi117747 		    sip_header->sip_hdr_current -
1233*2882Svi117747 		    value->via_protocol_transport.sip_str_ptr;
1234*2882Svi117747 
1235*2882Svi117747 		if (sip_skip_white_space(sip_header) != 0) {
1236*2882Svi117747 			if (sip_goto_next_value(sip_header) != 0) {
1237*2882Svi117747 				sip_free_phdr(parsed_header);
1238*2882Svi117747 				return (EPROTO);
1239*2882Svi117747 			}
1240*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
1241*2882Svi117747 			goto get_next_via_value;
1242*2882Svi117747 		}
1243*2882Svi117747 
1244*2882Svi117747 		value->via_sent_by_host.sip_str_ptr =
1245*2882Svi117747 		    sip_header->sip_hdr_current;
1246*2882Svi117747 		if (*sip_header->sip_hdr_current == '[') {
1247*2882Svi117747 			if (sip_find_token(sip_header, ']')) {
1248*2882Svi117747 				if (sip_goto_next_value(sip_header) != 0) {
1249*2882Svi117747 					sip_free_phdr(parsed_header);
1250*2882Svi117747 					return (EPROTO);
1251*2882Svi117747 				}
1252*2882Svi117747 				value->sip_value_state = SIP_VALUE_BAD;
1253*2882Svi117747 				goto get_next_via_value;
1254*2882Svi117747 			}
1255*2882Svi117747 		} else if (sip_find_separator(sip_header, SIP_SEMI, SIP_COMMA,
1256*2882Svi117747 		    SIP_HCOLON)) {
1257*2882Svi117747 			if (sip_goto_next_value(sip_header) != 0) {
1258*2882Svi117747 				sip_free_phdr(parsed_header);
1259*2882Svi117747 				return (EPROTO);
1260*2882Svi117747 			}
1261*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
1262*2882Svi117747 			goto get_next_via_value;
1263*2882Svi117747 		}
1264*2882Svi117747 		value->via_sent_by_host.sip_str_len =
1265*2882Svi117747 		    sip_header->sip_hdr_current -
1266*2882Svi117747 		    value->via_sent_by_host.sip_str_ptr;
1267*2882Svi117747 
1268*2882Svi117747 		if (sip_skip_white_space(sip_header) != 0) {
1269*2882Svi117747 			if (sip_goto_next_value(sip_header) != 0) {
1270*2882Svi117747 				sip_free_phdr(parsed_header);
1271*2882Svi117747 				return (EPROTO);
1272*2882Svi117747 			}
1273*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
1274*2882Svi117747 			goto get_next_via_value;
1275*2882Svi117747 		}
1276*2882Svi117747 
1277*2882Svi117747 		if (*sip_header->sip_hdr_current == SIP_HCOLON) {
1278*2882Svi117747 			sip_header->sip_hdr_current++;
1279*2882Svi117747 			/*
1280*2882Svi117747 			 * We have a port number
1281*2882Svi117747 			 */
1282*2882Svi117747 			if (sip_atoi(sip_header, &value->via_sent_by_port) !=
1283*2882Svi117747 			    0) {
1284*2882Svi117747 				if (sip_goto_next_value(sip_header) != 0) {
1285*2882Svi117747 					sip_free_phdr(parsed_header);
1286*2882Svi117747 					return (EPROTO);
1287*2882Svi117747 				}
1288*2882Svi117747 				value->sip_value_state = SIP_VALUE_BAD;
1289*2882Svi117747 				goto get_next_via_value;
1290*2882Svi117747 			}
1291*2882Svi117747 
1292*2882Svi117747 		}
1293*2882Svi117747 
1294*2882Svi117747 		/*
1295*2882Svi117747 		 * Do some sanity checking.
1296*2882Svi117747 		 * This should be replaced by a v4/v6 address check.
1297*2882Svi117747 		 */
1298*2882Svi117747 		if (value->via_sent_by_host.sip_str_len == 0 ||
1299*2882Svi117747 		    (!isalnum(*value->via_sent_by_host.sip_str_ptr) &&
1300*2882Svi117747 		    *value->via_sent_by_host.sip_str_ptr != '[')) {
1301*2882Svi117747 			if (sip_goto_next_value(sip_header) != 0) {
1302*2882Svi117747 				sip_free_phdr(parsed_header);
1303*2882Svi117747 				return (EPROTO);
1304*2882Svi117747 			}
1305*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
1306*2882Svi117747 			goto get_next_via_value;
1307*2882Svi117747 		}
1308*2882Svi117747 
1309*2882Svi117747 		ret = sip_parse_params(sip_header, &value->sip_param_list);
1310*2882Svi117747 		if (ret == EPROTO) {
1311*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
1312*2882Svi117747 		} else if (ret != 0) {
1313*2882Svi117747 			sip_free_phdr(parsed_header);
1314*2882Svi117747 			return (ret);
1315*2882Svi117747 		}
1316*2882Svi117747 get_next_via_value:
1317*2882Svi117747 		value->sip_value_end = sip_header->sip_hdr_current;
1318*2882Svi117747 
1319*2882Svi117747 		if (sip_find_token(sip_header, SIP_COMMA) != 0)
1320*2882Svi117747 			break;
1321*2882Svi117747 		last_value = value;
1322*2882Svi117747 		(void) sip_skip_white_space(sip_header);
1323*2882Svi117747 	}
1324*2882Svi117747 
1325*2882Svi117747 	sip_header->sip_hdr_parsed = parsed_header;
1326*2882Svi117747 
1327*2882Svi117747 	*header = parsed_header;
1328*2882Svi117747 	return (0);
1329*2882Svi117747 }
1330*2882Svi117747 
1331*2882Svi117747 /*
1332*2882Svi117747  * Max-Forwards  =  "Max-Forwards" HCOLON 1*DIGIT
1333*2882Svi117747  */
1334*2882Svi117747 int
1335*2882Svi117747 sip_parse_maxf_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
1336*2882Svi117747 {
1337*2882Svi117747 	return (sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL));
1338*2882Svi117747 }
1339*2882Svi117747 
1340*2882Svi117747 /*
1341*2882Svi117747  * Content-Type     =  ( "Content-Type" / "c" ) HCOLON media-type
1342*2882Svi117747  * media-type       =  m-type SLASH m-subtype *(SEMI m-parameter)
1343*2882Svi117747  * m-type           =  discrete-type / composite-type
1344*2882Svi117747  * discrete-type    =  "text" / "image" / "audio" / "video"
1345*2882Svi117747  *                     / "application" / extension-token
1346*2882Svi117747  * composite-type   =  "message" / "multipart" / extension-token
1347*2882Svi117747  * extension-token  =  ietf-token / x-token
1348*2882Svi117747  * ietf-token       =  token
1349*2882Svi117747  * x-token          =  "x-" token
1350*2882Svi117747  * m-subtype        =  extension-token / iana-token
1351*2882Svi117747  * iana-token       =  token
1352*2882Svi117747  * m-parameter      =  m-attribute EQUAL m-value
1353*2882Svi117747  * m-attribute      =  token
1354*2882Svi117747  * m-value          =  token / quoted-string
1355*2882Svi117747  */
1356*2882Svi117747 int
1357*2882Svi117747 sip_parse_ctype_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
1358*2882Svi117747 {
1359*2882Svi117747 	return (sip_parse_hdr_parser1(sip_header, header, SIP_SLASH));
1360*2882Svi117747 }
1361*2882Svi117747 
1362*2882Svi117747 /*
1363*2882Svi117747  * Content-Length  =  ( "Content-Length" / "l" ) HCOLON 1*DIGIT
1364*2882Svi117747  */
1365*2882Svi117747 int
1366*2882Svi117747 sip_parse_clen_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
1367*2882Svi117747 {
1368*2882Svi117747 	return (sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL));
1369*2882Svi117747 }
1370*2882Svi117747 
1371*2882Svi117747 /*
1372*2882Svi117747  * Generic parser for Contact, From, To, Route and Record-Route headers
1373*2882Svi117747  *
1374*2882Svi117747  * Contact = ("Contact" / "m" ) HCOLON
1375*2882Svi117747  *		( STAR / (contact-param *(COMMA contact-param)))
1376*2882Svi117747  * contact-param  =  (name-addr / addr-spec) *(SEMI contact-params)
1377*2882Svi117747  * name-addr      =  [ display-name ] LAQUOT addr-spec RAQUOT
1378*2882Svi117747  * addr-spec      =  SIP-URI / SIPS-URI / absoluteURI
1379*2882Svi117747  * display-name   =  *(token LWS)/ quoted-string
1380*2882Svi117747  * contact-params     =  c-p-q / c-p-expires
1381*2882Svi117747  *                     / contact-extension
1382*2882Svi117747  *
1383*2882Svi117747  * From =  ( "From" / "f" ) HCOLON from-spec
1384*2882Svi117747  * from-spec = ( name-addr / addr-spec )
1385*2882Svi117747  *	*( SEMI from-param )
1386*2882Svi117747  * from-param  =  tag-param / generic-param
1387*2882Svi117747  * tag-param   =  "tag" EQUAL token
1388*2882Svi117747  *
1389*2882Svi117747  * To =  ( "To" / "t" ) HCOLON ( name-addr
1390*2882Svi117747  *	/ addr-spec ) *( SEMI to-param )
1391*2882Svi117747  * to-param  =  tag-param / generic-param
1392*2882Svi117747  *
1393*2882Svi117747  * Route        =  "Route" HCOLON route-param *(COMMA route-param)
1394*2882Svi117747  * route-param  =  name-addr *( SEMI rr-param )
1395*2882Svi117747  *
1396*2882Svi117747  * Record-Route  =  "Record-Route" HCOLON rec-route *(COMMA rec-route)
1397*2882Svi117747  * rec-route     =  name-addr *( SEMI rr-param )
1398*2882Svi117747  * rr-param      =  generic-param
1399*2882Svi117747  *
1400*2882Svi117747  * We could have multiple values for these headers. For the ones that have
1401*2882Svi117747  * a display name we will have a LAQUOT/RAQUOT. If we encounter an error
1402*2882Svi117747  * when parsing a value, we mark the value as bad and start paring the
1403*2882Svi117747  * next value, if present. Before we start parsing the next value, we
1404*2882Svi117747  * check for any parameters, if present.
1405*2882Svi117747  */
1406*2882Svi117747 int
1407*2882Svi117747 sip_parse_cftr_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
1408*2882Svi117747 {
1409*2882Svi117747 	sip_parsed_header_t	*parsed_header;
1410*2882Svi117747 	char			*tmp_ptr;
1411*2882Svi117747 	char			*tmp_ptr_2;
1412*2882Svi117747 	int			ret;
1413*2882Svi117747 	sip_hdr_value_t		*value = NULL;
1414*2882Svi117747 	sip_hdr_value_t		*last_value = NULL;
1415*2882Svi117747 
1416*2882Svi117747 	if ((ret = sip_prim_parsers(sip_header, header)) != 0)
1417*2882Svi117747 		return (ret);
1418*2882Svi117747 
1419*2882Svi117747 	if (*header != NULL)
1420*2882Svi117747 		return (0);
1421*2882Svi117747 
1422*2882Svi117747 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
1423*2882Svi117747 	if (parsed_header == NULL)
1424*2882Svi117747 		return (ENOMEM);
1425*2882Svi117747 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
1426*2882Svi117747 	parsed_header->sip_header = sip_header;
1427*2882Svi117747 	while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
1428*2882Svi117747 		boolean_t	quoted_name = B_FALSE;
1429*2882Svi117747 
1430*2882Svi117747 		value =  calloc(1, sizeof (sip_hdr_value_t));
1431*2882Svi117747 		if (value == NULL) {
1432*2882Svi117747 			sip_free_cftr_header(parsed_header);
1433*2882Svi117747 			return (ENOMEM);
1434*2882Svi117747 		}
1435*2882Svi117747 		if (last_value != NULL)
1436*2882Svi117747 			last_value->sip_next_value = value;
1437*2882Svi117747 		else
1438*2882Svi117747 			parsed_header->value = (sip_value_t *)value;
1439*2882Svi117747 		if (*sip_header->sip_hdr_current == SIP_QUOTE) {
1440*2882Svi117747 			sip_header->sip_hdr_current++;
1441*2882Svi117747 			quoted_name = B_TRUE;
1442*2882Svi117747 		}
1443*2882Svi117747 		value->sip_value_version = SIP_VALUE_VERSION_1;
1444*2882Svi117747 		value->sip_value_start = sip_header->sip_hdr_current;
1445*2882Svi117747 		value->sip_value_header = parsed_header;
1446*2882Svi117747 		/*
1447*2882Svi117747 		 * let's see if there is a display name
1448*2882Svi117747 		 */
1449*2882Svi117747 		if (*sip_header->sip_hdr_current != SIP_LAQUOT) {
1450*2882Svi117747 
1451*2882Svi117747 			tmp_ptr = sip_header->sip_hdr_current;
1452*2882Svi117747 			/*
1453*2882Svi117747 			 * According to 20.10 '<' may not have a leading
1454*2882Svi117747 			 * space.
1455*2882Svi117747 			 */
1456*2882Svi117747 			if (quoted_name &&
1457*2882Svi117747 			    sip_find_token(sip_header, SIP_QUOTE) != 0) {
1458*2882Svi117747 				if (sip_goto_next_value(sip_header) != 0) {
1459*2882Svi117747 					sip_free_cftr_header(parsed_header);
1460*2882Svi117747 					return (EPROTO);
1461*2882Svi117747 				}
1462*2882Svi117747 				value->sip_value_state = SIP_VALUE_BAD;
1463*2882Svi117747 				goto get_next_cftr_value;
1464*2882Svi117747 			} else if (sip_find_separator(sip_header, SIP_SEMI,
1465*2882Svi117747 			    SIP_LAQUOT, SIP_COMMA) != 0) {
1466*2882Svi117747 				/*
1467*2882Svi117747 				 * only a uri.
1468*2882Svi117747 				 */
1469*2882Svi117747 				value->cftr_uri.sip_str_ptr = tmp_ptr;
1470*2882Svi117747 				value->cftr_uri.sip_str_len =
1471*2882Svi117747 				    sip_header->sip_hdr_current - tmp_ptr;
1472*2882Svi117747 				/*
1473*2882Svi117747 				 * It's an error not to have a uri.
1474*2882Svi117747 				 */
1475*2882Svi117747 				if (value->cftr_uri.sip_str_len == 0) {
1476*2882Svi117747 					if (sip_goto_next_value(sip_header) !=
1477*2882Svi117747 					    0) {
1478*2882Svi117747 						sip_free_cftr_header(
1479*2882Svi117747 						    parsed_header);
1480*2882Svi117747 						return (EPROTO);
1481*2882Svi117747 					}
1482*2882Svi117747 					value->sip_value_state = SIP_VALUE_BAD;
1483*2882Svi117747 					goto get_next_cftr_value;
1484*2882Svi117747 				}
1485*2882Svi117747 				continue;
1486*2882Svi117747 			}
1487*2882Svi117747 
1488*2882Svi117747 			tmp_ptr_2 = sip_header->sip_hdr_current;
1489*2882Svi117747 			if (*sip_header->sip_hdr_current == SIP_SP) {
1490*2882Svi117747 				if (sip_skip_white_space(sip_header) != 0) {
1491*2882Svi117747 					/*
1492*2882Svi117747 					 * only a uri.
1493*2882Svi117747 					 */
1494*2882Svi117747 					value->cftr_uri.sip_str_ptr = tmp_ptr;
1495*2882Svi117747 					value->cftr_uri.sip_str_len =
1496*2882Svi117747 					    tmp_ptr_2 - tmp_ptr;
1497*2882Svi117747 					/*
1498*2882Svi117747 					 * It's an error not to have a uri.
1499*2882Svi117747 					 */
1500*2882Svi117747 					if (value->cftr_uri.sip_str_len == 0) {
1501*2882Svi117747 						if (sip_goto_next_value(
1502*2882Svi117747 						    sip_header) != 0) {
1503*2882Svi117747 							sip_free_cftr_header(
1504*2882Svi117747 							    parsed_header);
1505*2882Svi117747 							return (EPROTO);
1506*2882Svi117747 						}
1507*2882Svi117747 						value->sip_value_state =
1508*2882Svi117747 						    SIP_VALUE_BAD;
1509*2882Svi117747 						goto get_next_cftr_value;
1510*2882Svi117747 					}
1511*2882Svi117747 					continue;
1512*2882Svi117747 				}
1513*2882Svi117747 			}
1514*2882Svi117747 
1515*2882Svi117747 			if (*sip_header->sip_hdr_current != SIP_LAQUOT) {
1516*2882Svi117747 				/*
1517*2882Svi117747 				 * No display name here.
1518*2882Svi117747 				 */
1519*2882Svi117747 				value->cftr_uri.sip_str_ptr = tmp_ptr;
1520*2882Svi117747 				value->cftr_uri.sip_str_len = tmp_ptr_2 -
1521*2882Svi117747 				    tmp_ptr;
1522*2882Svi117747 				/*
1523*2882Svi117747 				 * It's an error not to have a uri.
1524*2882Svi117747 				 */
1525*2882Svi117747 				if (value->cftr_uri.sip_str_len == 0) {
1526*2882Svi117747 					if (sip_goto_next_value(sip_header) !=
1527*2882Svi117747 					    0) {
1528*2882Svi117747 						sip_free_cftr_header(
1529*2882Svi117747 						    parsed_header);
1530*2882Svi117747 						return (EPROTO);
1531*2882Svi117747 					}
1532*2882Svi117747 					value->sip_value_state = SIP_VALUE_BAD;
1533*2882Svi117747 					goto get_next_cftr_value;
1534*2882Svi117747 				}
1535*2882Svi117747 				goto get_params;
1536*2882Svi117747 			}
1537*2882Svi117747 
1538*2882Svi117747 			value->cftr_name = malloc(sizeof (sip_str_t));
1539*2882Svi117747 			if (value->cftr_name == NULL) {
1540*2882Svi117747 				sip_free_cftr_header(parsed_header);
1541*2882Svi117747 				return (ENOMEM);
1542*2882Svi117747 			}
1543*2882Svi117747 			value->cftr_name->sip_str_ptr = tmp_ptr;
1544*2882Svi117747 			value->cftr_name->sip_str_len = tmp_ptr_2 - tmp_ptr;
1545*2882Svi117747 			if (quoted_name)
1546*2882Svi117747 				value->cftr_name->sip_str_len--;
1547*2882Svi117747 		}
1548*2882Svi117747 
1549*2882Svi117747 		if (sip_find_token(sip_header, SIP_LAQUOT) != 0) {
1550*2882Svi117747 			if (sip_goto_next_value(sip_header) != 0) {
1551*2882Svi117747 				sip_free_cftr_header(parsed_header);
1552*2882Svi117747 				return (EPROTO);
1553*2882Svi117747 			}
1554*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
1555*2882Svi117747 			goto get_next_cftr_value;
1556*2882Svi117747 		}
1557*2882Svi117747 
1558*2882Svi117747 		if (*sip_header->sip_hdr_current == SIP_SP) {
1559*2882Svi117747 			if (sip_skip_white_space(sip_header) != 0) {
1560*2882Svi117747 				if (sip_goto_next_value(sip_header) != 0) {
1561*2882Svi117747 					sip_free_cftr_header(parsed_header);
1562*2882Svi117747 					return (EPROTO);
1563*2882Svi117747 				}
1564*2882Svi117747 				value->sip_value_state = SIP_VALUE_BAD;
1565*2882Svi117747 				goto get_next_cftr_value;
1566*2882Svi117747 			}
1567*2882Svi117747 		}
1568*2882Svi117747 
1569*2882Svi117747 		tmp_ptr = sip_header->sip_hdr_current;
1570*2882Svi117747 
1571*2882Svi117747 		if (sip_find_separator(sip_header, SIP_RAQUOT, (char)NULL,
1572*2882Svi117747 		    (char)NULL)) {
1573*2882Svi117747 			if (sip_goto_next_value(sip_header) != 0) {
1574*2882Svi117747 				sip_free_cftr_header(parsed_header);
1575*2882Svi117747 				return (EPROTO);
1576*2882Svi117747 			}
1577*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
1578*2882Svi117747 			goto get_next_cftr_value;
1579*2882Svi117747 		}
1580*2882Svi117747 
1581*2882Svi117747 		value->cftr_uri.sip_str_ptr = tmp_ptr;
1582*2882Svi117747 		value->cftr_uri.sip_str_len =
1583*2882Svi117747 		    sip_header->sip_hdr_current - tmp_ptr;
1584*2882Svi117747 
1585*2882Svi117747 		if (sip_find_token(sip_header, SIP_RAQUOT) != 0) {
1586*2882Svi117747 			if (sip_goto_next_value(sip_header) != 0) {
1587*2882Svi117747 				sip_free_cftr_header(parsed_header);
1588*2882Svi117747 				return (EINVAL);
1589*2882Svi117747 			}
1590*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
1591*2882Svi117747 			goto get_next_cftr_value;
1592*2882Svi117747 		}
1593*2882Svi117747 
1594*2882Svi117747 		if (value->cftr_uri.sip_str_len <= strlen("<>")) {
1595*2882Svi117747 			if (sip_goto_next_value(sip_header) != 0) {
1596*2882Svi117747 				sip_free_cftr_header(parsed_header);
1597*2882Svi117747 				return (EPROTO);
1598*2882Svi117747 			}
1599*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
1600*2882Svi117747 			goto get_next_cftr_value;
1601*2882Svi117747 		}
1602*2882Svi117747 
1603*2882Svi117747 get_params:
1604*2882Svi117747 		ret = sip_parse_params(sip_header, &value->sip_param_list);
1605*2882Svi117747 		if (ret == EPROTO) {
1606*2882Svi117747 			value->sip_value_state = SIP_VALUE_BAD;
1607*2882Svi117747 		} else if (ret != 0) {
1608*2882Svi117747 			sip_free_cftr_header(parsed_header);
1609*2882Svi117747 			return (ret);
1610*2882Svi117747 		}
1611*2882Svi117747 get_next_cftr_value:
1612*2882Svi117747 		value->sip_value_end = sip_header->sip_hdr_current;
1613*2882Svi117747 
1614*2882Svi117747 		/*
1615*2882Svi117747 		 * Parse uri
1616*2882Svi117747 		 */
1617*2882Svi117747 		if (value->cftr_uri.sip_str_len > 0) {
1618*2882Svi117747 			int		error;
1619*2882Svi117747 
1620*2882Svi117747 			value->sip_value_parsed_uri = sip_parse_uri(
1621*2882Svi117747 			    &value->cftr_uri, &error);
1622*2882Svi117747 			if (value->sip_value_parsed_uri == NULL) {
1623*2882Svi117747 				sip_free_cftr_header(parsed_header);
1624*2882Svi117747 				return (ENOMEM);
1625*2882Svi117747 			}
1626*2882Svi117747 			if (error != 0 ||
1627*2882Svi117747 			    ((_sip_uri_t *)value->sip_value_parsed_uri)->
1628*2882Svi117747 			    sip_uri_errflags != 0) {
1629*2882Svi117747 				value->sip_value_state = SIP_VALUE_BAD;
1630*2882Svi117747 			}
1631*2882Svi117747 		}
1632*2882Svi117747 
1633*2882Svi117747 		(void) sip_find_token(sip_header, SIP_COMMA);
1634*2882Svi117747 		last_value = value;
1635*2882Svi117747 		(void) sip_skip_white_space(sip_header);
1636*2882Svi117747 	}
1637*2882Svi117747 
1638*2882Svi117747 	sip_header->sip_hdr_parsed = parsed_header;
1639*2882Svi117747 
1640*2882Svi117747 	*header = parsed_header;
1641*2882Svi117747 	return (0);
1642*2882Svi117747 }
1643*2882Svi117747 
1644*2882Svi117747 /*
1645*2882Svi117747  * PAssertedID = "P-Asserted-Identity" HCOLON PAssertedID-value
1646*2882Svi117747  *               *(COMMA PAssertedID-value)
1647*2882Svi117747  * PAssertedID-value = name-addr / addr-spec
1648*2882Svi117747  */
1649*2882Svi117747 int
1650*2882Svi117747 sip_parse_passertedid(_sip_header_t *sip_header, sip_parsed_header_t **header)
1651*2882Svi117747 {
1652*2882Svi117747 	return (sip_parse_hdr_parser3(sip_header, header, SIP_STRS_VAL,
1653*2882Svi117747 	    B_TRUE));
1654*2882Svi117747 }
1655*2882Svi117747 
1656*2882Svi117747 /*
1657*2882Svi117747  * PPreferredID = "P-Preferred-Identity" HCOLON PPreferredID-value
1658*2882Svi117747  *               *(COMMA PAssertedID-value)
1659*2882Svi117747  * PPreferredID-value = name-addr / addr-spec
1660*2882Svi117747  */
1661*2882Svi117747 int
1662*2882Svi117747 sip_parse_ppreferredid(_sip_header_t *sip_header, sip_parsed_header_t **header)
1663*2882Svi117747 {
1664*2882Svi117747 	return (sip_parse_hdr_parser3(sip_header, header, SIP_STRS_VAL,
1665*2882Svi117747 	    B_TRUE));
1666*2882Svi117747 }
1667*2882Svi117747 
1668*2882Svi117747 
1669*2882Svi117747 /*
1670*2882Svi117747  * We don't do anything for a header we don't understand
1671*2882Svi117747  */
1672*2882Svi117747 /* ARGSUSED */
1673*2882Svi117747 int
1674*2882Svi117747 sip_parse_unknown_header(_sip_header_t *sip_header,
1675*2882Svi117747     sip_parsed_header_t **header)
1676*2882Svi117747 {
1677*2882Svi117747 	return (EINVAL);
1678*2882Svi117747 }
1679