140cb5e5dSvi /*
240cb5e5dSvi  * CDDL HEADER START
340cb5e5dSvi  *
440cb5e5dSvi  * The contents of this file are subject to the terms of the
540cb5e5dSvi  * Common Development and Distribution License (the "License").
640cb5e5dSvi  * You may not use this file except in compliance with the License.
740cb5e5dSvi  *
840cb5e5dSvi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
940cb5e5dSvi  * or http://www.opensolaris.org/os/licensing.
1040cb5e5dSvi  * See the License for the specific language governing permissions
1140cb5e5dSvi  * and limitations under the License.
1240cb5e5dSvi  *
1340cb5e5dSvi  * When distributing Covered Code, include this CDDL HEADER in each
1440cb5e5dSvi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1540cb5e5dSvi  * If applicable, add the following below this CDDL HEADER, with the
1640cb5e5dSvi  * fields enclosed by brackets "[]" replaced with your own identifying
1740cb5e5dSvi  * information: Portions Copyright [yyyy] [name of copyright owner]
1840cb5e5dSvi  *
1940cb5e5dSvi  * CDDL HEADER END
2040cb5e5dSvi  */
2140cb5e5dSvi 
2240cb5e5dSvi /*
232c2c4183Svi  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
2440cb5e5dSvi  * Use is subject to license terms.
2540cb5e5dSvi  */
2640cb5e5dSvi 
272c2c4183Svi #include <ctype.h>
282c2c4183Svi #include <errno.h>
292c2c4183Svi #include <stdlib.h>
302c2c4183Svi #include <strings.h>
312c2c4183Svi #include <sip.h>
322c2c4183Svi 
3340cb5e5dSvi #include "sip_msg.h"
3440cb5e5dSvi #include "sip_miscdefs.h"
3540cb5e5dSvi #include "sip_parse_generic.h"
362c2c4183Svi #include "sip_parse_uri.h"
372c2c4183Svi 
3840cb5e5dSvi 
3940cb5e5dSvi /*
4040cb5e5dSvi  * Accept = "Accept" HCOLON [ accept-range *(COMMA accept-range) ]
4140cb5e5dSvi  * accept-range = media-range *(SEMI accept-param)
4240cb5e5dSvi  * media-range = ("* / *" |  (m-type SLASH "*") | (m-type SLASH m-subtype))
4340cb5e5dSvi  *		*(SEMI m-param)
4440cb5e5dSvi  * accept-param = ("q" EQUAL qvalue) | generic-param
4540cb5e5dSvi  * qvalue = ("0" ["." 0*3DIGIT]) | ("1" ["." 0*3DIGIT])
4640cb5e5dSvi  * generic-param = token [ EQUAL gen-value]
4740cb5e5dSvi  * gen-value = token | host | quoted-str
4840cb5e5dSvi  */
4940cb5e5dSvi int
sip_parse_acpt_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)5040cb5e5dSvi sip_parse_acpt_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
5140cb5e5dSvi {
5240cb5e5dSvi 	if (sip_is_empty_hdr(sip_header))
5340cb5e5dSvi 		return (sip_parse_hdr_empty(sip_header, header));
5440cb5e5dSvi 	return (sip_parse_hdr_parser1(sip_header, header, SIP_SLASH));
5540cb5e5dSvi }
5640cb5e5dSvi 
5740cb5e5dSvi /*
5840cb5e5dSvi  * Accept-Encoding = "Accept-Encoding" ":" 1#(codings [ ";" "q" "=" qval])
5940cb5e5dSvi  * codings = (content-coding | "*")
6040cb5e5dSvi  * content-coding = token
6140cb5e5dSvi  */
6240cb5e5dSvi int
sip_parse_acpt_encode_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)6340cb5e5dSvi sip_parse_acpt_encode_header(_sip_header_t *sip_header,
64*559f8b54SToomas Soome     sip_parsed_header_t **header)
6540cb5e5dSvi {
66*559f8b54SToomas Soome 	return (sip_parse_hdr_parser1(sip_header, header, 0));
6740cb5e5dSvi }
6840cb5e5dSvi 
6940cb5e5dSvi /*
7040cb5e5dSvi  * Accept-Language = "Accept-Language" ":" [ lang * (COMMA lang) ]
7140cb5e5dSvi  * lang = lang-range *(SEMI accept-param)
7240cb5e5dSvi  * lang-range = ((1*8ALPHA * ("-" 1*8ALPHA)) | "*"
7340cb5e5dSvi  */
7440cb5e5dSvi int
sip_parse_acpt_lang_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)7540cb5e5dSvi sip_parse_acpt_lang_header(_sip_header_t *sip_header,
76*559f8b54SToomas Soome     sip_parsed_header_t **header)
7740cb5e5dSvi {
7840cb5e5dSvi 	if (sip_is_empty_hdr(sip_header))
7940cb5e5dSvi 		return (sip_parse_hdr_empty(sip_header, header));
80*559f8b54SToomas Soome 	return (sip_parse_hdr_parser1(sip_header, header, 0));
8140cb5e5dSvi }
8240cb5e5dSvi 
8340cb5e5dSvi /*
8440cb5e5dSvi  * Alert-Info = "Alert-Info" ":" alert-param *(COMMA alert-param)
8540cb5e5dSvi  * alert-param = LAQUOT absoluteURI RAQUOT * (SEMI generic-param)
8640cb5e5dSvi  */
8740cb5e5dSvi int
sip_parse_alert_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)8840cb5e5dSvi sip_parse_alert_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
8940cb5e5dSvi {
9040cb5e5dSvi 	return (sip_parse_hdr_parser3(sip_header, header, SIP_STR_VAL, B_TRUE));
9140cb5e5dSvi }
9240cb5e5dSvi 
9340cb5e5dSvi /*
9440cb5e5dSvi  * Allow = "Allow" ":" method-name1[, method-name2..]
9540cb5e5dSvi  */
9640cb5e5dSvi int
sip_parse_allow_header(_sip_header_t * hdr,sip_parsed_header_t ** phdr)9740cb5e5dSvi sip_parse_allow_header(_sip_header_t *hdr, sip_parsed_header_t **phdr)
9840cb5e5dSvi {
9940cb5e5dSvi 	sip_parsed_header_t	*parsed_header;
10040cb5e5dSvi 	sip_hdr_value_t		*value = NULL;
10140cb5e5dSvi 	sip_hdr_value_t		*last_value = NULL;
10240cb5e5dSvi 	int			len;
10340cb5e5dSvi 	int			i;
10440cb5e5dSvi 	int			ret;
10540cb5e5dSvi 	boolean_t		multi_value = B_FALSE;
10640cb5e5dSvi 
10740cb5e5dSvi 	if ((ret = sip_prim_parsers(hdr, phdr)) != 0)
10840cb5e5dSvi 		return (ret);
10940cb5e5dSvi 
11040cb5e5dSvi 	if (*phdr != NULL)
11140cb5e5dSvi 		return (0);
11240cb5e5dSvi 
11340cb5e5dSvi 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
11440cb5e5dSvi 	if (parsed_header == NULL)
11540cb5e5dSvi 		return (ENOMEM);
11640cb5e5dSvi 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
11740cb5e5dSvi 	parsed_header->sip_header = hdr;
11840cb5e5dSvi 
11940cb5e5dSvi 	while (hdr->sip_hdr_current < hdr->sip_hdr_end) {
12040cb5e5dSvi 		value = calloc(1, sizeof (sip_hdr_value_t));
12140cb5e5dSvi 		if (value == NULL) {
12240cb5e5dSvi 			sip_free_phdr(parsed_header);
12340cb5e5dSvi 			return (ENOMEM);
12440cb5e5dSvi 		}
12540cb5e5dSvi 		if (last_value != NULL)
12640cb5e5dSvi 			last_value->sip_next_value = value;
12740cb5e5dSvi 		else
12840cb5e5dSvi 			parsed_header->value = (sip_value_t *)value;
12940cb5e5dSvi 
13040cb5e5dSvi 		value->sip_value_start = hdr->sip_hdr_current;
13140cb5e5dSvi 		value->sip_value_header = parsed_header;
13240cb5e5dSvi 
133*559f8b54SToomas Soome 		if (sip_find_separator(hdr, SIP_COMMA, 0, 0, B_FALSE) == 0) {
13440cb5e5dSvi 			multi_value = B_TRUE;
13540cb5e5dSvi 		}
13640cb5e5dSvi 
13740cb5e5dSvi 		len = hdr->sip_hdr_current - value->sip_value_start;
13840cb5e5dSvi 		for (i = 1; i < MAX_SIP_METHODS; i++) {
13940cb5e5dSvi 			if (strncmp(sip_methods[i].name, value->sip_value_start,
14040cb5e5dSvi 			    len) == 0) {
14140cb5e5dSvi 				break;
14240cb5e5dSvi 			}
14340cb5e5dSvi 		}
14440cb5e5dSvi 		if (i >= MAX_SIP_METHODS) {
14540cb5e5dSvi 			value->int_val = 0;
14640cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
14740cb5e5dSvi 			if (multi_value)
14840cb5e5dSvi 				goto next_val;
14940cb5e5dSvi 			else
15040cb5e5dSvi 				goto end;
15140cb5e5dSvi 		}
15240cb5e5dSvi 		value->int_val = i;
15340cb5e5dSvi 		if (!multi_value)
15440cb5e5dSvi 			goto end;
15540cb5e5dSvi 	next_val:
15640cb5e5dSvi 		if (sip_find_token(hdr, SIP_COMMA) != 0)
15740cb5e5dSvi 			break;
15840cb5e5dSvi 		value->sip_value_end = hdr->sip_hdr_current - 1;
15940cb5e5dSvi 		last_value = value;
16040cb5e5dSvi 		(void) sip_skip_white_space(hdr);
16140cb5e5dSvi 	}
16240cb5e5dSvi 
16340cb5e5dSvi end:
16440cb5e5dSvi 	*phdr = parsed_header;
16540cb5e5dSvi 	return (0);
16640cb5e5dSvi }
16740cb5e5dSvi 
16840cb5e5dSvi 
16940cb5e5dSvi /*
17040cb5e5dSvi  * Call-Info = "Call-Info" HCOLON info * (COMMA info)
17140cb5e5dSvi  * info = LAQUOT absoluteURI RAQUOT * (SEMI info-param)
17240cb5e5dSvi  * info-param = ("purpose" EQUAL ("icon" | "info" | "card" | token)) |
17340cb5e5dSvi  *		 generic-param
17440cb5e5dSvi  */
17540cb5e5dSvi int
sip_parse_callinfo_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)17640cb5e5dSvi sip_parse_callinfo_header(_sip_header_t *sip_header,
17740cb5e5dSvi     sip_parsed_header_t **header)
17840cb5e5dSvi {
17940cb5e5dSvi 	return (sip_parse_hdr_parser3(sip_header, header, SIP_STR_VAL, B_TRUE));
18040cb5e5dSvi }
18140cb5e5dSvi 
18240cb5e5dSvi /*
18340cb5e5dSvi  * Content-Disposition = "Content-Disposition" HCOLON disp-type *
18440cb5e5dSvi  *			(SEMI disp-param)
18540cb5e5dSvi  * disp-type = "render" | "session" | "icon" | "alert" | disp-ext-token
18640cb5e5dSvi  * disp-param = handling-param | generic-param
18740cb5e5dSvi  * handling-param = "handling" EQUAL("optional" | "required" | other-handling)
18840cb5e5dSvi  * other-handling = token
18940cb5e5dSvi  * disp-ext-token = token
19040cb5e5dSvi  *
19140cb5e5dSvi  */
19240cb5e5dSvi int
sip_parse_contentdis_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)19340cb5e5dSvi sip_parse_contentdis_header(_sip_header_t *sip_header,
19440cb5e5dSvi     sip_parsed_header_t **header)
19540cb5e5dSvi {
196*559f8b54SToomas Soome 	return (sip_parse_hdr_parser1(sip_header, header, 0));
19740cb5e5dSvi }
19840cb5e5dSvi 
19940cb5e5dSvi /*
20040cb5e5dSvi  * Content-Encoding = ("Content-Encoding" | "e") HCOLON content-coding *
20140cb5e5dSvi  *			(COMMA content-coding)
20240cb5e5dSvi  */
20340cb5e5dSvi int
sip_parse_contentencode_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)20440cb5e5dSvi sip_parse_contentencode_header(_sip_header_t *sip_header,
20540cb5e5dSvi     sip_parsed_header_t **header)
20640cb5e5dSvi {
207*559f8b54SToomas Soome 	return (sip_parse_hdr_parser1(sip_header, header, 0));
20840cb5e5dSvi }
20940cb5e5dSvi 
21040cb5e5dSvi /*
21140cb5e5dSvi  * Content-Language = ("Content-Language" | "l") HCOLON lang-tag *
21240cb5e5dSvi  *		 (COMMA lang-tag)
21340cb5e5dSvi  * lang-tag = primary-tag *("-" subtag)
21440cb5e5dSvi  * prmary-tag = 1*8ALPHA
21540cb5e5dSvi  * subtag = 1*8ALPHA
21640cb5e5dSvi  */
21740cb5e5dSvi int
sip_parse_contentlang_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)21840cb5e5dSvi sip_parse_contentlang_header(_sip_header_t *sip_header,
21940cb5e5dSvi     sip_parsed_header_t **header)
22040cb5e5dSvi {
221*559f8b54SToomas Soome 	return (sip_parse_hdr_parser1(sip_header, header, 0));
22240cb5e5dSvi }
22340cb5e5dSvi 
22440cb5e5dSvi /*
22540cb5e5dSvi  * Date = "Date" HCOLON SIPdate
22640cb5e5dSvi  * SIPdate = wkday "," SP date1 SP time SP "GMT"
22740cb5e5dSvi  * date1 = 2DIGIT SP mnth SP 4DIGIT; day month year
22840cb5e5dSvi  * time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
22940cb5e5dSvi  * wkday = "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun"
23040cb5e5dSvi  * month = "Jan" | "Feb" etc
23140cb5e5dSvi  */
23240cb5e5dSvi int
sip_parse_date_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)23340cb5e5dSvi sip_parse_date_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
23440cb5e5dSvi {
23540cb5e5dSvi 	sip_parsed_header_t	*parsed_header;
23640cb5e5dSvi 	int			 r;
23740cb5e5dSvi 	sip_hdr_value_t		*value = NULL;
23840cb5e5dSvi 
23940cb5e5dSvi 	if ((r = sip_prim_parsers(sip_header, header)) != 0)
24040cb5e5dSvi 		return (r);
24140cb5e5dSvi 
24240cb5e5dSvi 	if (*header != NULL)
24340cb5e5dSvi 		return (0);
24440cb5e5dSvi 
24540cb5e5dSvi 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
24640cb5e5dSvi 	if (parsed_header == NULL)
24740cb5e5dSvi 		return (ENOMEM);
24840cb5e5dSvi 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
24940cb5e5dSvi 	parsed_header->sip_header = sip_header;
25040cb5e5dSvi 
25140cb5e5dSvi 	value = calloc(1, sizeof (sip_hdr_value_t));
25240cb5e5dSvi 	if (value == NULL) {
25340cb5e5dSvi 		sip_free_phdr(parsed_header);
25440cb5e5dSvi 		return (ENOMEM);
25540cb5e5dSvi 	}
25640cb5e5dSvi 	parsed_header->value = (sip_value_t *)value;
25740cb5e5dSvi 
25840cb5e5dSvi 	value->sip_value_start = sip_header->sip_hdr_current;
25940cb5e5dSvi 	value->sip_value_header = parsed_header;
26040cb5e5dSvi 	value->date_wd_ptr = sip_header->sip_hdr_current;
26140cb5e5dSvi 	if (sip_find_token(sip_header, SIP_COMMA) == 0) {
26240cb5e5dSvi 		value->date_wd_len = sip_header->sip_hdr_current -
26340cb5e5dSvi 		    value->date_wd_ptr - 1;
26440cb5e5dSvi 		sip_header->sip_hdr_current++;
26540cb5e5dSvi 		if (sip_skip_white_space(sip_header) != 0) {
26640cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
26740cb5e5dSvi 			return (EPROTO);
26840cb5e5dSvi 		}
26940cb5e5dSvi 	} else {
27040cb5e5dSvi 		value->sip_value_state = SIP_VALUE_BAD;
27140cb5e5dSvi 		return (EPROTO);
27240cb5e5dSvi 	}
27340cb5e5dSvi 
27440cb5e5dSvi 	if (sip_skip_white_space(sip_header) != 0) {
27540cb5e5dSvi 		value->sip_value_state = SIP_VALUE_BAD;
27640cb5e5dSvi 		return (EPROTO);
27740cb5e5dSvi 	}
27840cb5e5dSvi 	r = sip_atoi(sip_header, &value->date_d);
27940cb5e5dSvi 	if (r != 0 || value->date_d < 0 || value->date_d > 31) {
28040cb5e5dSvi 		value->sip_value_state = SIP_VALUE_BAD;
28140cb5e5dSvi 		return (EPROTO);
28240cb5e5dSvi 	}
28340cb5e5dSvi 	if (sip_skip_white_space(sip_header) != 0) {
28440cb5e5dSvi 		value->sip_value_state = SIP_VALUE_BAD;
28540cb5e5dSvi 		return (EPROTO);
28640cb5e5dSvi 	}
28740cb5e5dSvi 	value->date_m_ptr = sip_header->sip_hdr_current;
28840cb5e5dSvi 	if (sip_find_token(sip_header, SIP_SP) == 0) {
28940cb5e5dSvi 		value->date_m_len = sip_header->sip_hdr_current -
29040cb5e5dSvi 		    value->date_m_ptr - 1;
29140cb5e5dSvi 	} else {
29240cb5e5dSvi 		value->sip_value_state = SIP_VALUE_BAD;
29340cb5e5dSvi 		return (EPROTO);
29440cb5e5dSvi 	}
29540cb5e5dSvi 
29640cb5e5dSvi 	r = sip_atoi(sip_header, &value->date_y);
29740cb5e5dSvi 	if (r != 0 || value->date_y < 0) {
29840cb5e5dSvi 		value->sip_value_state = SIP_VALUE_BAD;
29940cb5e5dSvi 		return (EPROTO);
30040cb5e5dSvi 	}
30140cb5e5dSvi 	if (sip_skip_white_space(sip_header) != 0) {
30240cb5e5dSvi 		value->sip_value_state = SIP_VALUE_BAD;
30340cb5e5dSvi 		return (EPROTO);
30440cb5e5dSvi 	}
30540cb5e5dSvi 	value->date_t_ptr = sip_header->sip_hdr_current;
30640cb5e5dSvi 	if (sip_find_token(sip_header, SIP_SP) == 0) {
30740cb5e5dSvi 		value->date_t_len = sip_header->sip_hdr_current -
30840cb5e5dSvi 		    value->date_t_ptr - 1;
30940cb5e5dSvi 	} else {
31040cb5e5dSvi 		value->sip_value_state = SIP_VALUE_BAD;
31140cb5e5dSvi 		return (EPROTO);
31240cb5e5dSvi 	}
31340cb5e5dSvi 
31440cb5e5dSvi 	value->date_tz_ptr =  sip_header->sip_hdr_current;
31540cb5e5dSvi 	/*
31640cb5e5dSvi 	 * minus 2 to get rid of the CRLF
31740cb5e5dSvi 	 */
31840cb5e5dSvi 	value->date_tz_len = sip_header->sip_hdr_end -
31940cb5e5dSvi 	    sip_header->sip_hdr_current - 2;
32040cb5e5dSvi 
32140cb5e5dSvi 	*header = parsed_header;
32240cb5e5dSvi 
32340cb5e5dSvi 	sip_header->sip_hdr_parsed = *header;
32440cb5e5dSvi 	return (0);
32540cb5e5dSvi }
32640cb5e5dSvi 
32740cb5e5dSvi /*
32840cb5e5dSvi  * Error-Info = "Error-Info" HCOLON error-uri *(COMMA error-uri)
32940cb5e5dSvi  * error-uri = LAQUOT absoluteURI RAQUOT *(SEMI generic-param)
33040cb5e5dSvi  */
33140cb5e5dSvi int
sip_parse_errorinfo_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)33240cb5e5dSvi sip_parse_errorinfo_header(_sip_header_t *sip_header,
33340cb5e5dSvi     sip_parsed_header_t **header)
33440cb5e5dSvi {
33540cb5e5dSvi 	return (sip_parse_hdr_parser3(sip_header, header, SIP_STR_VAL, B_TRUE));
33640cb5e5dSvi }
33740cb5e5dSvi 
33840cb5e5dSvi /*
33940cb5e5dSvi  * Expires = "Expires" HCOLON delta-seconds
34040cb5e5dSvi  */
34140cb5e5dSvi int
sip_parse_expire_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)34240cb5e5dSvi sip_parse_expire_header(_sip_header_t *sip_header,
34340cb5e5dSvi     sip_parsed_header_t **header)
34440cb5e5dSvi {
34540cb5e5dSvi 	return (sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL));
34640cb5e5dSvi }
34740cb5e5dSvi 
34840cb5e5dSvi /*
34940cb5e5dSvi  * In-Reply-To = "In-Reply-To" HCOLON callid *(COMMA callid)
35040cb5e5dSvi  */
35140cb5e5dSvi int
sip_parse_inreplyto_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)35240cb5e5dSvi sip_parse_inreplyto_header(_sip_header_t *sip_header,
35340cb5e5dSvi     sip_parsed_header_t **header)
35440cb5e5dSvi {
355*559f8b54SToomas Soome 	return (sip_parse_hdr_parser1(sip_header, header, 0));
35640cb5e5dSvi }
35740cb5e5dSvi 
35840cb5e5dSvi /*
35940cb5e5dSvi  * RSeq = "RSeq" HCOLON response-num
36040cb5e5dSvi  */
36140cb5e5dSvi int
sip_parse_rseq(_sip_header_t * sip_header,sip_parsed_header_t ** header)36240cb5e5dSvi sip_parse_rseq(_sip_header_t *sip_header, sip_parsed_header_t **header)
36340cb5e5dSvi {
36440cb5e5dSvi 	int		r;
36540cb5e5dSvi 	sip_hdr_value_t	*rseq_value;
36640cb5e5dSvi 
36740cb5e5dSvi 	r = sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL);
36840cb5e5dSvi 	/*
36940cb5e5dSvi 	 * Additionally, a value of 0 is bad_value
37040cb5e5dSvi 	 */
37140cb5e5dSvi 	if (sip_header->sip_hdr_parsed != NULL &&
37240cb5e5dSvi 	    sip_header->sip_hdr_parsed->value != NULL) {
37340cb5e5dSvi 		rseq_value = (sip_hdr_value_t *)
37440cb5e5dSvi 		    sip_header->sip_hdr_parsed->value;
37540cb5e5dSvi 		if (rseq_value->int_val == 0)
37640cb5e5dSvi 			rseq_value->sip_value_state = SIP_VALUE_BAD;
37740cb5e5dSvi 	}
37840cb5e5dSvi 	return (r);
37940cb5e5dSvi }
38040cb5e5dSvi 
38140cb5e5dSvi /*
38240cb5e5dSvi  * Min-Expires  =  "Min-Expires" HCOLON delta-seconds
38340cb5e5dSvi  */
38440cb5e5dSvi int
sip_parse_minexpire_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)38540cb5e5dSvi sip_parse_minexpire_header(_sip_header_t *sip_header,
38640cb5e5dSvi     sip_parsed_header_t **header)
38740cb5e5dSvi {
38840cb5e5dSvi 	return (sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL));
38940cb5e5dSvi }
39040cb5e5dSvi 
39140cb5e5dSvi /*
39240cb5e5dSvi  * MIME-Version = "MIME-Version" HCOLON 1*DIGIT "." 1*DIGIT
39340cb5e5dSvi  */
39440cb5e5dSvi int
sip_parse_mimeversion_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)39540cb5e5dSvi sip_parse_mimeversion_header(_sip_header_t *sip_header,
39640cb5e5dSvi     sip_parsed_header_t **header)
39740cb5e5dSvi {
39840cb5e5dSvi 	return (sip_parse_hdr_parser4(sip_header, header));
39940cb5e5dSvi }
40040cb5e5dSvi 
40140cb5e5dSvi /*
40240cb5e5dSvi  * Organization = "Organization" HCOLON [TEXT-UTF8-TRIM]
40340cb5e5dSvi  */
40440cb5e5dSvi int
sip_parse_org_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)40540cb5e5dSvi sip_parse_org_header(_sip_header_t *sip_header,
40640cb5e5dSvi     sip_parsed_header_t **header)
40740cb5e5dSvi {
40840cb5e5dSvi 	if (sip_is_empty_hdr(sip_header))
40940cb5e5dSvi 		return (sip_parse_hdr_empty(sip_header, header));
41040cb5e5dSvi 	return (sip_parse_hdr_parser4(sip_header, header));
41140cb5e5dSvi }
41240cb5e5dSvi 
41340cb5e5dSvi /*
41440cb5e5dSvi  * Priority = "Priority" HCOLON priority-val
41540cb5e5dSvi  * priority-val = "emergency" | "urgent" | "normal" | "non-urgent" | other
41640cb5e5dSvi  * other = token
41740cb5e5dSvi  */
41840cb5e5dSvi int
sip_parse_priority_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)41940cb5e5dSvi sip_parse_priority_header(_sip_header_t *sip_header,
42040cb5e5dSvi     sip_parsed_header_t **header)
42140cb5e5dSvi {
42240cb5e5dSvi 	return (sip_parse_hdr_parser4(sip_header, header));
42340cb5e5dSvi }
42440cb5e5dSvi 
42540cb5e5dSvi /*
42640cb5e5dSvi  * Reply-To = "Reply-To" HCOLON rplyto-spec
42740cb5e5dSvi  * rplyto-spec = (name-addr | addr-spec) *(SEMI rplyto-param)
42840cb5e5dSvi  * rplyto-param = generic-param
42940cb5e5dSvi  * name-addr = [ display-name ] LAQUOT addr-spec RAQUOT
43040cb5e5dSvi  * addr-spec = SIP-URI | SIPS-URI | absolute URI
43140cb5e5dSvi  */
43240cb5e5dSvi int
sip_parse_replyto_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)43340cb5e5dSvi sip_parse_replyto_header(_sip_header_t *sip_header,
43440cb5e5dSvi     sip_parsed_header_t **header)
43540cb5e5dSvi {
43640cb5e5dSvi 	return (sip_parse_hdr_parser3(sip_header, header, SIP_STRS_VAL,
43740cb5e5dSvi 	    B_TRUE));
43840cb5e5dSvi }
43940cb5e5dSvi 
44040cb5e5dSvi /*
44140cb5e5dSvi  * PRIVACY = "Privacy" HCOLON priv-value *(COMMA priv-value)
44240cb5e5dSvi  * priv-value   =   "header" / "session" / "user" / "none" / "critical"
44340cb5e5dSvi  *                  / token / id
44440cb5e5dSvi  */
44540cb5e5dSvi int
sip_parse_privacy_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)44640cb5e5dSvi sip_parse_privacy_header(_sip_header_t *sip_header,
44740cb5e5dSvi     sip_parsed_header_t **header)
44840cb5e5dSvi {
449*559f8b54SToomas Soome 	return (sip_parse_hdr_parser1(sip_header, header, 0));
45040cb5e5dSvi }
45140cb5e5dSvi 
45240cb5e5dSvi 
45340cb5e5dSvi /*
45440cb5e5dSvi  * Require = "Require" HCOLON option-tag * (COMMA option-tag)
45540cb5e5dSvi  */
45640cb5e5dSvi int
sip_parse_require_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)45740cb5e5dSvi sip_parse_require_header(_sip_header_t *sip_header,
45840cb5e5dSvi     sip_parsed_header_t **header)
45940cb5e5dSvi {
460*559f8b54SToomas Soome 	return (sip_parse_hdr_parser1(sip_header, header, 0));
46140cb5e5dSvi }
46240cb5e5dSvi 
46340cb5e5dSvi /*
46440cb5e5dSvi  * Retry-After = "Retry-After" HCOLON delta-seconds [ comment ] *
46540cb5e5dSvi  *		(SEMI retry-param)
46640cb5e5dSvi  * retry-param = "duration" EQUAL delta-seconds
46740cb5e5dSvi  */
46840cb5e5dSvi int
sip_parse_retryaft_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)46940cb5e5dSvi sip_parse_retryaft_header(_sip_header_t *sip_header,
47040cb5e5dSvi     sip_parsed_header_t **header)
47140cb5e5dSvi {
47240cb5e5dSvi 	sip_parsed_header_t	*parsed_header;
47340cb5e5dSvi 	sip_hdr_value_t		*value = NULL;
47440cb5e5dSvi 	int			ret;
47540cb5e5dSvi 
47640cb5e5dSvi 	if ((ret = sip_prim_parsers(sip_header, header)) != 0)
47740cb5e5dSvi 		return (ret);
47840cb5e5dSvi 
47940cb5e5dSvi 	if (*header != NULL)
48040cb5e5dSvi 		return (0);
48140cb5e5dSvi 
48240cb5e5dSvi 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
48340cb5e5dSvi 	if (parsed_header == NULL)
48440cb5e5dSvi 		return (ENOMEM);
48540cb5e5dSvi 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
48640cb5e5dSvi 	parsed_header->sip_header = sip_header;
48740cb5e5dSvi 
48840cb5e5dSvi 	value = calloc(1, sizeof (sip_hdr_value_t));
48940cb5e5dSvi 	if (value == NULL) {
49040cb5e5dSvi 		sip_free_phdr(parsed_header);
49140cb5e5dSvi 		return (ENOMEM);
49240cb5e5dSvi 	}
49340cb5e5dSvi 
49440cb5e5dSvi 	parsed_header->value = (sip_value_t *)value;
49540cb5e5dSvi 	value->sip_value_start = sip_header->sip_hdr_current;
49640cb5e5dSvi 	value->sip_value_header = parsed_header;
49740cb5e5dSvi 
49840cb5e5dSvi 	ret = sip_atoi(sip_header, &(value->intstr_int));
49940cb5e5dSvi 	if (ret != 0)
50040cb5e5dSvi 		value->sip_value_state = SIP_VALUE_BAD;
50140cb5e5dSvi 	if (sip_find_token(sip_header, SIP_LPAR) == 0) {
50240cb5e5dSvi 		value->intstr_str_ptr = sip_header->sip_hdr_current;
50340cb5e5dSvi 		if (sip_find_token(sip_header, SIP_RPAR) == 0) {
50440cb5e5dSvi 			value->intstr_str_len =
50540cb5e5dSvi 			    sip_header->sip_hdr_current -
506df4705eaSgm 			    value->intstr_str_ptr - 1;
50740cb5e5dSvi 			if (sip_find_token(sip_header, SIP_SEMI) == 0) {
50840cb5e5dSvi 				sip_header->sip_hdr_current--;
50940cb5e5dSvi 				(void) sip_parse_params(sip_header,
51040cb5e5dSvi 				    &(value->sip_param_list));
51140cb5e5dSvi 			}
51240cb5e5dSvi 		} else {
51340cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
51440cb5e5dSvi 			return (EPROTO);
51540cb5e5dSvi 		}
51640cb5e5dSvi 	} else {
51740cb5e5dSvi 		value->intstr_str_ptr = NULL;
51840cb5e5dSvi 		value->intstr_str_len = 0;
51940cb5e5dSvi 
52040cb5e5dSvi 		/*
52140cb5e5dSvi 		 * from value start, search if parameter list
52240cb5e5dSvi 		 */
52340cb5e5dSvi 		sip_header->sip_hdr_current = value->sip_value_start;
52440cb5e5dSvi 		if (sip_find_token(sip_header, SIP_SEMI) == 0) {
52540cb5e5dSvi 			sip_header->sip_hdr_current--;
52640cb5e5dSvi 			(void) sip_parse_params(sip_header,
52740cb5e5dSvi 			    &(value->sip_param_list));
52840cb5e5dSvi 		}
52940cb5e5dSvi 	}
53040cb5e5dSvi 
53140cb5e5dSvi 	*header = parsed_header;
53240cb5e5dSvi 	sip_header->sip_hdr_parsed = *header;
53340cb5e5dSvi 	return (0);
53440cb5e5dSvi }
53540cb5e5dSvi 
53640cb5e5dSvi /*
53740cb5e5dSvi  * Server = "Server" HCOLON servel-val *(LWS server-val)
53840cb5e5dSvi  * servel-val = product|comment
53940cb5e5dSvi  * product = token [SLASH version]
54040cb5e5dSvi  * version = token
54140cb5e5dSvi  * Treated as one single string
54240cb5e5dSvi  */
54340cb5e5dSvi int
sip_parse_server_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)54440cb5e5dSvi sip_parse_server_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
54540cb5e5dSvi {
54640cb5e5dSvi 	return (sip_parse_hdr_parser4(sip_header, header));
54740cb5e5dSvi }
54840cb5e5dSvi 
54940cb5e5dSvi /*
55040cb5e5dSvi  * Subject = ("Subject" | "s")HCOLON [TEXT-UTF8-TRIM]
55140cb5e5dSvi  */
55240cb5e5dSvi int
sip_parse_subject_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)55340cb5e5dSvi sip_parse_subject_header(_sip_header_t *sip_header,
55440cb5e5dSvi     sip_parsed_header_t **header)
55540cb5e5dSvi {
55640cb5e5dSvi 	if (sip_is_empty_hdr(sip_header))
55740cb5e5dSvi 		return (sip_parse_hdr_empty(sip_header, header));
55840cb5e5dSvi 	return (sip_parse_hdr_parser4(sip_header, header));
55940cb5e5dSvi }
56040cb5e5dSvi 
56140cb5e5dSvi /*
56240cb5e5dSvi  * Supported = ("Supported" | "k") HCOLON [option-tag * (COMMA option-tag) ]
56340cb5e5dSvi  */
56440cb5e5dSvi int
sip_parse_support_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)56540cb5e5dSvi sip_parse_support_header(_sip_header_t *sip_header,
56640cb5e5dSvi     sip_parsed_header_t **header)
56740cb5e5dSvi {
56840cb5e5dSvi 	if (sip_is_empty_hdr(sip_header))
56940cb5e5dSvi 		return (sip_parse_hdr_empty(sip_header, header));
570*559f8b54SToomas Soome 	return (sip_parse_hdr_parser1(sip_header, header, 0));
57140cb5e5dSvi }
57240cb5e5dSvi 
57340cb5e5dSvi /*
57440cb5e5dSvi  * Timestamp = "Timestamp" HCOLON 1*DIGIT ["." *(DIGIT)] [LWS delay]
57540cb5e5dSvi  */
57640cb5e5dSvi int
sip_parse_timestamp_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)57740cb5e5dSvi sip_parse_timestamp_header(_sip_header_t *sip_header,
57840cb5e5dSvi     sip_parsed_header_t **header)
57940cb5e5dSvi {
58040cb5e5dSvi 	sip_parsed_header_t	*parsed_header;
58140cb5e5dSvi 	sip_hdr_value_t		*value = NULL;
58240cb5e5dSvi 	int			ret;
58340cb5e5dSvi 
58440cb5e5dSvi 	if ((ret = sip_prim_parsers(sip_header, header)) != 0)
58540cb5e5dSvi 		return (ret);
58640cb5e5dSvi 
58740cb5e5dSvi 	if (*header != NULL)
58840cb5e5dSvi 		return (0);
58940cb5e5dSvi 
59040cb5e5dSvi 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
59140cb5e5dSvi 	if (parsed_header == NULL)
59240cb5e5dSvi 		return (ENOMEM);
59340cb5e5dSvi 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
59440cb5e5dSvi 	parsed_header->sip_header = sip_header;
59540cb5e5dSvi 
59640cb5e5dSvi 	value = calloc(1, sizeof (sip_hdr_value_t));
59740cb5e5dSvi 	if (value == NULL) {
59840cb5e5dSvi 		sip_free_phdr(parsed_header);
59940cb5e5dSvi 		return (ENOMEM);
60040cb5e5dSvi 	}
60140cb5e5dSvi 	parsed_header->value = (sip_value_t *)value;
60240cb5e5dSvi 
60340cb5e5dSvi 	value->sip_value_start = sip_header->sip_hdr_current;
60440cb5e5dSvi 	value->sip_value_header = parsed_header;
60540cb5e5dSvi 
60640cb5e5dSvi 	if (sip_skip_white_space(sip_header) != 0) {
60740cb5e5dSvi 		value->sip_value_state = SIP_VALUE_BAD;
60840cb5e5dSvi 		return (EPROTO);
60940cb5e5dSvi 	}
61040cb5e5dSvi 	value->strs1_val_ptr = sip_header->sip_hdr_current;
61140cb5e5dSvi 
61240cb5e5dSvi 	if (sip_find_white_space(sip_header) == 0) {
61340cb5e5dSvi 		/*
61440cb5e5dSvi 		 * timestamp and delay, timestamp in str1, delay in str2
61540cb5e5dSvi 		 */
61640cb5e5dSvi 		value->strs1_val_len = sip_header->sip_hdr_current -
61740cb5e5dSvi 		    value->strs1_val_ptr;
61840cb5e5dSvi 		(void) sip_skip_white_space(sip_header);
61940cb5e5dSvi 
62040cb5e5dSvi 		value->strs2_val_ptr = sip_header->sip_hdr_current;
62140cb5e5dSvi 		if (sip_find_cr(sip_header) != 0) {
62240cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
62340cb5e5dSvi 			return (EPROTO);
62440cb5e5dSvi 		}
62540cb5e5dSvi 		if (sip_header->sip_hdr_current < value->strs2_val_ptr) {
62640cb5e5dSvi 			value->strs2_val_ptr = NULL;
62740cb5e5dSvi 			value->strs2_val_len = 0;
62840cb5e5dSvi 		} else {
62940cb5e5dSvi 			value->strs2_val_len = sip_header->sip_hdr_current -
63040cb5e5dSvi 			    value->strs2_val_ptr;
63140cb5e5dSvi 		}
63240cb5e5dSvi 	} else {
63340cb5e5dSvi 		/*
63440cb5e5dSvi 		 * no delay information
63540cb5e5dSvi 		 */
63640cb5e5dSvi 		value->strs1_val_len = sip_header->sip_hdr_current
63740cb5e5dSvi 		    - value->strs1_val_ptr;
63840cb5e5dSvi 		value->strs2_val_ptr = NULL;
63940cb5e5dSvi 		value->strs2_val_len = 0;
64040cb5e5dSvi 	}
64140cb5e5dSvi 
64240cb5e5dSvi 	*header = parsed_header;
64340cb5e5dSvi 	sip_header->sip_hdr_parsed = *header;
64440cb5e5dSvi 
64540cb5e5dSvi 	return (0);
64640cb5e5dSvi }
64740cb5e5dSvi /*
64840cb5e5dSvi  * Unsupported = "Unsupported" HCOLON option-tag * (COMMA option-tag)
64940cb5e5dSvi  */
65040cb5e5dSvi int
sip_parse_usupport_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)65140cb5e5dSvi sip_parse_usupport_header(_sip_header_t *sip_header,
65240cb5e5dSvi     sip_parsed_header_t **header)
65340cb5e5dSvi {
654*559f8b54SToomas Soome 	return (sip_parse_hdr_parser1(sip_header, header, 0));
65540cb5e5dSvi }
65640cb5e5dSvi 
65740cb5e5dSvi /*
65840cb5e5dSvi  * User-Agent = "User-Agent" HCOLON server-val * (LWS server-val)
65940cb5e5dSvi  * servel-val = product |comment
66040cb5e5dSvi  * product = token [SLASH version]
66140cb5e5dSvi  * version = token
66240cb5e5dSvi  */
66340cb5e5dSvi int
sip_parse_useragt_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)66440cb5e5dSvi sip_parse_useragt_header(_sip_header_t *sip_header,
66540cb5e5dSvi     sip_parsed_header_t **header)
66640cb5e5dSvi {
66740cb5e5dSvi 	return (sip_parse_hdr_parser4(sip_header, header));
66840cb5e5dSvi }
66940cb5e5dSvi 
67040cb5e5dSvi /*
67140cb5e5dSvi  * Warning = "Warning" HCOLON warning-value *(COMMA warning-value)
67240cb5e5dSvi  * warning-value = warn-code SP warn-agent SP warn-text
67340cb5e5dSvi  * warn-code = 3DIGIT
67440cb5e5dSvi  * warn-agent = hostport | pseudonym ;
67540cb5e5dSvi  *		 the name or pseudonym of the server adding;
67640cb5e5dSvi  *		 the Warning header, for use in debugging
67740cb5e5dSvi  * warn-text = quoted-string
67840cb5e5dSvi  * pseudonym = token
67940cb5e5dSvi  */
68040cb5e5dSvi int
sip_parse_warn_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)68140cb5e5dSvi sip_parse_warn_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
68240cb5e5dSvi {
68340cb5e5dSvi 	sip_parsed_header_t	*parsed_header;
68440cb5e5dSvi 	int			ret;
68540cb5e5dSvi 	sip_hdr_value_t		*value = NULL;
68640cb5e5dSvi 	sip_hdr_value_t		*last_value = NULL;
68740cb5e5dSvi 
68840cb5e5dSvi 	if ((ret = sip_prim_parsers(sip_header, header)) != 0)
68940cb5e5dSvi 		return (ret);
69040cb5e5dSvi 
69140cb5e5dSvi 	if (*header != NULL)
69240cb5e5dSvi 		return (0);
69340cb5e5dSvi 
69440cb5e5dSvi 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
69540cb5e5dSvi 	if (parsed_header == NULL)
69640cb5e5dSvi 		return (ENOMEM);
69740cb5e5dSvi 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
69840cb5e5dSvi 	parsed_header->sip_header = sip_header;
69940cb5e5dSvi 
70040cb5e5dSvi 	while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
70140cb5e5dSvi 		value = calloc(1, sizeof (sip_hdr_value_t));
70240cb5e5dSvi 		if (value == NULL) {
70340cb5e5dSvi 			sip_free_phdr(parsed_header);
70440cb5e5dSvi 			return (ENOMEM);
70540cb5e5dSvi 		}
70640cb5e5dSvi 
70740cb5e5dSvi 		if (last_value != NULL)
70840cb5e5dSvi 			last_value->sip_next_value = value;
70940cb5e5dSvi 		else
71040cb5e5dSvi 			parsed_header->value = (sip_value_t *)value;
71140cb5e5dSvi 
71240cb5e5dSvi 		value->sip_value_start = sip_header->sip_hdr_current;
71340cb5e5dSvi 		value->sip_value_header = parsed_header;
71440cb5e5dSvi 
71540cb5e5dSvi 		ret = sip_atoi(sip_header, &value->warn_code);
71640cb5e5dSvi 		if (ret != 0 || value->warn_code < 100 ||
71740cb5e5dSvi 		    value->warn_code > 999) {
71840cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
71940cb5e5dSvi 			goto get_next_val;
72040cb5e5dSvi 		}
72140cb5e5dSvi 		if (sip_skip_white_space(sip_header) != 0) {
72240cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
72340cb5e5dSvi 			goto get_next_val;
72440cb5e5dSvi 		}
72540cb5e5dSvi 		value->warn_agt_ptr = sip_header->sip_hdr_current;
72640cb5e5dSvi 
72740cb5e5dSvi 		if (sip_find_token(sip_header, SIP_QUOTE) == 0) {
72840cb5e5dSvi 			/*
72940cb5e5dSvi 			 * get warning agent
73040cb5e5dSvi 			 */
73140cb5e5dSvi 			sip_header->sip_hdr_current--;
73240cb5e5dSvi 			(void) sip_reverse_skip_white_space(sip_header);
73340cb5e5dSvi 			value->warn_agt_len = sip_header->sip_hdr_current -
73440cb5e5dSvi 			    value->warn_agt_ptr - 1;
73540cb5e5dSvi 			if (value->warn_agt_len <= 0) {
73640cb5e5dSvi 				value->warn_agt_ptr = NULL;
73740cb5e5dSvi 				value->sip_value_state = SIP_VALUE_BAD;
73840cb5e5dSvi 			}
73940cb5e5dSvi 
74040cb5e5dSvi 			/*
74140cb5e5dSvi 			 * We will have a  SIP_QUOTE here
74240cb5e5dSvi 			 */
74340cb5e5dSvi 			(void) sip_find_token(sip_header, SIP_QUOTE);
74440cb5e5dSvi 
74540cb5e5dSvi 			value->warn_text_ptr =  sip_header->sip_hdr_current;
74640cb5e5dSvi 			if (sip_find_token(sip_header, SIP_QUOTE) == 0) {
74740cb5e5dSvi 				value->warn_text_len =
74840cb5e5dSvi 				    sip_header->sip_hdr_current -
749df4705eaSgm 				    value->warn_text_ptr - 1;
75040cb5e5dSvi 			} else {
75140cb5e5dSvi 				value->sip_value_state = SIP_VALUE_BAD;
75240cb5e5dSvi 				goto get_next_val;
75340cb5e5dSvi 			}
75440cb5e5dSvi 		} else
75540cb5e5dSvi 			/*
75640cb5e5dSvi 			 * warning text must present
75740cb5e5dSvi 			 */
75840cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
75940cb5e5dSvi 
76040cb5e5dSvi get_next_val:
76140cb5e5dSvi 		if (sip_find_token(sip_header, SIP_COMMA) != 0)
76240cb5e5dSvi 			break;
76340cb5e5dSvi 		value->sip_value_end = sip_header->sip_hdr_current - 1;
76440cb5e5dSvi 		last_value = value;
76540cb5e5dSvi 		(void) sip_skip_white_space(sip_header);
76640cb5e5dSvi 	}
76740cb5e5dSvi 
76840cb5e5dSvi 	*header = parsed_header;
76940cb5e5dSvi 
77040cb5e5dSvi 	sip_header->sip_hdr_parsed = *header;
77140cb5e5dSvi 	return (0);
77240cb5e5dSvi }
77340cb5e5dSvi 
77440cb5e5dSvi /*
77540cb5e5dSvi  * Parse RAck header
77640cb5e5dSvi  * "RAck" HCOLON response-num LWS CSeq-num LWS Method
77740cb5e5dSvi  * response-num  =  1*DIGIT
77840cb5e5dSvi  * CSeq-num      =  1*DIGIT
77940cb5e5dSvi  */
78040cb5e5dSvi int
sip_parse_rack(_sip_header_t * sip_header,sip_parsed_header_t ** header)78140cb5e5dSvi sip_parse_rack(_sip_header_t *sip_header, sip_parsed_header_t **header)
78240cb5e5dSvi {
78340cb5e5dSvi 	sip_parsed_header_t	*parsed_header;
78440cb5e5dSvi 	sip_hdr_value_t		*rack_value;
78540cb5e5dSvi 	int			len;
78640cb5e5dSvi 	char			*tmp_ptr;
78740cb5e5dSvi 	int			i;
78840cb5e5dSvi 	int			ret;
78940cb5e5dSvi 
79040cb5e5dSvi 	if ((ret = sip_prim_parsers(sip_header, header)) != 0)
79140cb5e5dSvi 		return (ret);
79240cb5e5dSvi 
79340cb5e5dSvi 	if (*header != NULL)
79440cb5e5dSvi 		return (0);
79540cb5e5dSvi 
79640cb5e5dSvi 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
79740cb5e5dSvi 	if (parsed_header == NULL)
79840cb5e5dSvi 		return (ENOMEM);
79940cb5e5dSvi 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
80040cb5e5dSvi 	parsed_header->sip_header = sip_header;
80140cb5e5dSvi 
80240cb5e5dSvi 	parsed_header->value =  calloc(1, sizeof (sip_hdr_value_t));
80340cb5e5dSvi 	if (parsed_header->value == NULL) {
80440cb5e5dSvi 		free(parsed_header);
80540cb5e5dSvi 		return (ENOMEM);
80640cb5e5dSvi 	}
80740cb5e5dSvi 	rack_value = (sip_hdr_value_t *)parsed_header->value;
80840cb5e5dSvi 	rack_value->sip_value_version = SIP_VALUE_VERSION_1;
80940cb5e5dSvi 	rack_value->sip_value_start = sip_header->sip_hdr_current;
81040cb5e5dSvi 	rack_value->sip_value_header = parsed_header;
81140cb5e5dSvi 	if (sip_atoi(sip_header, &rack_value->rack_resp) ||
81240cb5e5dSvi 	    rack_value->rack_resp == 0) {
81340cb5e5dSvi 		rack_value->sip_value_state = SIP_VALUE_BAD;
81440cb5e5dSvi 		rack_value->sip_value_end = sip_header->sip_hdr_end - 2;
81540cb5e5dSvi 		goto rack_parse_done;
81640cb5e5dSvi 	}
81740cb5e5dSvi 	rack_value->sip_value_header = parsed_header;
81840cb5e5dSvi 	/*
81940cb5e5dSvi 	 * Get cseq.
82040cb5e5dSvi 	 */
82140cb5e5dSvi 	if (sip_skip_white_space(sip_header) != 0) {
82240cb5e5dSvi 		rack_value->sip_value_state = SIP_VALUE_BAD;
82340cb5e5dSvi 		rack_value->sip_value_end = sip_header->sip_hdr_end - 2;
82440cb5e5dSvi 		goto rack_parse_done;
82540cb5e5dSvi 	}
82640cb5e5dSvi 	if (sip_atoi(sip_header, &rack_value->rack_cseq)) {
82740cb5e5dSvi 		rack_value->sip_value_state = SIP_VALUE_BAD;
82840cb5e5dSvi 		rack_value->sip_value_end = sip_header->sip_hdr_end - 2;
82940cb5e5dSvi 		goto rack_parse_done;
83040cb5e5dSvi 	}
83140cb5e5dSvi 	/*
83240cb5e5dSvi 	 * Get method.
83340cb5e5dSvi 	 */
83440cb5e5dSvi 	if (sip_skip_white_space(sip_header) != 0) {
83540cb5e5dSvi 		rack_value->sip_value_state = SIP_VALUE_BAD;
83640cb5e5dSvi 		rack_value->sip_value_end = sip_header->sip_hdr_end - 2;
83740cb5e5dSvi 		goto rack_parse_done;
83840cb5e5dSvi 	}
83940cb5e5dSvi 
84040cb5e5dSvi 	tmp_ptr = sip_header->sip_hdr_current;
84140cb5e5dSvi 	if (sip_find_white_space(sip_header)) {
84240cb5e5dSvi 		rack_value->sip_value_state = SIP_VALUE_BAD;
84340cb5e5dSvi 		rack_value->sip_value_end = sip_header->sip_hdr_end - 2;
84440cb5e5dSvi 		goto rack_parse_done;
84540cb5e5dSvi 	}
84640cb5e5dSvi 
84740cb5e5dSvi 	len = sip_header->sip_hdr_current - tmp_ptr;
84840cb5e5dSvi 
84940cb5e5dSvi 	for (i = 1; i < MAX_SIP_METHODS; i++) {
85040cb5e5dSvi 		if (strncmp(sip_methods[i].name, tmp_ptr, len) == 0)
85140cb5e5dSvi 			break;
85240cb5e5dSvi 	}
85340cb5e5dSvi 
85440cb5e5dSvi 	if (i >= MAX_SIP_METHODS) {
85540cb5e5dSvi 		rack_value->sip_value_state = SIP_VALUE_BAD;
85640cb5e5dSvi 		rack_value->sip_value_end = sip_header->sip_hdr_end - 2;
85740cb5e5dSvi 		goto rack_parse_done;
85840cb5e5dSvi 	}
85940cb5e5dSvi 
86040cb5e5dSvi 	rack_value->rack_method = i;
86140cb5e5dSvi 	rack_value->sip_value_end = sip_header->sip_hdr_current;
86240cb5e5dSvi 
86340cb5e5dSvi rack_parse_done:
86440cb5e5dSvi 	sip_header->sip_hdr_parsed = parsed_header;
86540cb5e5dSvi 
86640cb5e5dSvi 	*header = parsed_header;
86740cb5e5dSvi 	return (0);
86840cb5e5dSvi }
86940cb5e5dSvi 
87040cb5e5dSvi /*
87140cb5e5dSvi  * Allow  =  "Allow" HCOLON [Method *(COMMA Method)]
87240cb5e5dSvi  */
87340cb5e5dSvi int
sip_parse_allow_events_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)87440cb5e5dSvi sip_parse_allow_events_header(_sip_header_t *sip_header,
87540cb5e5dSvi     sip_parsed_header_t **header)
87640cb5e5dSvi {
877*559f8b54SToomas Soome 	return (sip_parse_hdr_parser1(sip_header, header, 0));
87840cb5e5dSvi }
87940cb5e5dSvi 
88040cb5e5dSvi /*
88140cb5e5dSvi  * Event             =  ( "Event" / "o" ) HCOLON event-type
88240cb5e5dSvi  *			*( SEMI event-param )
88340cb5e5dSvi  * event-type        =  event-package *( "." event-template )
88440cb5e5dSvi  * event-package     =  token-nodot
88540cb5e5dSvi  * event-template    =  token-nodot
88640cb5e5dSvi  * token-nodot       =  1*( alphanum / "-"  / "!" / "%" / "*"
88740cb5e5dSvi  *			/ "_" / "+" / "`" / "'" / "~" )
88840cb5e5dSvi  * event-param       =  generic-param / ( "id" EQUAL token )
88940cb5e5dSvi  */
89040cb5e5dSvi int
sip_parse_event_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)89140cb5e5dSvi sip_parse_event_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
89240cb5e5dSvi {
893*559f8b54SToomas Soome 	return (sip_parse_hdr_parser1(sip_header, header, 0));
89440cb5e5dSvi }
89540cb5e5dSvi 
89640cb5e5dSvi /*
89740cb5e5dSvi  * Subscription-State   = "Subscription-State" HCOLON substate-value
898*559f8b54SToomas Soome  *			*( SEMI subexp-params )
89940cb5e5dSvi  * substate-value       = "active" / "pending" / "terminated"
90040cb5e5dSvi  *			/ extension-substate
90140cb5e5dSvi  * extension-substate   = token
90240cb5e5dSvi  * subexp-params        =   ("reason" EQUAL event-reason-value)
90340cb5e5dSvi  *			/ ("expires" EQUAL delta-seconds)*
904*559f8b54SToomas Soome  *			/ ("retry-after" EQUAL delta-seconds)
90540cb5e5dSvi  *			/ generic-param
90640cb5e5dSvi  * event-reason-value   =   "deactivated"
90740cb5e5dSvi  *				/ "probation"
90840cb5e5dSvi  *				/ "rejected"
90940cb5e5dSvi  *				/ "timeout"
91040cb5e5dSvi  *				/ "giveup"
91140cb5e5dSvi  *				/ "noresource"
91240cb5e5dSvi  *				/ event-reason-extension
91340cb5e5dSvi  * event-reason-extension = token
91440cb5e5dSvi  */
91540cb5e5dSvi int
sip_parse_substate_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)91640cb5e5dSvi sip_parse_substate_header(_sip_header_t *sip_header,
91740cb5e5dSvi     sip_parsed_header_t **header)
91840cb5e5dSvi {
919*559f8b54SToomas Soome 	return (sip_parse_hdr_parser1(sip_header, header, 0));
92040cb5e5dSvi }
92140cb5e5dSvi 
92240cb5e5dSvi /*
92340cb5e5dSvi  * Authorization     =  "Authorization" HCOLON credentials
92440cb5e5dSvi  * credentials       =  ("Digest" LWS digest-response)
92540cb5e5dSvi  *			/ other-response
92640cb5e5dSvi  * digest-response   =  dig-resp *(COMMA dig-resp)
92740cb5e5dSvi  * dig-resp          =  username / realm / nonce / digest-uri
92840cb5e5dSvi  *			/ dresponse / algorithm / cnonce
92940cb5e5dSvi  *			/ opaque / message-qop
93040cb5e5dSvi  *			/ nonce-count / auth-param
93140cb5e5dSvi  * username          =  "username" EQUAL username-value
93240cb5e5dSvi  * username-value    =  quoted-string
93340cb5e5dSvi  * digest-uri        =  "uri" EQUAL LDQUOT digest-uri-value RDQUOT
93440cb5e5dSvi  * digest-uri-value  =  rquest-uri ; Equal to request-uri as specified
93540cb5e5dSvi  *			by HTTP/1.1
93640cb5e5dSvi  * message-qop       =  "qop" EQUAL qop-value
93740cb5e5dSvi  * cnonce            =  "cnonce" EQUAL cnonce-value
93840cb5e5dSvi  * cnonce-value      =  nonce-value
93940cb5e5dSvi  * nonce-count       =  "nc" EQUAL nc-value
94040cb5e5dSvi  * nc-value          =  8LHEX
94140cb5e5dSvi  * dresponse         =  "response" EQUAL request-digest
94240cb5e5dSvi  * request-digest    =  LDQUOT 32LHEX RDQUOT
94340cb5e5dSvi  * auth-param        =  auth-param-name EQUAL
944*559f8b54SToomas Soome  *			( token / quoted-string )
94540cb5e5dSvi  * auth-param-name   =  token
94640cb5e5dSvi  * other-response    =  auth-scheme LWS auth-param
94740cb5e5dSvi  *			*(COMMA auth-param)
94840cb5e5dSvi  * auth-scheme       =  token
94940cb5e5dSvi  */
95040cb5e5dSvi int
sip_parse_author_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)95140cb5e5dSvi sip_parse_author_header(_sip_header_t *sip_header,
95240cb5e5dSvi     sip_parsed_header_t **header)
95340cb5e5dSvi {
95440cb5e5dSvi 	return (sip_parse_hdr_parser5(sip_header, header, B_TRUE));
95540cb5e5dSvi }
95640cb5e5dSvi 
95740cb5e5dSvi /*
95840cb5e5dSvi  * Authentication-Info  =  "Authentication-Info" HCOLON ainfo
95940cb5e5dSvi  *				*(COMMA ainfo)
96040cb5e5dSvi  * ainfo                =  nextnonce / message-qop
96140cb5e5dSvi  *				/ response-auth / cnonce
96240cb5e5dSvi  *				/ nonce-count
96340cb5e5dSvi  * nextnonce            =  "nextnonce" EQUAL nonce-value
96440cb5e5dSvi  * response-auth        =  "rspauth" EQUAL response-digest
96540cb5e5dSvi  * response-digest      =  LDQUOT *LHEX RDQUOT
96640cb5e5dSvi  *
96740cb5e5dSvi  */
96840cb5e5dSvi int
sip_parse_ainfo_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)96940cb5e5dSvi sip_parse_ainfo_header(_sip_header_t *sip_header,
97040cb5e5dSvi     sip_parsed_header_t **header)
97140cb5e5dSvi {
972*559f8b54SToomas Soome 	return (sip_parse_hdr_parser1(sip_header, header, 0));
97340cb5e5dSvi }
97440cb5e5dSvi 
97540cb5e5dSvi /*
97640cb5e5dSvi  * Proxy-Authenticate  =  "Proxy-Authenticate" HCOLON challenge
97740cb5e5dSvi  * challenge           =  ("Digest" LWS digest-cln *(COMMA digest-cln))
97840cb5e5dSvi  *				/ other-challenge
97940cb5e5dSvi  * other-challenge     =  auth-scheme LWS auth-param
980*559f8b54SToomas Soome  *				*(COMMA auth-param)
98140cb5e5dSvi  * digest-cln          =  realm / domain / nonce
98240cb5e5dSvi  *				/ opaque / stale / algorithm
98340cb5e5dSvi  *				/ qop-options / auth-param
98440cb5e5dSvi  * realm               =  "realm" EQUAL realm-value
98540cb5e5dSvi  * realm-value         =  quoted-string
98640cb5e5dSvi  * domain              =  "domain" EQUAL LDQUOT URI
98740cb5e5dSvi  *				*( 1*SP URI ) RDQUOT
98840cb5e5dSvi  * URI                 =  absoluteURI / abs-path
98940cb5e5dSvi  * nonce               =  "nonce" EQUAL nonce-value
99040cb5e5dSvi  * nonce-value         =  quoted-string
99140cb5e5dSvi  * opaque              =  "opaque" EQUAL quoted-string
99240cb5e5dSvi  * stale               =  "stale" EQUAL ( "true" / "false" )
99340cb5e5dSvi  * algorithm           =  "algorithm" EQUAL ( "MD5" / "MD5-sess"
99440cb5e5dSvi  *			/ token )
99540cb5e5dSvi  * qop-options         =  "qop" EQUAL LDQUOT qop-value
99640cb5e5dSvi  *			*("," qop-value) RDQUOT
99740cb5e5dSvi  * qop-value           =  "auth" / "auth-int" / token
99840cb5e5dSvi  *
99940cb5e5dSvi  */
100040cb5e5dSvi int
sip_parse_pauthen_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)100140cb5e5dSvi sip_parse_pauthen_header(_sip_header_t *sip_header,
100240cb5e5dSvi     sip_parsed_header_t **header)
100340cb5e5dSvi {
100440cb5e5dSvi 	return (sip_parse_hdr_parser5(sip_header, header, B_TRUE));
100540cb5e5dSvi }
100640cb5e5dSvi 
100740cb5e5dSvi /*
100840cb5e5dSvi  * Proxy-Authorization  =  "Proxy-Authorization" HCOLON credentials
100940cb5e5dSvi  */
101040cb5e5dSvi int
sip_parse_pauthor_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)101140cb5e5dSvi sip_parse_pauthor_header(_sip_header_t *sip_header,
101240cb5e5dSvi     sip_parsed_header_t **header)
101340cb5e5dSvi {
101440cb5e5dSvi 	return (sip_parse_hdr_parser5(sip_header, header, B_TRUE));
101540cb5e5dSvi }
101640cb5e5dSvi 
101740cb5e5dSvi /*
101840cb5e5dSvi  * Proxy-Require  =  "Proxy-Require" HCOLON option-tag
101940cb5e5dSvi  *			*(COMMA option-tag)
102040cb5e5dSvi  * option-tag     =  token
102140cb5e5dSvi  */
102240cb5e5dSvi int
sip_parse_preq_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)102340cb5e5dSvi sip_parse_preq_header(_sip_header_t *sip_header,
102440cb5e5dSvi     sip_parsed_header_t **header)
102540cb5e5dSvi {
1026*559f8b54SToomas Soome 	return (sip_parse_hdr_parser1(sip_header, header, 0));
102740cb5e5dSvi }
102840cb5e5dSvi 
102940cb5e5dSvi /*
103040cb5e5dSvi  * WWW-Authenticate  =  "WWW-Authenticate" HCOLON challenge
103140cb5e5dSvi  * extension-header  =  header-name HCOLON header-value
103240cb5e5dSvi  * header-name       =  token
103340cb5e5dSvi  * header-value      =  *(TEXT-UTF8char / UTF8-CONT / LWS)
103440cb5e5dSvi  * message-body  =  *OCTET
103540cb5e5dSvi  *
103640cb5e5dSvi  */
103740cb5e5dSvi int
sip_parse_wauthen_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)103840cb5e5dSvi sip_parse_wauthen_header(_sip_header_t *sip_header,
103940cb5e5dSvi     sip_parsed_header_t **header)
104040cb5e5dSvi {
104140cb5e5dSvi 	return (sip_parse_hdr_parser5(sip_header, header, B_TRUE));
104240cb5e5dSvi }
104340cb5e5dSvi 
104440cb5e5dSvi /*
104540cb5e5dSvi  * Call-ID  =  ( "Call-ID" / "i" ) HCOLON callid
104640cb5e5dSvi  */
104740cb5e5dSvi int
sip_parse_cid_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)104840cb5e5dSvi sip_parse_cid_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
104940cb5e5dSvi {
105040cb5e5dSvi 	return (sip_parse_hdr_parser4(sip_header, header));
105140cb5e5dSvi }
105240cb5e5dSvi 
105340cb5e5dSvi /*
105440cb5e5dSvi  * CSeq  =  "CSeq" HCOLON 1*DIGIT LWS Method
105540cb5e5dSvi  */
105640cb5e5dSvi int
sip_parse_cseq_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)105740cb5e5dSvi sip_parse_cseq_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
105840cb5e5dSvi {
105940cb5e5dSvi 	sip_parsed_header_t	*parsed_header;
106040cb5e5dSvi 	sip_hdr_value_t		*cseq_value;
106140cb5e5dSvi 	int			len;
106240cb5e5dSvi 	char			*tmp_ptr;
106340cb5e5dSvi 	int			i;
106440cb5e5dSvi 	int			ret;
106540cb5e5dSvi 
106640cb5e5dSvi 	if ((ret = sip_prim_parsers(sip_header, header)) != 0)
106740cb5e5dSvi 		return (ret);
106840cb5e5dSvi 
106940cb5e5dSvi 	if (*header != NULL)
107040cb5e5dSvi 		return (0);
107140cb5e5dSvi 
107240cb5e5dSvi 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
107340cb5e5dSvi 	if (parsed_header == NULL)
107440cb5e5dSvi 		return (ENOMEM);
107540cb5e5dSvi 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
107640cb5e5dSvi 	parsed_header->sip_header = sip_header;
107740cb5e5dSvi 
107840cb5e5dSvi 	parsed_header->value =  calloc(1, sizeof (sip_hdr_value_t));
107940cb5e5dSvi 	if (parsed_header->value == NULL) {
108040cb5e5dSvi 		free(parsed_header);
108140cb5e5dSvi 		return (ENOMEM);
108240cb5e5dSvi 	}
108340cb5e5dSvi 	cseq_value = (sip_hdr_value_t *)parsed_header->value;
108440cb5e5dSvi 	cseq_value->sip_value_version = SIP_VALUE_VERSION_1;
108540cb5e5dSvi 	cseq_value->sip_value_start = sip_header->sip_hdr_current;
108640cb5e5dSvi 	if (sip_atoi(sip_header, &cseq_value->cseq_num)) {
108740cb5e5dSvi 		cseq_value->sip_value_state = SIP_VALUE_BAD;
108840cb5e5dSvi 		cseq_value->sip_value_end = sip_header->sip_hdr_end - 2;
108940cb5e5dSvi 		goto cseq_parse_done;
109040cb5e5dSvi 	}
109140cb5e5dSvi 	cseq_value->sip_value_header = parsed_header;
109240cb5e5dSvi 	/*
109340cb5e5dSvi 	 * Get method.
109440cb5e5dSvi 	 */
109540cb5e5dSvi 	if (sip_skip_white_space(sip_header) != 0) {
109640cb5e5dSvi 		cseq_value->sip_value_state = SIP_VALUE_BAD;
109740cb5e5dSvi 		cseq_value->sip_value_end = sip_header->sip_hdr_end - 2;
109840cb5e5dSvi 		goto cseq_parse_done;
109940cb5e5dSvi 	}
110040cb5e5dSvi 
110140cb5e5dSvi 	tmp_ptr = sip_header->sip_hdr_current;
110240cb5e5dSvi 
110340cb5e5dSvi 	if (sip_find_white_space(sip_header)) {
110440cb5e5dSvi 		cseq_value->sip_value_state = SIP_VALUE_BAD;
110540cb5e5dSvi 		cseq_value->sip_value_end = sip_header->sip_hdr_current;
110640cb5e5dSvi 		goto cseq_parse_done;
110740cb5e5dSvi 	}
110840cb5e5dSvi 
110940cb5e5dSvi 	len = sip_header->sip_hdr_current - tmp_ptr;
111040cb5e5dSvi 
111140cb5e5dSvi 	for (i = 1; i < MAX_SIP_METHODS; i++) {
111240cb5e5dSvi 		if (strncmp(sip_methods[i].name, tmp_ptr, len) == 0)
111340cb5e5dSvi 			break;
111440cb5e5dSvi 	}
111540cb5e5dSvi 
111640cb5e5dSvi 	if (i >= MAX_SIP_METHODS) {
111740cb5e5dSvi 		cseq_value->sip_value_state = SIP_VALUE_BAD;
111840cb5e5dSvi 		cseq_value->sip_value_end = sip_header->sip_hdr_current;
111940cb5e5dSvi 		goto cseq_parse_done;
112040cb5e5dSvi 	}
112140cb5e5dSvi 
112240cb5e5dSvi 	cseq_value->cseq_method = i;
112340cb5e5dSvi 	cseq_value->sip_value_end = sip_header->sip_hdr_current;
112440cb5e5dSvi cseq_parse_done:
112540cb5e5dSvi 
112640cb5e5dSvi 	sip_header->sip_hdr_parsed = parsed_header;
112740cb5e5dSvi 
112840cb5e5dSvi 	*header = parsed_header;
112940cb5e5dSvi 	return (0);
113040cb5e5dSvi }
113140cb5e5dSvi 
113240cb5e5dSvi 
113340cb5e5dSvi /*
113440cb5e5dSvi  * Via =  ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
113540cb5e5dSvi  * via-parm          =  sent-protocol LWS sent-by *( SEMI via-params )
113640cb5e5dSvi  * via-params        =  via-ttl / via-maddr
113740cb5e5dSvi  *                      / via-received / via-branch
113840cb5e5dSvi  *                      / via-extension
113940cb5e5dSvi  * via-ttl           =  "ttl" EQUAL ttl
114040cb5e5dSvi  * via-maddr         =  "maddr" EQUAL host
114140cb5e5dSvi  * via-received      =  "received" EQUAL (IPv4address / IPv6address)
114240cb5e5dSvi  * via-branch        =  "branch" EQUAL token
114340cb5e5dSvi  * via-extension     =  generic-param
114440cb5e5dSvi  * sent-protocol     =  protocol-name SLASH protocol-version
114540cb5e5dSvi  *                      SLASH transport
114640cb5e5dSvi  * protocol-name     =  "SIP" / token
114740cb5e5dSvi  * protocol-version  =  token
114840cb5e5dSvi  * transport         =  "UDP" / "TCP" / "TLS" / "SCTP"
114940cb5e5dSvi  *                      / other-transport
115040cb5e5dSvi  * sent-by           =  host [ COLON port ]
115140cb5e5dSvi  * ttl               =  1*3DIGIT ; 0 to 255
115240cb5e5dSvi  *
115340cb5e5dSvi  * There can be multiple via headers we always append the header.
115440cb5e5dSvi  */
115540cb5e5dSvi int
sip_parse_via_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)115640cb5e5dSvi sip_parse_via_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
115740cb5e5dSvi {
115840cb5e5dSvi 	sip_parsed_header_t	*parsed_header;
115940cb5e5dSvi 	int			ret;
116040cb5e5dSvi 	sip_hdr_value_t		*value = NULL;
116140cb5e5dSvi 	sip_hdr_value_t		*last_value = NULL;
116240cb5e5dSvi 
116340cb5e5dSvi 	if ((ret = sip_prim_parsers(sip_header, header)) != 0)
116440cb5e5dSvi 		return (ret);
116540cb5e5dSvi 
116640cb5e5dSvi 	if (*header != NULL)
116740cb5e5dSvi 		return (0);
116840cb5e5dSvi 
116940cb5e5dSvi 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
117040cb5e5dSvi 	if (parsed_header == NULL)
117140cb5e5dSvi 		return (ENOMEM);
117240cb5e5dSvi 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
117340cb5e5dSvi 	parsed_header->sip_header = sip_header;
117440cb5e5dSvi 
117540cb5e5dSvi 	while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
117640cb5e5dSvi 
117740cb5e5dSvi 		value = calloc(1, sizeof (sip_hdr_value_t));
117840cb5e5dSvi 		if (value == NULL) {
117940cb5e5dSvi 			sip_free_phdr(parsed_header);
118040cb5e5dSvi 			return (ENOMEM);
118140cb5e5dSvi 		}
118240cb5e5dSvi 		if (last_value != NULL)
118340cb5e5dSvi 			last_value->sip_next_value = value;
118440cb5e5dSvi 		else
118540cb5e5dSvi 			parsed_header->value = (sip_value_t *)value;
118640cb5e5dSvi 
118740cb5e5dSvi 		value->sip_value_version = SIP_VALUE_VERSION_1;
118840cb5e5dSvi 		value->sip_value_start = sip_header->sip_hdr_current;
118940cb5e5dSvi 		value->sip_value_header = parsed_header;
119040cb5e5dSvi 		value->via_protocol_name.sip_str_ptr =
119140cb5e5dSvi 		    sip_header->sip_hdr_current;
119240cb5e5dSvi 
119340cb5e5dSvi 		/*
119440cb5e5dSvi 		 * Check to see if there is a version number
119540cb5e5dSvi 		 */
119640cb5e5dSvi 		if (sip_get_protocol_version(sip_header,
119740cb5e5dSvi 		    &value->via_protocol) != 0) {
119840cb5e5dSvi 			if (sip_goto_next_value(sip_header) != 0) {
119940cb5e5dSvi 				sip_free_phdr(parsed_header);
120040cb5e5dSvi 				return (EPROTO);
120140cb5e5dSvi 			}
120240cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
120340cb5e5dSvi 			goto get_next_via_value;
120440cb5e5dSvi 		}
120540cb5e5dSvi 
120640cb5e5dSvi 		if (sip_find_token(sip_header, SIP_SLASH) != 0) {
120740cb5e5dSvi 			if (sip_goto_next_value(sip_header) != 0) {
120840cb5e5dSvi 				sip_free_phdr(parsed_header);
120940cb5e5dSvi 				return (EPROTO);
121040cb5e5dSvi 			}
121140cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
121240cb5e5dSvi 			goto get_next_via_value;
121340cb5e5dSvi 		}
121440cb5e5dSvi 
121540cb5e5dSvi 		if (sip_skip_white_space(sip_header) != 0) {
121640cb5e5dSvi 			if (sip_goto_next_value(sip_header) != 0) {
121740cb5e5dSvi 				sip_free_phdr(parsed_header);
121840cb5e5dSvi 				return (EPROTO);
121940cb5e5dSvi 			}
122040cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
122140cb5e5dSvi 			goto get_next_via_value;
122240cb5e5dSvi 		}
122340cb5e5dSvi 
122440cb5e5dSvi 		value->via_protocol_transport.sip_str_ptr =
122540cb5e5dSvi 		    sip_header->sip_hdr_current;
122640cb5e5dSvi 		if (sip_find_white_space(sip_header) != 0) {
122740cb5e5dSvi 			if (sip_goto_next_value(sip_header) != 0) {
122840cb5e5dSvi 				sip_free_phdr(parsed_header);
122940cb5e5dSvi 				return (EPROTO);
123040cb5e5dSvi 			}
123140cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
123240cb5e5dSvi 			goto get_next_via_value;
123340cb5e5dSvi 		}
123440cb5e5dSvi 
123540cb5e5dSvi 		value->via_protocol_transport.sip_str_len =
123640cb5e5dSvi 		    sip_header->sip_hdr_current -
123740cb5e5dSvi 		    value->via_protocol_transport.sip_str_ptr;
123840cb5e5dSvi 
123940cb5e5dSvi 		if (sip_skip_white_space(sip_header) != 0) {
124040cb5e5dSvi 			if (sip_goto_next_value(sip_header) != 0) {
124140cb5e5dSvi 				sip_free_phdr(parsed_header);
124240cb5e5dSvi 				return (EPROTO);
124340cb5e5dSvi 			}
124440cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
124540cb5e5dSvi 			goto get_next_via_value;
124640cb5e5dSvi 		}
124740cb5e5dSvi 
124840cb5e5dSvi 		value->via_sent_by_host.sip_str_ptr =
124940cb5e5dSvi 		    sip_header->sip_hdr_current;
125040cb5e5dSvi 		if (*sip_header->sip_hdr_current == '[') {
125140cb5e5dSvi 			if (sip_find_token(sip_header, ']')) {
125240cb5e5dSvi 				if (sip_goto_next_value(sip_header) != 0) {
125340cb5e5dSvi 					sip_free_phdr(parsed_header);
125440cb5e5dSvi 					return (EPROTO);
125540cb5e5dSvi 				}
125640cb5e5dSvi 				value->sip_value_state = SIP_VALUE_BAD;
125740cb5e5dSvi 				goto get_next_via_value;
125840cb5e5dSvi 			}
125940cb5e5dSvi 		} else if (sip_find_separator(sip_header, SIP_SEMI, SIP_COMMA,
1260df4705eaSgm 		    SIP_HCOLON, B_FALSE)) {
126140cb5e5dSvi 			if (sip_goto_next_value(sip_header) != 0) {
126240cb5e5dSvi 				sip_free_phdr(parsed_header);
126340cb5e5dSvi 				return (EPROTO);
126440cb5e5dSvi 			}
126540cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
126640cb5e5dSvi 			goto get_next_via_value;
126740cb5e5dSvi 		}
126840cb5e5dSvi 		value->via_sent_by_host.sip_str_len =
126940cb5e5dSvi 		    sip_header->sip_hdr_current -
127040cb5e5dSvi 		    value->via_sent_by_host.sip_str_ptr;
127140cb5e5dSvi 
127240cb5e5dSvi 		if (sip_skip_white_space(sip_header) != 0) {
127340cb5e5dSvi 			if (sip_goto_next_value(sip_header) != 0) {
127440cb5e5dSvi 				sip_free_phdr(parsed_header);
127540cb5e5dSvi 				return (EPROTO);
127640cb5e5dSvi 			}
127740cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
127840cb5e5dSvi 			goto get_next_via_value;
127940cb5e5dSvi 		}
128040cb5e5dSvi 
128140cb5e5dSvi 		if (*sip_header->sip_hdr_current == SIP_HCOLON) {
128240cb5e5dSvi 			sip_header->sip_hdr_current++;
128340cb5e5dSvi 			/*
128440cb5e5dSvi 			 * We have a port number
128540cb5e5dSvi 			 */
128640cb5e5dSvi 			if (sip_atoi(sip_header, &value->via_sent_by_port) !=
128740cb5e5dSvi 			    0) {
128840cb5e5dSvi 				if (sip_goto_next_value(sip_header) != 0) {
128940cb5e5dSvi 					sip_free_phdr(parsed_header);
129040cb5e5dSvi 					return (EPROTO);
129140cb5e5dSvi 				}
129240cb5e5dSvi 				value->sip_value_state = SIP_VALUE_BAD;
129340cb5e5dSvi 				goto get_next_via_value;
129440cb5e5dSvi 			}
129540cb5e5dSvi 
129640cb5e5dSvi 		}
129740cb5e5dSvi 
129840cb5e5dSvi 		/*
129940cb5e5dSvi 		 * Do some sanity checking.
130040cb5e5dSvi 		 * This should be replaced by a v4/v6 address check.
130140cb5e5dSvi 		 */
130240cb5e5dSvi 		if (value->via_sent_by_host.sip_str_len == 0 ||
130340cb5e5dSvi 		    (!isalnum(*value->via_sent_by_host.sip_str_ptr) &&
130440cb5e5dSvi 		    *value->via_sent_by_host.sip_str_ptr != '[')) {
130540cb5e5dSvi 			if (sip_goto_next_value(sip_header) != 0) {
130640cb5e5dSvi 				sip_free_phdr(parsed_header);
130740cb5e5dSvi 				return (EPROTO);
130840cb5e5dSvi 			}
130940cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
131040cb5e5dSvi 			goto get_next_via_value;
131140cb5e5dSvi 		}
131240cb5e5dSvi 
131340cb5e5dSvi 		ret = sip_parse_params(sip_header, &value->sip_param_list);
131440cb5e5dSvi 		if (ret == EPROTO) {
131540cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
131640cb5e5dSvi 		} else if (ret != 0) {
131740cb5e5dSvi 			sip_free_phdr(parsed_header);
131840cb5e5dSvi 			return (ret);
131940cb5e5dSvi 		}
132040cb5e5dSvi get_next_via_value:
132140cb5e5dSvi 		value->sip_value_end = sip_header->sip_hdr_current;
132240cb5e5dSvi 
132340cb5e5dSvi 		if (sip_find_token(sip_header, SIP_COMMA) != 0)
132440cb5e5dSvi 			break;
132540cb5e5dSvi 		last_value = value;
132640cb5e5dSvi 		(void) sip_skip_white_space(sip_header);
132740cb5e5dSvi 	}
132840cb5e5dSvi 
132940cb5e5dSvi 	sip_header->sip_hdr_parsed = parsed_header;
133040cb5e5dSvi 
133140cb5e5dSvi 	*header = parsed_header;
133240cb5e5dSvi 	return (0);
133340cb5e5dSvi }
133440cb5e5dSvi 
133540cb5e5dSvi /*
133640cb5e5dSvi  * Max-Forwards  =  "Max-Forwards" HCOLON 1*DIGIT
133740cb5e5dSvi  */
133840cb5e5dSvi int
sip_parse_maxf_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)133940cb5e5dSvi sip_parse_maxf_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
134040cb5e5dSvi {
134140cb5e5dSvi 	return (sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL));
134240cb5e5dSvi }
134340cb5e5dSvi 
134440cb5e5dSvi /*
134540cb5e5dSvi  * Content-Type     =  ( "Content-Type" / "c" ) HCOLON media-type
134640cb5e5dSvi  * media-type       =  m-type SLASH m-subtype *(SEMI m-parameter)
134740cb5e5dSvi  * m-type           =  discrete-type / composite-type
134840cb5e5dSvi  * discrete-type    =  "text" / "image" / "audio" / "video"
134940cb5e5dSvi  *                     / "application" / extension-token
135040cb5e5dSvi  * composite-type   =  "message" / "multipart" / extension-token
135140cb5e5dSvi  * extension-token  =  ietf-token / x-token
135240cb5e5dSvi  * ietf-token       =  token
135340cb5e5dSvi  * x-token          =  "x-" token
135440cb5e5dSvi  * m-subtype        =  extension-token / iana-token
135540cb5e5dSvi  * iana-token       =  token
135640cb5e5dSvi  * m-parameter      =  m-attribute EQUAL m-value
135740cb5e5dSvi  * m-attribute      =  token
135840cb5e5dSvi  * m-value          =  token / quoted-string
135940cb5e5dSvi  */
136040cb5e5dSvi int
sip_parse_ctype_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)136140cb5e5dSvi sip_parse_ctype_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
136240cb5e5dSvi {
136340cb5e5dSvi 	return (sip_parse_hdr_parser1(sip_header, header, SIP_SLASH));
136440cb5e5dSvi }
136540cb5e5dSvi 
136640cb5e5dSvi /*
136740cb5e5dSvi  * Content-Length  =  ( "Content-Length" / "l" ) HCOLON 1*DIGIT
136840cb5e5dSvi  */
136940cb5e5dSvi int
sip_parse_clen_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)137040cb5e5dSvi sip_parse_clen_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
137140cb5e5dSvi {
137240cb5e5dSvi 	return (sip_parse_hdr_parser2(sip_header, header, SIP_INT_VAL));
137340cb5e5dSvi }
137440cb5e5dSvi 
137540cb5e5dSvi /*
137640cb5e5dSvi  * Generic parser for Contact, From, To, Route and Record-Route headers
137740cb5e5dSvi  *
137840cb5e5dSvi  * Contact = ("Contact" / "m" ) HCOLON
137940cb5e5dSvi  *		( STAR / (contact-param *(COMMA contact-param)))
138040cb5e5dSvi  * contact-param  =  (name-addr / addr-spec) *(SEMI contact-params)
138140cb5e5dSvi  * name-addr      =  [ display-name ] LAQUOT addr-spec RAQUOT
138240cb5e5dSvi  * addr-spec      =  SIP-URI / SIPS-URI / absoluteURI
138340cb5e5dSvi  * display-name   =  *(token LWS)/ quoted-string
138440cb5e5dSvi  * contact-params     =  c-p-q / c-p-expires
138540cb5e5dSvi  *                     / contact-extension
138640cb5e5dSvi  *
138740cb5e5dSvi  * From =  ( "From" / "f" ) HCOLON from-spec
138840cb5e5dSvi  * from-spec = ( name-addr / addr-spec )
138940cb5e5dSvi  *	*( SEMI from-param )
139040cb5e5dSvi  * from-param  =  tag-param / generic-param
139140cb5e5dSvi  * tag-param   =  "tag" EQUAL token
139240cb5e5dSvi  *
139340cb5e5dSvi  * To =  ( "To" / "t" ) HCOLON ( name-addr
139440cb5e5dSvi  *	/ addr-spec ) *( SEMI to-param )
139540cb5e5dSvi  * to-param  =  tag-param / generic-param
139640cb5e5dSvi  *
139740cb5e5dSvi  * Route        =  "Route" HCOLON route-param *(COMMA route-param)
139840cb5e5dSvi  * route-param  =  name-addr *( SEMI rr-param )
139940cb5e5dSvi  *
140040cb5e5dSvi  * Record-Route  =  "Record-Route" HCOLON rec-route *(COMMA rec-route)
140140cb5e5dSvi  * rec-route     =  name-addr *( SEMI rr-param )
140240cb5e5dSvi  * rr-param      =  generic-param
140340cb5e5dSvi  *
140440cb5e5dSvi  * We could have multiple values for these headers. For the ones that have
140540cb5e5dSvi  * a display name we will have a LAQUOT/RAQUOT. If we encounter an error
140640cb5e5dSvi  * when parsing a value, we mark the value as bad and start paring the
140740cb5e5dSvi  * next value, if present. Before we start parsing the next value, we
140840cb5e5dSvi  * check for any parameters, if present.
140940cb5e5dSvi  */
141040cb5e5dSvi int
sip_parse_cftr_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)141140cb5e5dSvi sip_parse_cftr_header(_sip_header_t *sip_header, sip_parsed_header_t **header)
141240cb5e5dSvi {
141340cb5e5dSvi 	sip_parsed_header_t	*parsed_header;
141440cb5e5dSvi 	char			*tmp_ptr;
141540cb5e5dSvi 	char			*tmp_ptr_2;
141640cb5e5dSvi 	int			ret;
141740cb5e5dSvi 	sip_hdr_value_t		*value = NULL;
141840cb5e5dSvi 	sip_hdr_value_t		*last_value = NULL;
141940cb5e5dSvi 
142040cb5e5dSvi 	if ((ret = sip_prim_parsers(sip_header, header)) != 0)
142140cb5e5dSvi 		return (ret);
142240cb5e5dSvi 
142340cb5e5dSvi 	if (*header != NULL)
142440cb5e5dSvi 		return (0);
142540cb5e5dSvi 
142640cb5e5dSvi 	parsed_header = calloc(1, sizeof (sip_parsed_header_t));
142740cb5e5dSvi 	if (parsed_header == NULL)
142840cb5e5dSvi 		return (ENOMEM);
142940cb5e5dSvi 	parsed_header->sip_parsed_header_version = SIP_PARSED_HEADER_VERSION_1;
143040cb5e5dSvi 	parsed_header->sip_header = sip_header;
143140cb5e5dSvi 	while (sip_header->sip_hdr_current < sip_header->sip_hdr_end) {
143240cb5e5dSvi 		boolean_t	quoted_name = B_FALSE;
143340cb5e5dSvi 
143440cb5e5dSvi 		value =  calloc(1, sizeof (sip_hdr_value_t));
143540cb5e5dSvi 		if (value == NULL) {
143640cb5e5dSvi 			sip_free_cftr_header(parsed_header);
143740cb5e5dSvi 			return (ENOMEM);
143840cb5e5dSvi 		}
143940cb5e5dSvi 		if (last_value != NULL)
144040cb5e5dSvi 			last_value->sip_next_value = value;
144140cb5e5dSvi 		else
144240cb5e5dSvi 			parsed_header->value = (sip_value_t *)value;
144340cb5e5dSvi 		if (*sip_header->sip_hdr_current == SIP_QUOTE) {
144440cb5e5dSvi 			sip_header->sip_hdr_current++;
144540cb5e5dSvi 			quoted_name = B_TRUE;
144640cb5e5dSvi 		}
144740cb5e5dSvi 		value->sip_value_version = SIP_VALUE_VERSION_1;
144840cb5e5dSvi 		value->sip_value_start = sip_header->sip_hdr_current;
144940cb5e5dSvi 		value->sip_value_header = parsed_header;
145040cb5e5dSvi 		/*
145140cb5e5dSvi 		 * let's see if there is a display name
145240cb5e5dSvi 		 */
145340cb5e5dSvi 		if (*sip_header->sip_hdr_current != SIP_LAQUOT) {
145440cb5e5dSvi 
145540cb5e5dSvi 			tmp_ptr = sip_header->sip_hdr_current;
145640cb5e5dSvi 			/*
145740cb5e5dSvi 			 * According to 20.10 '<' may not have a leading
145840cb5e5dSvi 			 * space.
145940cb5e5dSvi 			 */
146040cb5e5dSvi 			if (quoted_name &&
146140cb5e5dSvi 			    sip_find_token(sip_header, SIP_QUOTE) != 0) {
146240cb5e5dSvi 				if (sip_goto_next_value(sip_header) != 0) {
146340cb5e5dSvi 					sip_free_cftr_header(parsed_header);
146440cb5e5dSvi 					return (EPROTO);
146540cb5e5dSvi 				}
146640cb5e5dSvi 				value->sip_value_state = SIP_VALUE_BAD;
146740cb5e5dSvi 				goto get_next_cftr_value;
146840cb5e5dSvi 			} else if (sip_find_separator(sip_header, SIP_SEMI,
1469df4705eaSgm 			    SIP_LAQUOT, SIP_COMMA, B_TRUE) != 0) {
147040cb5e5dSvi 				/*
147140cb5e5dSvi 				 * only a uri.
147240cb5e5dSvi 				 */
147340cb5e5dSvi 				value->cftr_uri.sip_str_ptr = tmp_ptr;
147440cb5e5dSvi 				value->cftr_uri.sip_str_len =
147540cb5e5dSvi 				    sip_header->sip_hdr_current - tmp_ptr;
147640cb5e5dSvi 				/*
147740cb5e5dSvi 				 * It's an error not to have a uri.
147840cb5e5dSvi 				 */
147940cb5e5dSvi 				if (value->cftr_uri.sip_str_len == 0) {
148040cb5e5dSvi 					if (sip_goto_next_value(sip_header) !=
148140cb5e5dSvi 					    0) {
148240cb5e5dSvi 						sip_free_cftr_header(
148340cb5e5dSvi 						    parsed_header);
148440cb5e5dSvi 						return (EPROTO);
148540cb5e5dSvi 					}
148640cb5e5dSvi 					value->sip_value_state = SIP_VALUE_BAD;
148740cb5e5dSvi 					goto get_next_cftr_value;
148840cb5e5dSvi 				}
1489df4705eaSgm 				goto get_next_cftr_value;
149040cb5e5dSvi 			}
1491df4705eaSgm 			/*
1492df4705eaSgm 			 * This is needed to get rid of leading white spaces of
1493df4705eaSgm 			 * display name or uri
1494df4705eaSgm 			 */
1495df4705eaSgm 			--sip_header->sip_hdr_current;
1496df4705eaSgm 			(void) sip_reverse_skip_white_space(sip_header);
1497df4705eaSgm 			++sip_header->sip_hdr_current;
149840cb5e5dSvi 			tmp_ptr_2 = sip_header->sip_hdr_current;
149940cb5e5dSvi 			if (*sip_header->sip_hdr_current == SIP_SP) {
150040cb5e5dSvi 				if (sip_skip_white_space(sip_header) != 0) {
150140cb5e5dSvi 					/*
150240cb5e5dSvi 					 * only a uri.
150340cb5e5dSvi 					 */
150440cb5e5dSvi 					value->cftr_uri.sip_str_ptr = tmp_ptr;
150540cb5e5dSvi 					value->cftr_uri.sip_str_len =
150640cb5e5dSvi 					    tmp_ptr_2 - tmp_ptr;
150740cb5e5dSvi 					/*
150840cb5e5dSvi 					 * It's an error not to have a uri.
150940cb5e5dSvi 					 */
151040cb5e5dSvi 					if (value->cftr_uri.sip_str_len == 0) {
151140cb5e5dSvi 						if (sip_goto_next_value(
151240cb5e5dSvi 						    sip_header) != 0) {
151340cb5e5dSvi 							sip_free_cftr_header(
151440cb5e5dSvi 							    parsed_header);
151540cb5e5dSvi 							return (EPROTO);
151640cb5e5dSvi 						}
151740cb5e5dSvi 						value->sip_value_state =
151840cb5e5dSvi 						    SIP_VALUE_BAD;
151940cb5e5dSvi 						goto get_next_cftr_value;
152040cb5e5dSvi 					}
1521df4705eaSgm 					goto get_next_cftr_value;
152240cb5e5dSvi 				}
152340cb5e5dSvi 			}
152440cb5e5dSvi 
152540cb5e5dSvi 			if (*sip_header->sip_hdr_current != SIP_LAQUOT) {
152640cb5e5dSvi 				/*
152740cb5e5dSvi 				 * No display name here.
152840cb5e5dSvi 				 */
152940cb5e5dSvi 				value->cftr_uri.sip_str_ptr = tmp_ptr;
153040cb5e5dSvi 				value->cftr_uri.sip_str_len = tmp_ptr_2 -
153140cb5e5dSvi 				    tmp_ptr;
153240cb5e5dSvi 				/*
153340cb5e5dSvi 				 * It's an error not to have a uri.
153440cb5e5dSvi 				 */
153540cb5e5dSvi 				if (value->cftr_uri.sip_str_len == 0) {
153640cb5e5dSvi 					if (sip_goto_next_value(sip_header) !=
153740cb5e5dSvi 					    0) {
153840cb5e5dSvi 						sip_free_cftr_header(
153940cb5e5dSvi 						    parsed_header);
154040cb5e5dSvi 						return (EPROTO);
154140cb5e5dSvi 					}
154240cb5e5dSvi 					value->sip_value_state = SIP_VALUE_BAD;
154340cb5e5dSvi 					goto get_next_cftr_value;
154440cb5e5dSvi 				}
154540cb5e5dSvi 				goto get_params;
154640cb5e5dSvi 			}
154740cb5e5dSvi 
154840cb5e5dSvi 			value->cftr_name = malloc(sizeof (sip_str_t));
154940cb5e5dSvi 			if (value->cftr_name == NULL) {
155040cb5e5dSvi 				sip_free_cftr_header(parsed_header);
155140cb5e5dSvi 				return (ENOMEM);
155240cb5e5dSvi 			}
155340cb5e5dSvi 			value->cftr_name->sip_str_ptr = tmp_ptr;
155440cb5e5dSvi 			value->cftr_name->sip_str_len = tmp_ptr_2 - tmp_ptr;
155540cb5e5dSvi 			if (quoted_name)
155640cb5e5dSvi 				value->cftr_name->sip_str_len--;
155740cb5e5dSvi 		}
155840cb5e5dSvi 
155940cb5e5dSvi 		if (sip_find_token(sip_header, SIP_LAQUOT) != 0) {
156040cb5e5dSvi 			if (sip_goto_next_value(sip_header) != 0) {
156140cb5e5dSvi 				sip_free_cftr_header(parsed_header);
156240cb5e5dSvi 				return (EPROTO);
156340cb5e5dSvi 			}
156440cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
156540cb5e5dSvi 			goto get_next_cftr_value;
156640cb5e5dSvi 		}
156740cb5e5dSvi 
156840cb5e5dSvi 		if (*sip_header->sip_hdr_current == SIP_SP) {
156940cb5e5dSvi 			if (sip_skip_white_space(sip_header) != 0) {
157040cb5e5dSvi 				if (sip_goto_next_value(sip_header) != 0) {
157140cb5e5dSvi 					sip_free_cftr_header(parsed_header);
157240cb5e5dSvi 					return (EPROTO);
157340cb5e5dSvi 				}
157440cb5e5dSvi 				value->sip_value_state = SIP_VALUE_BAD;
157540cb5e5dSvi 				goto get_next_cftr_value;
157640cb5e5dSvi 			}
157740cb5e5dSvi 		}
157840cb5e5dSvi 
157940cb5e5dSvi 		tmp_ptr = sip_header->sip_hdr_current;
158040cb5e5dSvi 
1581*559f8b54SToomas Soome 		if (sip_find_separator(sip_header, SIP_RAQUOT, 0, 0, B_FALSE)) {
158240cb5e5dSvi 			if (sip_goto_next_value(sip_header) != 0) {
158340cb5e5dSvi 				sip_free_cftr_header(parsed_header);
158440cb5e5dSvi 				return (EPROTO);
158540cb5e5dSvi 			}
158640cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
158740cb5e5dSvi 			goto get_next_cftr_value;
158840cb5e5dSvi 		}
158940cb5e5dSvi 
159040cb5e5dSvi 		value->cftr_uri.sip_str_ptr = tmp_ptr;
159140cb5e5dSvi 		value->cftr_uri.sip_str_len =
159240cb5e5dSvi 		    sip_header->sip_hdr_current - tmp_ptr;
159340cb5e5dSvi 
159440cb5e5dSvi 		if (sip_find_token(sip_header, SIP_RAQUOT) != 0) {
159540cb5e5dSvi 			if (sip_goto_next_value(sip_header) != 0) {
159640cb5e5dSvi 				sip_free_cftr_header(parsed_header);
159740cb5e5dSvi 				return (EINVAL);
159840cb5e5dSvi 			}
159940cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
160040cb5e5dSvi 			goto get_next_cftr_value;
160140cb5e5dSvi 		}
160240cb5e5dSvi 
160340cb5e5dSvi 		if (value->cftr_uri.sip_str_len <= strlen("<>")) {
160440cb5e5dSvi 			if (sip_goto_next_value(sip_header) != 0) {
160540cb5e5dSvi 				sip_free_cftr_header(parsed_header);
160640cb5e5dSvi 				return (EPROTO);
160740cb5e5dSvi 			}
160840cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
160940cb5e5dSvi 			goto get_next_cftr_value;
161040cb5e5dSvi 		}
161140cb5e5dSvi 
161240cb5e5dSvi get_params:
161340cb5e5dSvi 		ret = sip_parse_params(sip_header, &value->sip_param_list);
161440cb5e5dSvi 		if (ret == EPROTO) {
161540cb5e5dSvi 			value->sip_value_state = SIP_VALUE_BAD;
161640cb5e5dSvi 		} else if (ret != 0) {
161740cb5e5dSvi 			sip_free_cftr_header(parsed_header);
161840cb5e5dSvi 			return (ret);
161940cb5e5dSvi 		}
162040cb5e5dSvi get_next_cftr_value:
162140cb5e5dSvi 		value->sip_value_end = sip_header->sip_hdr_current;
162240cb5e5dSvi 
162340cb5e5dSvi 		/*
162440cb5e5dSvi 		 * Parse uri
162540cb5e5dSvi 		 */
162640cb5e5dSvi 		if (value->cftr_uri.sip_str_len > 0) {
1627df4705eaSgm 			int			error;
1628df4705eaSgm 			uint_t			uri_errflags;
1629df4705eaSgm 			char			*uri = "*";
1630df4705eaSgm 			_sip_msg_t		*sip_msg;
1631df4705eaSgm 			sip_message_type_t	*msg_type;
163240cb5e5dSvi 
163340cb5e5dSvi 			value->sip_value_parsed_uri = sip_parse_uri(
163440cb5e5dSvi 			    &value->cftr_uri, &error);
163540cb5e5dSvi 			if (value->sip_value_parsed_uri == NULL) {
163640cb5e5dSvi 				sip_free_cftr_header(parsed_header);
163740cb5e5dSvi 				return (ENOMEM);
163840cb5e5dSvi 			}
1639df4705eaSgm 			uri_errflags = ((_sip_uri_t *)value->
1640df4705eaSgm 			    sip_value_parsed_uri)->sip_uri_errflags;
1641df4705eaSgm 			if (error != 0 || uri_errflags != 0) {
1642df4705eaSgm 				if ((strcmp(SIP_CONTACT, sip_header->
1643df4705eaSgm 				    sip_header_functions->header_name) == 0) &&
1644df4705eaSgm 				    (strncmp(value->cftr_uri.sip_str_ptr, uri,
1645df4705eaSgm 				    strlen(uri)) == 0) && (strlen(uri) ==
1646df4705eaSgm 				    value->cftr_uri.sip_str_len)) {
1647df4705eaSgm 					sip_msg = sip_header->sip_hdr_sipmsg;
1648df4705eaSgm 					msg_type = sip_msg->sip_msg_req_res;
1649df4705eaSgm 					if (msg_type->is_request && msg_type->
1650df4705eaSgm 					    sip_req_method == REGISTER) {
1651df4705eaSgm 						error = 0;
1652df4705eaSgm 						((_sip_uri_t *)value->
1653df4705eaSgm 						    sip_value_parsed_uri)->
1654df4705eaSgm 						    sip_uri_errflags = 0;
1655df4705eaSgm 					} else {
1656df4705eaSgm 						value->sip_value_state =
1657df4705eaSgm 						    SIP_VALUE_BAD;
1658df4705eaSgm 					}
1659df4705eaSgm 				} else {
1660df4705eaSgm 					value->sip_value_state = SIP_VALUE_BAD;
1661df4705eaSgm 				}
166240cb5e5dSvi 			}
166340cb5e5dSvi 		}
166440cb5e5dSvi 
166540cb5e5dSvi 		(void) sip_find_token(sip_header, SIP_COMMA);
166640cb5e5dSvi 		last_value = value;
166740cb5e5dSvi 		(void) sip_skip_white_space(sip_header);
166840cb5e5dSvi 	}
166940cb5e5dSvi 
167040cb5e5dSvi 	sip_header->sip_hdr_parsed = parsed_header;
167140cb5e5dSvi 
167240cb5e5dSvi 	*header = parsed_header;
167340cb5e5dSvi 	return (0);
167440cb5e5dSvi }
167540cb5e5dSvi 
167640cb5e5dSvi /*
167740cb5e5dSvi  * PAssertedID = "P-Asserted-Identity" HCOLON PAssertedID-value
167840cb5e5dSvi  *               *(COMMA PAssertedID-value)
167940cb5e5dSvi  * PAssertedID-value = name-addr / addr-spec
168040cb5e5dSvi  */
168140cb5e5dSvi int
sip_parse_passertedid(_sip_header_t * sip_header,sip_parsed_header_t ** header)168240cb5e5dSvi sip_parse_passertedid(_sip_header_t *sip_header, sip_parsed_header_t **header)
168340cb5e5dSvi {
168440cb5e5dSvi 	return (sip_parse_hdr_parser3(sip_header, header, SIP_STRS_VAL,
168540cb5e5dSvi 	    B_TRUE));
168640cb5e5dSvi }
168740cb5e5dSvi 
168840cb5e5dSvi /*
168940cb5e5dSvi  * PPreferredID = "P-Preferred-Identity" HCOLON PPreferredID-value
169040cb5e5dSvi  *               *(COMMA PAssertedID-value)
169140cb5e5dSvi  * PPreferredID-value = name-addr / addr-spec
169240cb5e5dSvi  */
169340cb5e5dSvi int
sip_parse_ppreferredid(_sip_header_t * sip_header,sip_parsed_header_t ** header)169440cb5e5dSvi sip_parse_ppreferredid(_sip_header_t *sip_header, sip_parsed_header_t **header)
169540cb5e5dSvi {
169640cb5e5dSvi 	return (sip_parse_hdr_parser3(sip_header, header, SIP_STRS_VAL,
169740cb5e5dSvi 	    B_TRUE));
169840cb5e5dSvi }
169940cb5e5dSvi 
170040cb5e5dSvi 
170140cb5e5dSvi /*
170240cb5e5dSvi  * We don't do anything for a header we don't understand
170340cb5e5dSvi  */
170440cb5e5dSvi /* ARGSUSED */
170540cb5e5dSvi int
sip_parse_unknown_header(_sip_header_t * sip_header,sip_parsed_header_t ** header)170640cb5e5dSvi sip_parse_unknown_header(_sip_header_t *sip_header,
170740cb5e5dSvi     sip_parsed_header_t **header)
170840cb5e5dSvi {
170940cb5e5dSvi 	return (EINVAL);
171040cb5e5dSvi }
1711