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