xref: /illumos-gate/usr/src/lib/libsip/common/sip_parse_generic.c (revision b0fe7b8fa79924061f3bdf7f240ea116c2c0b704)
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 <stdlib.h>
30 #include <assert.h>
31 #include <errno.h>
32 #include <strings.h>
33 #include <ctype.h>
34 #include <sip.h>
35 
36 #include "sip_miscdefs.h"
37 #include "sip_msg.h"
38 #include "sip_parse_uri.h"
39 
40 /*
41  * atoi function from a header
42  */
43 int
44 sip_atoi(_sip_header_t *sip_header, int *num)
45 {
46 	boolean_t	num_found = B_FALSE;
47 
48 	*num = 0;
49 	while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
50 		if (isspace(*sip_header->sip_hdr_current)) {
51 			sip_header->sip_hdr_current++;
52 			if (num_found)
53 				break;
54 		} else if (isdigit(*sip_header->sip_hdr_current)) {
55 			*num = (*num * 10) +
56 			    (*sip_header->sip_hdr_current - '0');
57 			num_found = B_TRUE;
58 			sip_header->sip_hdr_current++;
59 		} else {
60 			break;
61 		}
62 	}
63 	if (!num_found)
64 		return (EINVAL);
65 	return (0);
66 }
67 
68 /*
69  * Find the 'token'
70  */
71 int
72 sip_find_token(_sip_header_t *sip_header, char token)
73 {
74 	while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
75 		if (token != SIP_COMMA &&
76 		    *sip_header->sip_hdr_current == SIP_COMMA) {
77 			sip_header->sip_hdr_current--;
78 			return (1);
79 		}
80 		if (*sip_header->sip_hdr_current++ == token) {
81 			/*
82 			 * sip_hdr_current points to the char
83 			 * after the token
84 			 */
85 			return (0);
86 		}
87 	}
88 	return (1);
89 }
90 
91 /*
92  * Find a carriage-return
93  */
94 int
95 sip_find_cr(_sip_header_t *sip_header)
96 {
97 	sip_header->sip_hdr_current = sip_header->sip_hdr_end;
98 	while (*sip_header->sip_hdr_current-- != '\n') {
99 		if (sip_header->sip_hdr_current == sip_header->sip_hdr_start)
100 			return (1);
101 	}
102 	return (0);
103 }
104 
105 /*
106  * Find one of the separator provided, i.e. separator_1st or separator_2nd or
107  * separator_3rd.
108  */
109 int
110 sip_find_separator(_sip_header_t *sip_header, char separator_1st,
111     char separator_2nd, char separator_3rd)
112 {
113 	assert(separator_1st != (char)NULL || separator_2nd != (char)NULL);
114 	while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
115 		if (isspace(*sip_header->sip_hdr_current) ||
116 		    (separator_1st != (char)NULL &&
117 		    (*sip_header->sip_hdr_current == separator_1st)) ||
118 		    (separator_2nd != (char)NULL &&
119 		    (*sip_header->sip_hdr_current == separator_2nd)) ||
120 		    (separator_3rd != (char)NULL &&
121 		    (*sip_header->sip_hdr_current == separator_3rd))) {
122 			return (0);
123 		}
124 		/*
125 		 * If we have escape character, go to the next char
126 		 */
127 		if (*sip_header->sip_hdr_current == '\\')
128 			sip_header->sip_hdr_current++;
129 		sip_header->sip_hdr_current++;
130 	}
131 	return (1);
132 }
133 
134 /*
135  * Return when we hit a white space
136  */
137 int
138 sip_find_white_space(_sip_header_t *sip_header)
139 {
140 	while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
141 		if (isspace(*sip_header->sip_hdr_current))
142 			return (0);
143 		sip_header->sip_hdr_current++;
144 	}
145 	return (1);
146 }
147 
148 /*
149  * Skip to the next non-whitespace
150  */
151 int
152 sip_skip_white_space(_sip_header_t *sip_header)
153 {
154 	while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
155 		if (!isspace(*sip_header->sip_hdr_current))
156 			return (0);
157 		sip_header->sip_hdr_current++;
158 	}
159 	return (1);
160 }
161 
162 
163 /*
164  * Skip to the non-white space in the reverse direction
165  */
166 int
167 sip_reverse_skip_white_space(_sip_header_t *sip_header)
168 {
169 	while (sip_header->sip_hdr_current >= sip_header->sip_hdr_start) {
170 		if (!isspace(*sip_header->sip_hdr_current))
171 			return (0);
172 		sip_header->sip_hdr_current--;
173 	}
174 	return (1);
175 }
176 
177 /*
178  * get to the first non space after ':'
179  */
180 int
181 sip_parse_goto_values(_sip_header_t *sip_header)
182 {
183 	if (sip_find_token(sip_header, SIP_HCOLON) !=  0)
184 		return (1);
185 	if (sip_skip_white_space(sip_header) != 0)
186 		return (1);
187 
188 	return (0);
189 }
190 
191 /*
192  * Skip the current value.
193  */
194 int
195 sip_goto_next_value(_sip_header_t *sip_header)
196 {
197 	boolean_t	quoted = B_FALSE;
198 
199 	while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
200 		if (*sip_header->sip_hdr_current == SIP_QUOTE) {
201 			if (quoted)
202 				quoted = B_FALSE;
203 			else
204 				quoted = B_TRUE;
205 		} else if (!quoted &&
206 		    *sip_header->sip_hdr_current == SIP_COMMA) {
207 			/*
208 			 * value ends before the COMMA
209 			 */
210 			sip_header->sip_hdr_current--;
211 			return (0);
212 		}
213 		sip_header->sip_hdr_current++;
214 	}
215 	if (quoted)
216 		return (1);
217 	return (0);
218 }
219 
220 /*
221  * Parse the header into parameter list. Parameters start with a ';'
222  */
223 int
224 sip_parse_params(_sip_header_t *sip_header, sip_param_t **parsed_list)
225 {
226 	sip_param_t	*param = NULL;
227 	sip_param_t	*new_param;
228 	char		*tmp_ptr;
229 
230 	if (parsed_list == NULL)
231 		return (0);
232 
233 	*parsed_list = NULL;
234 	for (;;) {
235 		boolean_t	quoted_name = B_FALSE;
236 
237 		/*
238 		 * First check if there are any params
239 		 */
240 		if (sip_skip_white_space(sip_header) != 0)
241 			return (0);
242 		if (*sip_header->sip_hdr_current != SIP_SEMI)
243 			return (0);
244 
245 		sip_header->sip_hdr_current++;
246 
247 		new_param = calloc(1, sizeof (sip_param_t));
248 		if (new_param == NULL)
249 			return (ENOMEM);
250 
251 		if (param != NULL)
252 			param->param_next = new_param;
253 		else
254 			*parsed_list = new_param;
255 
256 		param = new_param;
257 
258 		/*
259 		 * Let's get to the start of the param name
260 		 */
261 		if (sip_skip_white_space(sip_header) != 0)
262 			return (EPROTO);
263 		/*
264 		 * start of param name
265 		 */
266 		tmp_ptr = sip_header->sip_hdr_current;
267 		param->param_name.sip_str_ptr = tmp_ptr;
268 
269 		if (sip_find_separator(sip_header, SIP_EQUAL, SIP_SEMI,
270 		    SIP_COMMA) != 0) {
271 			param->param_name.sip_str_len =
272 			    sip_header->sip_hdr_current - tmp_ptr;
273 			param->param_value.sip_str_ptr = NULL;
274 			param->param_value.sip_str_len = 0;
275 			return (0);
276 		}
277 
278 		/*
279 		 * End of param name
280 		 */
281 		param->param_name.sip_str_len =
282 		    sip_header->sip_hdr_current - tmp_ptr;
283 
284 		if (sip_skip_white_space(sip_header) != 0 ||
285 		    *sip_header->sip_hdr_current == SIP_COMMA) {
286 			param->param_value.sip_str_ptr = NULL;
287 			param->param_value.sip_str_len = 0;
288 			return (0);
289 		}
290 		if (*sip_header->sip_hdr_current == SIP_SEMI) {
291 			param->param_value.sip_str_ptr = NULL;
292 			param->param_value.sip_str_len = 0;
293 			continue;
294 		}
295 		assert(*sip_header->sip_hdr_current == SIP_EQUAL);
296 
297 		/*
298 		 * We are at EQUAL, lets go beyond that
299 		 */
300 		sip_header->sip_hdr_current++;
301 
302 		if (sip_skip_white_space(sip_header) != 0)
303 			return (EPROTO);
304 
305 		if (*sip_header->sip_hdr_current == SIP_QUOTE) {
306 			sip_header->sip_hdr_current++;
307 			quoted_name = B_TRUE;
308 		}
309 
310 		/*
311 		 * start of param value
312 		 */
313 		param->param_value.sip_str_ptr = sip_header->sip_hdr_current;
314 		tmp_ptr = sip_header->sip_hdr_current;
315 
316 		if (quoted_name && sip_find_token(sip_header, SIP_QUOTE) != 0) {
317 			return (EPROTO);
318 		} else if (sip_find_separator(sip_header, SIP_SEMI, SIP_COMMA,
319 		    (char)NULL) != 0) {
320 			return (EPROTO);
321 		}
322 		param->param_value.sip_str_len = sip_header->sip_hdr_current -
323 		    tmp_ptr;
324 		if (quoted_name)
325 			param->param_value.sip_str_len--;
326 	}
327 }
328 
329 /*
330  * a header that only has "header_name : " is an empty header
331  * ":" must exist
332  * sip_hdr_current resets to sip_hdr_start before exit
333  */
334 boolean_t
335 sip_is_empty_hdr(_sip_header_t *sip_header)
336 {
337 	if (sip_find_token(sip_header, SIP_HCOLON) != 0) {
338 		sip_header->sip_hdr_current = sip_header->sip_hdr_start;
339 		return (B_FALSE);
340 	}
341 
342 	if (sip_skip_white_space(sip_header) == 0) {
343 		sip_header->sip_hdr_current = sip_header->sip_hdr_start;
344 		return (B_FALSE);
345 	}
346 
347 	sip_header->sip_hdr_current = sip_header->sip_hdr_start;
348 	return (B_TRUE);
349 }
350 
351 /*
352  * Parsing an empty header, i.e. only has a ":"
353  */
354 int
355 sip_parse_hdr_empty(_sip_header_t *hdr, sip_parsed_header_t **phdr)
356 {
357 	sip_parsed_header_t	*parsed_header;
358 
359 	if (hdr == NULL || phdr == NULL)
360 		return (EINVAL);
361 
362 	/*
363 	 * check if already parsed
364 	 */
365 	if (hdr->sip_hdr_parsed != NULL) {
366 		*phdr = hdr->sip_hdr_parsed;
367 		return (0);
368 	}
369 
370 	*phdr = NULL;
371 
372 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
373 	if (parsed_header == NULL)
374 		return (ENOMEM);
375 	parsed_header->sip_header = hdr;
376 
377 	parsed_header->value = NULL;
378 
379 	*phdr = parsed_header;
380 	return (0);
381 }
382 
383 /*
384  * validate uri str and parse uri using uri_parse()
385  */
386 static void
387 sip_parse_uri_str(sip_str_t *sip_str, sip_hdr_value_t *value)
388 {
389 	int		error;
390 
391 	/*
392 	 * Parse uri
393 	 */
394 	if (sip_str->sip_str_len > 0) {
395 		value->sip_value_parsed_uri = sip_parse_uri(sip_str, &error);
396 		if (value->sip_value_parsed_uri == NULL)
397 			return;
398 		if (error != 0 ||
399 		    value->sip_value_parsed_uri->sip_uri_errflags != 0) {
400 			value->sip_value_state = SIP_VALUE_BAD;
401 		}
402 	}
403 }
404 
405 /*
406  * Some basic common checks before parsing the headers
407  */
408 int
409 sip_prim_parsers(_sip_header_t *sip_header, sip_parsed_header_t **header)
410 {
411 	if (sip_header == NULL || header == NULL)
412 		return (EINVAL);
413 
414 	/*
415 	 * check if already parsed
416 	 */
417 	if (sip_header->sip_hdr_parsed != NULL) {
418 		*header = sip_header->sip_hdr_parsed;
419 		return (0);
420 	}
421 	*header = NULL;
422 
423 	assert(sip_header->sip_hdr_start == sip_header->sip_hdr_current);
424 
425 	if (sip_parse_goto_values(sip_header) != 0)
426 		return (EPROTO);
427 
428 	return (0);
429 }
430 
431 /*
432  * Parse SIP/2.0 string
433  */
434 int
435 sip_get_protocol_version(_sip_header_t *sip_header,
436     sip_proto_version_t *sip_proto_version)
437 {
438 	if (sip_skip_white_space(sip_header) != 0)
439 		return (1);
440 
441 	if (strncasecmp(sip_header->sip_hdr_current, SIP, strlen(SIP)) == 0) {
442 		sip_proto_version->name.sip_str_ptr =
443 		    sip_header->sip_hdr_current;
444 		sip_proto_version->name.sip_str_len = strlen(SIP);
445 
446 		if (sip_find_token(sip_header, SIP_SLASH) != 0)
447 			return (1);
448 		if (sip_skip_white_space(sip_header) != 0)
449 			return (1);
450 
451 		sip_proto_version->version.sip_str_ptr =
452 		    sip_header->sip_hdr_current;
453 		while (isdigit(*sip_header->sip_hdr_current)) {
454 			sip_header->sip_hdr_current++;
455 			if (sip_header->sip_hdr_current >=
456 			    sip_header->sip_hdr_end) {
457 				return (1);
458 			}
459 		}
460 		if (*sip_header->sip_hdr_current != SIP_PERIOD)
461 			return (1);
462 		sip_header->sip_hdr_current++;
463 
464 		if (!isdigit(*sip_header->sip_hdr_current))
465 			return (1);
466 		while (isdigit(*sip_header->sip_hdr_current)) {
467 			sip_header->sip_hdr_current++;
468 			if (sip_header->sip_hdr_current >=
469 			    sip_header->sip_hdr_end) {
470 				return (1);
471 			}
472 		}
473 
474 		sip_proto_version->version.sip_str_len =
475 		    sip_header->sip_hdr_current -
476 		    sip_proto_version->version.sip_str_ptr;
477 		return (0);
478 	}
479 	return (1);
480 }
481 
482 /*
483  * parser1 parses hdr format
484  *	header_name: val1[; par1=pval1;par2=pval2 ..][, val2[;parlist..] ]
485  *	val can be str1/str2 or str
486  * headers: Accept, Accept-Encode, Accept-lang, Allow, Content-disp,
487  *	    Content-Encode, Content-Lang, In-reply-to,
488  *	    Priority, Require, Supported, Unsupported
489  *	    Allow-Events, Event, Subscription-State
490  */
491 int
492 sip_parse_hdr_parser1(_sip_header_t *hdr, sip_parsed_header_t **phdr, char sep)
493 {
494 	sip_parsed_header_t	*parsed_header;
495 	int			ret;
496 	sip_hdr_value_t		*value = NULL;
497 	sip_hdr_value_t		*last_value = NULL;
498 
499 	if ((ret = sip_prim_parsers(hdr, phdr)) != 0)
500 		return (ret);
501 
502 	/*
503 	 * check if previously parsed
504 	 */
505 	if (*phdr != NULL) {
506 		hdr->sip_hdr_parsed = *phdr;
507 		return (0);
508 	}
509 
510 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
511 	if (parsed_header == NULL)
512 		return (ENOMEM);
513 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
514 	parsed_header->sip_header = hdr;
515 
516 	while (hdr->sip_hdr_current < hdr->sip_hdr_end) {
517 		value = calloc(1, sizeof (sip_hdr_value_t));
518 		if (value == NULL) {
519 			sip_free_phdr(parsed_header);
520 			return (ENOMEM);
521 		}
522 		if (last_value != NULL)
523 			last_value->sip_next_value = value;
524 		else
525 			parsed_header->value = (sip_value_t *)value;
526 
527 		value->sip_value_start = hdr->sip_hdr_current;
528 		value->sip_value_header = parsed_header;
529 
530 		if (sip_find_separator(hdr, sep, SIP_COMMA, SIP_SEMI) == 0) {
531 			char	c = *hdr->sip_hdr_current;
532 
533 			if (isspace(c) && sep == (char)NULL) {
534 				value->str_val_ptr = value->sip_value_start;
535 				value->str_val_len = hdr->sip_hdr_current -
536 				    value->sip_value_start;
537 				/*
538 				 * nothing at the end except space
539 				 */
540 				if (sip_skip_white_space(hdr) != 0) {
541 					value->sip_value_end =
542 					    hdr->sip_hdr_current;
543 					goto end;
544 				}
545 				/*
546 				 * white space skipped
547 				 */
548 				c = *(hdr->sip_hdr_current);
549 			}
550 
551 			/*
552 			 * only one string until COMMA, use sip_str_t
553 			 */
554 			if (c == SIP_COMMA) {
555 				char	*t = hdr->sip_hdr_current;
556 
557 				hdr->sip_hdr_current--;
558 				(void) sip_reverse_skip_white_space(hdr);
559 				value->str_val_ptr = value->sip_value_start;
560 				value->str_val_len = hdr->sip_hdr_current -
561 				    value->sip_value_start + 1;
562 				hdr->sip_hdr_current = t;
563 				goto get_next_val;
564 			}
565 
566 			/*
567 			 * two strings, use sip_2strs_t
568 			 */
569 			if ((sep != (char)NULL) && (c == sep)) {
570 				value->strs1_val_ptr = value->sip_value_start;
571 				value->strs1_val_len = hdr->sip_hdr_current -
572 				    value->sip_value_start;
573 
574 				value->strs2_val_ptr =
575 				    (++hdr->sip_hdr_current);
576 				if (sip_find_separator(hdr, SIP_SEMI, SIP_COMMA,
577 				    (char)NULL) == 0) {
578 					char t = *(hdr->sip_hdr_current);
579 					value->strs2_val_len =
580 					    hdr->sip_hdr_current -
581 						value->strs2_val_ptr;
582 					/*
583 					 * if COMMA, no param list, get next val
584 					 * if SEMI, need to set params list
585 					 */
586 					if (t == SIP_COMMA)
587 						goto get_next_val;
588 				} else { /* the last part */
589 					value->strs2_val_len =
590 					    hdr->sip_hdr_current -
591 						value->strs2_val_ptr;
592 					value->sip_value_end =
593 					    hdr->sip_hdr_current;
594 					goto end;
595 				}
596 			} else if (sep != (char)NULL) {
597 				value->sip_value_state = SIP_VALUE_BAD;
598 				goto get_next_val;
599 			}
600 
601 			/*
602 			 * c == SEMI, value contains single string
603 			 * only one string until SEMI, use sip_str_t
604 			 */
605 			if (c == SIP_SEMI) {
606 				char	*t = hdr->sip_hdr_current;
607 
608 				hdr->sip_hdr_current--;
609 				/*
610 				 * get rid of SP at end of value field
611 				 */
612 				(void) sip_reverse_skip_white_space(hdr);
613 				value->str_val_ptr = value->sip_value_start;
614 				value->str_val_len = hdr->sip_hdr_current -
615 				    value->str_val_ptr + 1;
616 				hdr->sip_hdr_current = t;
617 			}
618 
619 			/*
620 			 * if SEMI exists in the value, set params list
621 			 * two situations, there is or not SLASH before SEMI
622 			 */
623 			ret = sip_parse_params(hdr, &value->sip_param_list);
624 			if (ret == EPROTO) {
625 				value->sip_value_state = SIP_VALUE_BAD;
626 			} else if (ret != 0) {
627 				sip_free_phdr(parsed_header);
628 				return (ret);
629 			}
630 			goto get_next_val;
631 		} else {
632 			value->str_val_ptr = value->sip_value_start;
633 			value->str_val_len = hdr->sip_hdr_current -
634 			    value->sip_value_start;
635 			value->sip_value_end = hdr->sip_hdr_current;
636 			goto end;
637 		}
638 get_next_val:
639 		if (sip_find_token(hdr, SIP_COMMA) != 0) {
640 			value->sip_value_end = hdr->sip_hdr_current;
641 			break;
642 		}
643 		value->sip_value_end = hdr->sip_hdr_current - 1;
644 		last_value = value;
645 		(void) sip_skip_white_space(hdr);
646 	}
647 
648 end:
649 	*phdr = parsed_header;
650 	hdr->sip_hdr_parsed = *phdr;
651 	return (0);
652 }
653 
654 /*
655  * header_name: int
656  * headers: Expires, Min-Expires
657  */
658 /* ARGSUSED */
659 int
660 sip_parse_hdr_parser2(_sip_header_t *hdr, sip_parsed_header_t **phdr,
661     int val_type)
662 {
663 	sip_parsed_header_t	*parsed_header;
664 	int			ret = 0;
665 	sip_hdr_value_t		*value = NULL;
666 
667 	if ((ret = sip_prim_parsers(hdr, phdr)) != 0)
668 		return (ret);
669 
670 	/*
671 	 * check if previously parsed
672 	 */
673 	if (*phdr != NULL) {
674 		hdr->sip_hdr_parsed = *phdr;
675 		return (0);
676 	}
677 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
678 	if (parsed_header == NULL)
679 		return (ENOMEM);
680 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
681 	parsed_header->sip_header = hdr;
682 
683 	value = calloc(1, sizeof (sip_hdr_value_t));
684 	if (value == NULL) {
685 		sip_free_phdr(parsed_header);
686 		return (ENOMEM);
687 	}
688 
689 	parsed_header->value = (sip_value_t *)value;
690 
691 	value->sip_value_start = hdr->sip_hdr_current;
692 	value->sip_value_header = parsed_header;
693 
694 	ret = sip_atoi(hdr, &value->int_val);
695 	if (ret != 0) {
696 		value->int_val = 0;
697 		value->sip_value_state = SIP_VALUE_BAD;
698 	}
699 
700 	value->sip_value_end = hdr->sip_hdr_current - 1;
701 
702 	*phdr = parsed_header;
703 	hdr->sip_hdr_parsed = *phdr;
704 	return (0);
705 }
706 
707 /*
708  * parser3 parses hdr format
709  * header_name: <val1>[, <val2>]
710  * Alert-Info, Call-Info, Error-Info, reply-to
711  */
712 int
713 sip_parse_hdr_parser3(_sip_header_t *hdr, sip_parsed_header_t **phdr, int type,
714     boolean_t parse_uri)
715 {
716 	sip_parsed_header_t	*parsed_header;
717 	sip_hdr_value_t		*value = NULL;
718 	sip_hdr_value_t		*last_value = NULL;
719 	int			ret;
720 
721 	if ((ret = sip_prim_parsers(hdr, phdr)) != 0)
722 		return (ret);
723 
724 	/*
725 	 * check if previously parsed
726 	 */
727 	if (*phdr != NULL) {
728 		hdr->sip_hdr_parsed = *phdr;
729 		return (0);
730 	}
731 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
732 	if (parsed_header == NULL)
733 		return (ENOMEM);
734 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
735 	parsed_header->sip_header = hdr;
736 	while (hdr->sip_hdr_current < hdr->sip_hdr_end) {
737 		int		r;
738 
739 		value = calloc(1, sizeof (sip_hdr_value_t));
740 		if (value == NULL) {
741 			sip_free_phdr(parsed_header);
742 			return (ENOMEM);
743 		}
744 
745 		if (last_value != NULL)
746 			last_value->sip_next_value = value;
747 		else
748 			parsed_header->value = (sip_value_t *)value;
749 
750 		value->sip_value_start = hdr->sip_hdr_current;
751 		value->sip_value_header = parsed_header;
752 
753 		if (type == SIP_STRS_VAL) {
754 			if (sip_find_token(hdr, SIP_LAQUOT) == 0) {
755 				char	*cur;
756 
757 				/*
758 				 * record the position after LAQUOT
759 				 */
760 				cur = hdr->sip_hdr_current;
761 				/*
762 				 * get display name and store in str1
763 				 */
764 				hdr->sip_hdr_current = value->sip_value_start;
765 				if (*(hdr->sip_hdr_current) != SIP_LAQUOT) {
766 					/*
767 					 * record start pos of display name
768 					 */
769 					char	*tmp = hdr->sip_hdr_current;
770 
771 					if (*hdr->sip_hdr_current ==
772 					    SIP_QUOTE) {
773 						hdr->sip_hdr_current++;
774 						tmp++;
775 						if (sip_find_token(hdr,
776 						    SIP_QUOTE) != 0) {
777 							value->sip_value_state =
778 							    SIP_VALUE_BAD;
779 							goto get_next_val;
780 						}
781 						hdr->sip_hdr_current -= 2;
782 					} else {
783 						hdr->sip_hdr_current = cur - 2;
784 						(void)
785 						    sip_reverse_skip_white_space
786 						    (hdr);
787 					}
788 					value->strs1_val_ptr = tmp;
789 					value->strs1_val_len =
790 					    hdr->sip_hdr_current - tmp + 1;
791 				} else {
792 					value->strs1_val_ptr = NULL;
793 					value->strs1_val_len = 0;
794 				}
795 
796 				/*
797 				 * set current to the char after LAQUOT
798 				 */
799 				hdr->sip_hdr_current = cur;
800 				value->strs2_val_ptr = hdr->sip_hdr_current;
801 				if (sip_find_token(hdr, SIP_RAQUOT)) {
802 					/*
803 					 * no RAQUOT
804 					 */
805 					value->strs1_val_ptr = NULL;
806 					value->strs1_val_len = 0;
807 					value->strs2_val_ptr = NULL;
808 					value->strs2_val_len = 0;
809 					value->sip_value_state = SIP_VALUE_BAD;
810 					goto get_next_val;
811 				}
812 				value->strs2_val_len = hdr->sip_hdr_current -
813 				    value->strs2_val_ptr - 1;
814 			} else {
815 				char	*cur;
816 
817 				/*
818 				 * No display name - Only URI.
819 				 */
820 				value->strs1_val_ptr = NULL;
821 				value->strs1_val_len = 0;
822 				cur = value->sip_value_start;
823 				hdr->sip_hdr_current = cur;
824 				if (sip_find_separator(hdr, SIP_COMMA,
825 				    (char)NULL, (char)NULL) != 0) {
826 					value->strs2_val_ptr = cur;
827 					value->strs2_val_len =
828 					    hdr->sip_hdr_current -
829 					    value->strs2_val_ptr - 1;
830 				} else if (*hdr->sip_hdr_current == SIP_SP) {
831 					value->strs2_val_ptr = cur;
832 					cur = hdr->sip_hdr_current - 1;
833 					if (sip_skip_white_space(hdr) != 0) {
834 						value->strs2_val_len = cur -
835 						    value->strs2_val_ptr - 1;
836 					} else if (*hdr->sip_hdr_current ==
837 					    SIP_COMMA) {
838 						value->strs2_val_len = cur -
839 						    value->strs2_val_ptr - 1;
840 					} else {
841 						value->sip_value_state =
842 						    SIP_VALUE_BAD;
843 						goto get_next_val;
844 					}
845 				} else {
846 					value->strs2_val_ptr = cur;
847 					value->strs2_val_len =
848 					    hdr->sip_hdr_current -
849 					    value->strs2_val_ptr;
850 				}
851 			}
852 			if (parse_uri)
853 				sip_parse_uri_str(&value->strs_s2, value);
854 		}
855 
856 		if (type == SIP_STR_VAL) {
857 			/*
858 			 * alert-info, error-info, call-info
859 			 */
860 			if (sip_find_token(hdr, SIP_LAQUOT) == 0) {
861 				value->str_val_ptr = hdr->sip_hdr_current;
862 				if (sip_find_token(hdr, SIP_RAQUOT) == 0) {
863 					value->str_val_len =
864 					    hdr->sip_hdr_current -
865 						value->str_val_ptr - 1;
866 				} else {
867 					value->str_val_ptr = NULL;
868 					value->str_val_len = 0;
869 					value->sip_value_state = SIP_VALUE_BAD;
870 					goto get_next_val;
871 				}
872 				hdr->sip_hdr_current--;
873 			} else {
874 				value->str_val_ptr = NULL;
875 				value->str_val_len = 0;
876 				value->sip_value_state = SIP_VALUE_BAD;
877 				goto get_next_val;
878 			}
879 			if (parse_uri)
880 				sip_parse_uri_str(&value->str_val, value);
881 		}
882 
883 		r = sip_find_separator(hdr, SIP_COMMA, SIP_SEMI, (char)NULL);
884 		if (r != 0) {
885 			value->sip_value_end = hdr->sip_hdr_current;
886 			goto end;
887 		}
888 		if (*hdr->sip_hdr_current == SIP_SEMI) {
889 			(void) sip_parse_params(hdr,
890 			    &(value->sip_param_list));
891 			goto get_next_val;
892 		}
893 
894 		if (*hdr->sip_hdr_current == SIP_COMMA) {
895 			hdr->sip_hdr_current--;
896 			goto get_next_val;
897 		}
898 get_next_val:
899 		if (sip_find_token(hdr, SIP_COMMA) != 0) {
900 			value->sip_value_end = hdr->sip_hdr_current;
901 			break;
902 		}
903 		value->sip_value_end = hdr->sip_hdr_current - 1;
904 		last_value = value;
905 		(void) sip_skip_white_space(hdr);
906 	}
907 
908 end:
909 	*phdr = parsed_header;
910 	hdr->sip_hdr_parsed = *phdr;
911 	return (0);
912 }
913 
914 /*
915  * parser4 parses hdr format, the whole field is one single str
916  * header: Subject, MIME-Version, Organization, Server, User-Agent
917  */
918 int
919 sip_parse_hdr_parser4(_sip_header_t *hdr, sip_parsed_header_t **phdr)
920 {
921 	sip_parsed_header_t	*parsed_header;
922 	sip_hdr_value_t		*value = NULL;
923 	int			ret;
924 
925 	if ((ret = sip_prim_parsers(hdr, phdr)) != 0)
926 		return (ret);
927 
928 	/*
929 	 * check if previously parsed
930 	 */
931 	if (*phdr != NULL) {
932 		hdr->sip_hdr_parsed = *phdr;
933 		return (0);
934 	}
935 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
936 	if (parsed_header == NULL)
937 		return (ENOMEM);
938 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
939 	parsed_header->sip_header = hdr;
940 
941 	value = calloc(1, sizeof (sip_hdr_value_t));
942 	if (value == NULL) {
943 		sip_free_phdr(parsed_header);
944 		return (ENOMEM);
945 	}
946 
947 	parsed_header->value = (sip_value_t *)value;
948 
949 	value->sip_value_start = hdr->sip_hdr_current;
950 	value->sip_value_header = parsed_header;
951 
952 	value->str_val_ptr = hdr->sip_hdr_current;
953 	/*
954 	 * get rid of CRLF at end
955 	 */
956 	value->str_val_len = hdr->sip_hdr_end - value->str_val_ptr - 2;
957 	value->sip_value_end = hdr->sip_hdr_end;
958 
959 	*phdr = parsed_header;
960 	hdr->sip_hdr_parsed = *phdr;
961 	return (0);
962 }
963 
964 int
965 sip_parse_hdr_parser5(_sip_header_t *hdr, sip_parsed_header_t **phdr,
966     boolean_t parse_uri)
967 {
968 	sip_parsed_header_t	*parsed_header;
969 	sip_hdr_value_t		*value = NULL;
970 	sip_param_t		*tmp_param;
971 	boolean_t		first_param = B_TRUE;
972 	int			ret;
973 
974 	if ((ret = sip_prim_parsers(hdr, phdr)) != 0)
975 		return (ret);
976 
977 	/*
978 	 * check if previously parsed
979 	 */
980 	if (*phdr != NULL) {
981 		hdr->sip_hdr_parsed = *phdr;
982 		return (0);
983 	}
984 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
985 	if (parsed_header == NULL)
986 		return (ENOMEM);
987 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
988 	parsed_header->sip_header = hdr;
989 
990 	value = calloc(1, sizeof (sip_hdr_value_t));
991 	if (value == NULL) {
992 		sip_free_phdr(parsed_header);
993 		return (ENOMEM);
994 	}
995 
996 	parsed_header->value = (sip_value_t *)value;
997 
998 	value->sip_value_start = hdr->sip_hdr_current;
999 	value->auth_scheme_ptr = value->sip_value_start;
1000 	value->sip_value_header = parsed_header;
1001 	/*
1002 	 * get auth_scheme
1003 	 */
1004 	if (sip_find_white_space(hdr)) {
1005 		value->sip_value_state = SIP_VALUE_BAD;
1006 		return (EINVAL);
1007 	}
1008 	value->auth_scheme_len = hdr->sip_hdr_current - value->auth_scheme_ptr;
1009 
1010 	tmp_param = value->auth_param;
1011 
1012 	/*
1013 	 * parse auth_param
1014 	 */
1015 	for (;;) {
1016 		char		*tmp_cur;
1017 		boolean_t	quoted_name = B_FALSE;
1018 		char		quoted_char = (char)0;
1019 		sip_param_t	*new_param;
1020 		boolean_t	pval_is_uri = B_FALSE;
1021 
1022 		if (sip_skip_white_space(hdr) != 0) {
1023 			value->sip_value_state = SIP_VALUE_BAD;
1024 			return (EPROTO);
1025 		}
1026 		tmp_cur = hdr->sip_hdr_current;
1027 
1028 		new_param = calloc(1, sizeof (sip_param_t));
1029 		if (new_param == NULL)
1030 			return (ENOMEM);
1031 
1032 		if (first_param == B_FALSE)
1033 			tmp_param->param_next = new_param;
1034 		else
1035 			value->auth_param = new_param;
1036 
1037 		tmp_param = new_param;
1038 		tmp_param->param_name.sip_str_ptr = tmp_cur;
1039 
1040 		if (sip_find_separator(hdr, SIP_EQUAL, SIP_COMMA, (char)NULL) !=
1041 		    0) {
1042 			tmp_param->param_name.sip_str_len =
1043 			    hdr->sip_hdr_current - tmp_cur;
1044 			tmp_param->param_value.sip_str_ptr = NULL;
1045 			tmp_param->param_value.sip_str_len = 0;
1046 			value->sip_value_end = hdr->sip_hdr_current;
1047 			goto end;
1048 		}
1049 
1050 		/*
1051 		 * End of param name
1052 		 */
1053 		tmp_param->param_name.sip_str_len = hdr->sip_hdr_current -
1054 		    tmp_cur;
1055 
1056 		if (sip_skip_white_space(hdr) != 0 ||
1057 		    *hdr->sip_hdr_current == SIP_COMMA) {
1058 			tmp_param->param_value.sip_str_ptr = NULL;
1059 			tmp_param->param_value.sip_str_len = 0;
1060 			continue;
1061 		}
1062 
1063 		/*
1064 		 * We are at EQUAL
1065 		 */
1066 		hdr->sip_hdr_current++;
1067 
1068 		if (sip_skip_white_space(hdr) != 0) {
1069 			value->sip_value_state = SIP_VALUE_BAD;
1070 			free(tmp_param);
1071 			return (EPROTO);
1072 		}
1073 
1074 		if (*hdr->sip_hdr_current == SIP_QUOTE ||
1075 		    *hdr->sip_hdr_current == SIP_LAQUOT) {
1076 			if (*hdr->sip_hdr_current == SIP_QUOTE)
1077 				quoted_char = SIP_QUOTE;
1078 			else {
1079 				quoted_char = SIP_RAQUOT;
1080 				pval_is_uri = B_TRUE;
1081 			}
1082 			hdr->sip_hdr_current++;
1083 			quoted_name = B_TRUE;
1084 		}
1085 
1086 		/*
1087 		 * start of param value
1088 		 */
1089 		tmp_cur = hdr->sip_hdr_current;
1090 		tmp_param->param_value.sip_str_ptr = tmp_cur;
1091 		if (quoted_name) {
1092 			if (sip_find_token(hdr, quoted_char) != 0) {
1093 				value->sip_value_state = SIP_VALUE_BAD;
1094 				free(tmp_param);
1095 				return (EPROTO);
1096 			}
1097 			tmp_param->param_value.sip_str_len =
1098 			    hdr->sip_hdr_current - tmp_cur - 1;
1099 		}
1100 
1101 		if (sip_find_token(hdr, SIP_COMMA) != 0) {
1102 			value->sip_value_end = hdr->sip_hdr_current;
1103 			goto end;
1104 		} else {
1105 			if (!quoted_name) {
1106 				char *t = hdr->sip_hdr_current;
1107 				hdr->sip_hdr_current--;
1108 				(void) sip_reverse_skip_white_space(hdr);
1109 				tmp_param->param_value.sip_str_len =
1110 				    hdr->sip_hdr_current - tmp_cur;
1111 				hdr->sip_hdr_current = t;
1112 			}
1113 		}
1114 
1115 		if (first_param == B_TRUE)
1116 			first_param = B_FALSE;
1117 
1118 		/*
1119 		 * Parse uri
1120 		 */
1121 		if (pval_is_uri && parse_uri)
1122 			sip_parse_uri_str(&tmp_param->param_value, value);
1123 
1124 	}
1125 
1126 end:
1127 	*phdr = parsed_header;
1128 	hdr->sip_hdr_parsed = *phdr;
1129 	return (0);
1130 }
1131 
1132 /*
1133  * Return the URI in the request startline
1134  */
1135 static int
1136 _sip_get_request_uri(_sip_header_t *sip_header, sip_message_type_t *msg_info)
1137 {
1138 	int	size = 0;
1139 	char	*start_ptr;
1140 
1141 	if (sip_skip_white_space(sip_header) != 0)
1142 		return (EINVAL);
1143 	start_ptr = sip_header->sip_hdr_current;
1144 
1145 	while (!isspace(*sip_header->sip_hdr_current)) {
1146 		if (sip_header->sip_hdr_current >= sip_header->sip_hdr_end)
1147 			return (EINVAL);
1148 		sip_header->sip_hdr_current++;
1149 	}
1150 
1151 	size = sip_header->sip_hdr_current - start_ptr;
1152 
1153 	msg_info->U.sip_request.sip_request_uri.sip_str_ptr = start_ptr;
1154 	msg_info->U.sip_request.sip_request_uri.sip_str_len = size;
1155 	if (size > 0) {	/* Parse uri */
1156 		int		error;
1157 
1158 		msg_info->U.sip_request.sip_parse_uri = sip_parse_uri(
1159 		    &msg_info->U.sip_request.sip_request_uri, &error);
1160 		if (msg_info->U.sip_request.sip_parse_uri == NULL)
1161 			return (error);
1162 	}
1163 	return (0);
1164 }
1165 
1166 /*
1167  * Parse the start line into request/response
1168  */
1169 int
1170 sip_parse_first_line(_sip_header_t *sip_header, sip_message_type_t **msg_info)
1171 {
1172 	sip_message_type_t	*sip_msg_info;
1173 	boolean_t		sip_is_request = B_TRUE;
1174 	int			ret;
1175 
1176 	if (sip_header == NULL || msg_info == NULL)
1177 		return (EINVAL);
1178 
1179 	if (sip_skip_white_space(sip_header) != 0)
1180 		return (EPROTO);
1181 
1182 	/*
1183 	 * There is nothing, return
1184 	 */
1185 	if (sip_header->sip_hdr_current + strlen(SIP_VERSION) >=
1186 	    sip_header->sip_hdr_end) {
1187 		return (EPROTO);
1188 	}
1189 #ifdef	__solaris__
1190 	assert(mutex_held(&sip_header->sip_hdr_sipmsg->sip_msg_mutex));
1191 #endif
1192 	sip_msg_info = malloc(sizeof (sip_message_type_t));
1193 	if (sip_msg_info == NULL)
1194 		return (ENOMEM);
1195 
1196 	/*
1197 	 * let's see if it's a request or a response
1198 	 */
1199 	ret = sip_get_protocol_version(sip_header,
1200 	    &sip_msg_info->sip_proto_version);
1201 	if (ret == 0) {
1202 		sip_is_request = B_FALSE;
1203 	} else if (ret == 2) {
1204 		free(sip_msg_info);
1205 		return (EPROTO);
1206 	}
1207 
1208 	if (sip_skip_white_space(sip_header) != 0) {
1209 		free(sip_msg_info);
1210 		return (EPROTO);
1211 	}
1212 
1213 	if (!sip_is_request) {
1214 		/*
1215 		 * check for status code.
1216 		 */
1217 		if (sip_skip_white_space(sip_header) != 0) {
1218 			free(sip_msg_info);
1219 			return (EPROTO);
1220 		}
1221 		if (sip_header->sip_hdr_current + SIP_SIZE_OF_STATUS_CODE >=
1222 		    sip_header->sip_hdr_end) {
1223 			free(sip_msg_info);
1224 			return (EPROTO);
1225 		}
1226 
1227 		if (sip_atoi(sip_header,
1228 		    &sip_msg_info->U.sip_response.sip_response_code)) {
1229 			free(sip_msg_info);
1230 			return (EPROTO);
1231 		}
1232 
1233 		if (sip_msg_info->U.sip_response.sip_response_code < 100 ||
1234 		    sip_msg_info->U.sip_response.sip_response_code > 700) {
1235 			free(sip_msg_info);
1236 			return (EPROTO);
1237 		}
1238 
1239 		/*
1240 		 * get reason phrase.
1241 		 */
1242 		if (sip_skip_white_space(sip_header) != 0) {
1243 			sip_msg_info->sip_resp_phrase_len = 0;
1244 			sip_msg_info->sip_resp_phrase_ptr = NULL;
1245 		} else {
1246 			sip_msg_info->sip_resp_phrase_ptr =
1247 			    sip_header->sip_hdr_current;
1248 			if (sip_find_cr(sip_header) != 0) {
1249 				free(sip_msg_info);
1250 				return (EPROTO);
1251 			}
1252 			sip_msg_info->sip_resp_phrase_len =
1253 			    sip_header->sip_hdr_current -
1254 			    sip_msg_info->sip_resp_phrase_ptr;
1255 		}
1256 		sip_msg_info->is_request = B_FALSE;
1257 	} else {
1258 		int i;
1259 		/*
1260 		 * It's a request.
1261 		 */
1262 		sip_msg_info->is_request = B_TRUE;
1263 		for (i = 1; i < MAX_SIP_METHODS; i++) {
1264 			if (strncmp(sip_methods[i].name,
1265 			    sip_header->sip_hdr_current,
1266 			    sip_methods[i].len) == 0) {
1267 				sip_msg_info->sip_req_method = i;
1268 				sip_header->sip_hdr_current +=
1269 				    sip_methods[i].len;
1270 				if (!isspace(*sip_header->sip_hdr_current++) ||
1271 				    !isalpha(*sip_header->sip_hdr_current)) {
1272 					free(sip_msg_info);
1273 					return (EPROTO);
1274 				}
1275 
1276 				if ((ret = _sip_get_request_uri(sip_header,
1277 				    sip_msg_info)) != 0) {
1278 					free(sip_msg_info);
1279 					return (ret);
1280 				}
1281 
1282 				/*
1283 				 * Get SIP version
1284 				 */
1285 				ret = sip_get_protocol_version(sip_header,
1286 				    &sip_msg_info->sip_proto_version);
1287 				if (ret != 0) {
1288 					free(sip_msg_info);
1289 					return (EPROTO);
1290 				}
1291 				goto done;
1292 			}
1293 		}
1294 		free(sip_msg_info);
1295 		return (EPROTO);
1296 	}
1297 done:
1298 	sip_msg_info->sip_next = *msg_info;
1299 	*msg_info = sip_msg_info;
1300 	return (0);
1301 }
1302