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