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