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