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