xref: /illumos-gate/usr/src/lib/libsip/common/sip_parse_hdrs.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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  */
49 int
50 sip_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  */
62 int
63 sip_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  */
74 int
75 sip_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  */
87 int
88 sip_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  */
96 int
97 sip_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 
163 end:
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  */
175 int
176 sip_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  */
192 int
193 sip_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  */
203 int
204 sip_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  */
217 int
218 sip_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  */
232 int
233 sip_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  */
331 int
332 sip_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  */
341 int
342 sip_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  */
351 int
352 sip_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  */
361 int
362 sip_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  */
384 int
385 sip_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  */
394 int
395 sip_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  */
404 int
405 sip_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  */
418 int
419 sip_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  */
432 int
433 sip_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  */
445 int
446 sip_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  */
456 int
457 sip_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  */
468 int
469 sip_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  */
543 int
544 sip_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  */
552 int
553 sip_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  */
564 int
565 sip_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  */
576 int
577 sip_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  */
650 int
651 sip_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  */
663 int
664 sip_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  */
680 int
681 sip_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 
760 get_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  */
780 int
781 sip_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 
863 rack_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  */
873 int
874 sip_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  */
890 int
891 sip_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  */
915 int
916 sip_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  */
950 int
951 sip_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  */
968 int
969 sip_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  */
1000 int
1001 sip_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  */
1010 int
1011 sip_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  */
1022 int
1023 sip_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  */
1037 int
1038 sip_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  */
1047 int
1048 sip_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  */
1056 int
1057 sip_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;
1124 cseq_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  */
1155 int
1156 sip_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 		}
1320 get_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  */
1338 int
1339 sip_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  */
1360 int
1361 sip_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  */
1369 int
1370 sip_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  */
1410 int
1411 sip_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 
1612 get_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 		}
1620 get_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  */
1681 int
1682 sip_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  */
1693 int
1694 sip_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 */
1705 int
1706 sip_parse_unknown_header(_sip_header_t *sip_header,
1707     sip_parsed_header_t **header)
1708 {
1709 	return (EINVAL);
1710 }
1711