/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <strings.h>
#include <sip.h>
#include "sip_msg.h"
#include "sip_miscdefs.h"
#include "sip_parse_generic.h"
#include "sip_parse_uri.h"
/*
* Accept = "Accept" HCOLON [ accept-range *(COMMA accept-range) ]
* accept-range = media-range *(SEMI accept-param)
* media-range = ("* / *" | (m-type SLASH "*") | (m-type SLASH m-subtype))
* *(SEMI m-param)
* accept-param = ("q" EQUAL qvalue) | generic-param
* qvalue = ("0" ["." 0*3DIGIT]) | ("1" ["." 0*3DIGIT])
* generic-param = token [ EQUAL gen-value]
* gen-value = token | host | quoted-str
*/
int
{
if (sip_is_empty_hdr(sip_header))
}
/*
* Accept-Encoding = "Accept-Encoding" ":" 1#(codings [ ";" "q" "=" qval])
* codings = (content-coding | "*")
* content-coding = token
*/
int
{
}
/*
* Accept-Language = "Accept-Language" ":" [ lang * (COMMA lang) ]
* lang = lang-range *(SEMI accept-param)
* lang-range = ((1*8ALPHA * ("-" 1*8ALPHA)) | "*"
*/
int
{
if (sip_is_empty_hdr(sip_header))
}
/*
* Alert-Info = "Alert-Info" ":" alert-param *(COMMA alert-param)
* alert-param = LAQUOT absoluteURI RAQUOT * (SEMI generic-param)
*/
int
{
}
/*
* Allow = "Allow" ":" method-name1[, method-name2..]
*/
int
{
int len;
int i;
int ret;
return (ret);
return (0);
if (parsed_header == NULL)
return (ENOMEM);
return (ENOMEM);
}
if (last_value != NULL)
else
}
for (i = 1; i < MAX_SIP_METHODS; i++) {
len) == 0) {
break;
}
}
if (i >= MAX_SIP_METHODS) {
if (multi_value)
goto next_val;
else
goto end;
}
if (!multi_value)
goto end;
break;
last_value = value;
(void) sip_skip_white_space(hdr);
}
end:
*phdr = parsed_header;
return (0);
}
/*
* Call-Info = "Call-Info" HCOLON info * (COMMA info)
* info = LAQUOT absoluteURI RAQUOT * (SEMI info-param)
* info-param = ("purpose" EQUAL ("icon" | "info" | "card" | token)) |
* generic-param
*/
int
{
}
/*
* Content-Disposition = "Content-Disposition" HCOLON disp-type *
* (SEMI disp-param)
* disp-type = "render" | "session" | "icon" | "alert" | disp-ext-token
* disp-param = handling-param | generic-param
* handling-param = "handling" EQUAL("optional" | "required" | other-handling)
* other-handling = token
* disp-ext-token = token
*
*/
int
{
}
/*
* Content-Encoding = ("Content-Encoding" | "e") HCOLON content-coding *
* (COMMA content-coding)
*/
int
{
}
/*
* Content-Language = ("Content-Language" | "l") HCOLON lang-tag *
* (COMMA lang-tag)
* lang-tag = primary-tag *("-" subtag)
* prmary-tag = 1*8ALPHA
* subtag = 1*8ALPHA
*/
int
{
}
/*
* Date = "Date" HCOLON SIPdate
* SIPdate = wkday "," SP date1 SP time SP "GMT"
* date1 = 2DIGIT SP mnth SP 4DIGIT; day month year
* time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
* wkday = "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun"
* month = "Jan" | "Feb" etc
*/
int
{
int r;
return (r);
return (0);
if (parsed_header == NULL)
return (ENOMEM);
return (ENOMEM);
}
if (sip_skip_white_space(sip_header) != 0) {
return (EPROTO);
}
} else {
return (EPROTO);
}
if (sip_skip_white_space(sip_header) != 0) {
return (EPROTO);
}
return (EPROTO);
}
if (sip_skip_white_space(sip_header) != 0) {
return (EPROTO);
}
} else {
return (EPROTO);
}
return (EPROTO);
}
if (sip_skip_white_space(sip_header) != 0) {
return (EPROTO);
}
} else {
return (EPROTO);
}
/*
* minus 2 to get rid of the CRLF
*/
*header = parsed_header;
return (0);
}
/*
* Error-Info = "Error-Info" HCOLON error-uri *(COMMA error-uri)
* error-uri = LAQUOT absoluteURI RAQUOT *(SEMI generic-param)
*/
int
{
}
/*
* Expires = "Expires" HCOLON delta-seconds
*/
int
{
}
/*
* In-Reply-To = "In-Reply-To" HCOLON callid *(COMMA callid)
*/
int
{
}
/*
* RSeq = "RSeq" HCOLON response-num
*/
int
{
int r;
/*
* Additionally, a value of 0 is bad_value
*/
rseq_value = (sip_hdr_value_t *)
if (rseq_value->int_val == 0)
}
return (r);
}
/*
* Min-Expires = "Min-Expires" HCOLON delta-seconds
*/
int
{
}
/*
* MIME-Version = "MIME-Version" HCOLON 1*DIGIT "." 1*DIGIT
*/
int
{
}
/*
* Organization = "Organization" HCOLON [TEXT-UTF8-TRIM]
*/
int
{
if (sip_is_empty_hdr(sip_header))
}
/*
* Priority = "Priority" HCOLON priority-val
* priority-val = "emergency" | "urgent" | "normal" | "non-urgent" | other
* other = token
*/
int
{
}
/*
* Reply-To = "Reply-To" HCOLON rplyto-spec
* rplyto-spec = (name-addr | addr-spec) *(SEMI rplyto-param)
* rplyto-param = generic-param
* name-addr = [ display-name ] LAQUOT addr-spec RAQUOT
* addr-spec = SIP-URI | SIPS-URI | absolute URI
*/
int
{
B_TRUE));
}
/*
* PRIVACY = "Privacy" HCOLON priv-value *(COMMA priv-value)
* priv-value = "header" / "session" / "user" / "none" / "critical"
* / token / id
*/
int
{
}
/*
* Require = "Require" HCOLON option-tag * (COMMA option-tag)
*/
int
{
}
/*
* Retry-After = "Retry-After" HCOLON delta-seconds [ comment ] *
* (SEMI retry-param)
* retry-param = "duration" EQUAL delta-seconds
*/
int
{
int ret;
return (ret);
return (0);
if (parsed_header == NULL)
return (ENOMEM);
return (ENOMEM);
}
if (ret != 0)
(void) sip_parse_params(sip_header,
&(value->sip_param_list));
}
} else {
return (EPROTO);
}
} else {
value->intstr_str_len = 0;
/*
* from value start, search if parameter list
*/
(void) sip_parse_params(sip_header,
&(value->sip_param_list));
}
}
*header = parsed_header;
return (0);
}
/*
* Server = "Server" HCOLON servel-val *(LWS server-val)
* servel-val = product|comment
* product = token [SLASH version]
* version = token
* Treated as one single string
*/
int
{
}
/*
* Subject = ("Subject" | "s")HCOLON [TEXT-UTF8-TRIM]
*/
int
{
if (sip_is_empty_hdr(sip_header))
}
/*
* Supported = ("Supported" | "k") HCOLON [option-tag * (COMMA option-tag) ]
*/
int
{
if (sip_is_empty_hdr(sip_header))
}
/*
* Timestamp = "Timestamp" HCOLON 1*DIGIT ["." *(DIGIT)] [LWS delay]
*/
int
{
int ret;
return (ret);
return (0);
if (parsed_header == NULL)
return (ENOMEM);
return (ENOMEM);
}
if (sip_skip_white_space(sip_header) != 0) {
return (EPROTO);
}
if (sip_find_white_space(sip_header) == 0) {
/*
* timestamp and delay, timestamp in str1, delay in str2
*/
(void) sip_skip_white_space(sip_header);
if (sip_find_cr(sip_header) != 0) {
return (EPROTO);
}
value->strs2_val_len = 0;
} else {
}
} else {
/*
* no delay information
*/
- value->strs1_val_ptr;
value->strs2_val_len = 0;
}
*header = parsed_header;
return (0);
}
/*
* Unsupported = "Unsupported" HCOLON option-tag * (COMMA option-tag)
*/
int
{
}
/*
* User-Agent = "User-Agent" HCOLON server-val * (LWS server-val)
* servel-val = product |comment
* product = token [SLASH version]
* version = token
*/
int
{
}
/*
* Warning = "Warning" HCOLON warning-value *(COMMA warning-value)
* warning-value = warn-code SP warn-agent SP warn-text
* warn-code = 3DIGIT
* warn-agent = hostport | pseudonym ;
* the name or pseudonym of the server adding;
* the Warning header, for use in debugging
* warn-text = quoted-string
* pseudonym = token
*/
int
{
int ret;
return (ret);
return (0);
if (parsed_header == NULL)
return (ENOMEM);
return (ENOMEM);
}
if (last_value != NULL)
else
goto get_next_val;
}
if (sip_skip_white_space(sip_header) != 0) {
goto get_next_val;
}
/*
* get warning agent
*/
(void) sip_reverse_skip_white_space(sip_header);
if (value->warn_agt_len <= 0) {
}
/*
* We will have a SIP_QUOTE here
*/
} else {
goto get_next_val;
}
} else
/*
* warning text must present
*/
break;
last_value = value;
(void) sip_skip_white_space(sip_header);
}
*header = parsed_header;
return (0);
}
/*
* Parse RAck header
* "RAck" HCOLON response-num LWS CSeq-num LWS Method
* response-num = 1*DIGIT
* CSeq-num = 1*DIGIT
*/
int
{
int len;
char *tmp_ptr;
int i;
int ret;
return (ret);
return (0);
if (parsed_header == NULL)
return (ENOMEM);
return (ENOMEM);
}
rack_value->rack_resp == 0) {
goto rack_parse_done;
}
/*
* Get cseq.
*/
if (sip_skip_white_space(sip_header) != 0) {
goto rack_parse_done;
}
goto rack_parse_done;
}
/*
* Get method.
*/
if (sip_skip_white_space(sip_header) != 0) {
goto rack_parse_done;
}
if (sip_find_white_space(sip_header)) {
goto rack_parse_done;
}
for (i = 1; i < MAX_SIP_METHODS; i++) {
break;
}
if (i >= MAX_SIP_METHODS) {
goto rack_parse_done;
}
rack_value->rack_method = i;
*header = parsed_header;
return (0);
}
/*
* Allow = "Allow" HCOLON [Method *(COMMA Method)]
*/
int
{
}
/*
* Event = ( "Event" / "o" ) HCOLON event-type
* *( SEMI event-param )
* event-type = event-package *( "." event-template )
* event-package = token-nodot
* event-template = token-nodot
* token-nodot = 1*( alphanum / "-" / "!" / "%" / "*"
* / "_" / "+" / "`" / "'" / "~" )
* event-param = generic-param / ( "id" EQUAL token )
*/
int
{
}
/*
* Subscription-State = "Subscription-State" HCOLON substate-value
* *( SEMI subexp-params )
* substate-value = "active" / "pending" / "terminated"
* / extension-substate
* extension-substate = token
* subexp-params = ("reason" EQUAL event-reason-value)
* / ("expires" EQUAL delta-seconds)*
* / ("retry-after" EQUAL delta-seconds)
* / generic-param
* event-reason-value = "deactivated"
* / "probation"
* / "rejected"
* / "timeout"
* / "giveup"
* / "noresource"
* / event-reason-extension
* event-reason-extension = token
*/
int
{
}
/*
* Authorization = "Authorization" HCOLON credentials
* credentials = ("Digest" LWS digest-response)
* / other-response
* digest-response = dig-resp *(COMMA dig-resp)
* dig-resp = username / realm / nonce / digest-uri
* / dresponse / algorithm / cnonce
* / opaque / message-qop
* / nonce-count / auth-param
* username = "username" EQUAL username-value
* username-value = quoted-string
* digest-uri = "uri" EQUAL LDQUOT digest-uri-value RDQUOT
* digest-uri-value = rquest-uri ; Equal to request-uri as specified
* by HTTP/1.1
* message-qop = "qop" EQUAL qop-value
* cnonce = "cnonce" EQUAL cnonce-value
* cnonce-value = nonce-value
* nonce-count = "nc" EQUAL nc-value
* nc-value = 8LHEX
* dresponse = "response" EQUAL request-digest
* request-digest = LDQUOT 32LHEX RDQUOT
* auth-param = auth-param-name EQUAL
* ( token / quoted-string )
* auth-param-name = token
* other-response = auth-scheme LWS auth-param
* *(COMMA auth-param)
* auth-scheme = token
*/
int
{
}
/*
* Authentication-Info = "Authentication-Info" HCOLON ainfo
* *(COMMA ainfo)
* ainfo = nextnonce / message-qop
* / response-auth / cnonce
* / nonce-count
* nextnonce = "nextnonce" EQUAL nonce-value
* response-auth = "rspauth" EQUAL response-digest
* response-digest = LDQUOT *LHEX RDQUOT
*
*/
int
{
}
/*
* Proxy-Authenticate = "Proxy-Authenticate" HCOLON challenge
* challenge = ("Digest" LWS digest-cln *(COMMA digest-cln))
* / other-challenge
* other-challenge = auth-scheme LWS auth-param
* *(COMMA auth-param)
* digest-cln = realm / domain / nonce
* / opaque / stale / algorithm
* / qop-options / auth-param
* realm = "realm" EQUAL realm-value
* realm-value = quoted-string
* domain = "domain" EQUAL LDQUOT URI
* *( 1*SP URI ) RDQUOT
* URI = absoluteURI / abs-path
* nonce = "nonce" EQUAL nonce-value
* nonce-value = quoted-string
* opaque = "opaque" EQUAL quoted-string
* stale = "stale" EQUAL ( "true" / "false" )
* algorithm = "algorithm" EQUAL ( "MD5" / "MD5-sess"
* / token )
* qop-options = "qop" EQUAL LDQUOT qop-value
* *("," qop-value) RDQUOT
* qop-value = "auth" / "auth-int" / token
*
*/
int
{
}
/*
* Proxy-Authorization = "Proxy-Authorization" HCOLON credentials
*/
int
{
}
/*
* Proxy-Require = "Proxy-Require" HCOLON option-tag
* *(COMMA option-tag)
* option-tag = token
*/
int
{
}
/*
* WWW-Authenticate = "WWW-Authenticate" HCOLON challenge
* extension-header = header-name HCOLON header-value
* header-name = token
* header-value = *(TEXT-UTF8char / UTF8-CONT / LWS)
* message-body = *OCTET
*
*/
int
{
}
/*
* Call-ID = ( "Call-ID" / "i" ) HCOLON callid
*/
int
{
}
/*
* CSeq = "CSeq" HCOLON 1*DIGIT LWS Method
*/
int
{
int len;
char *tmp_ptr;
int i;
int ret;
return (ret);
return (0);
if (parsed_header == NULL)
return (ENOMEM);
return (ENOMEM);
}
goto cseq_parse_done;
}
/*
* Get method.
*/
if (sip_skip_white_space(sip_header) != 0) {
goto cseq_parse_done;
}
if (sip_find_white_space(sip_header)) {
goto cseq_parse_done;
}
for (i = 1; i < MAX_SIP_METHODS; i++) {
break;
}
if (i >= MAX_SIP_METHODS) {
goto cseq_parse_done;
}
cseq_value->cseq_method = i;
*header = parsed_header;
return (0);
}
/*
* Via = ( "Via" / "v" ) HCOLON via-parm *(COMMA via-parm)
* via-parm = sent-protocol LWS sent-by *( SEMI via-params )
* via-params = via-ttl / via-maddr
* / via-received / via-branch
* / via-extension
* via-ttl = "ttl" EQUAL ttl
* via-maddr = "maddr" EQUAL host
* via-received = "received" EQUAL (IPv4address / IPv6address)
* via-branch = "branch" EQUAL token
* via-extension = generic-param
* sent-protocol = protocol-name SLASH protocol-version
* SLASH transport
* protocol-name = "SIP" / token
* protocol-version = token
* transport = "UDP" / "TCP" / "TLS" / "SCTP"
* / other-transport
* sent-by = host [ COLON port ]
* ttl = 1*3DIGIT ; 0 to 255
*
* There can be multiple via headers we always append the header.
*/
int
{
int ret;
return (ret);
return (0);
if (parsed_header == NULL)
return (ENOMEM);
return (ENOMEM);
}
if (last_value != NULL)
else
/*
* Check to see if there is a version number
*/
&value->via_protocol) != 0) {
if (sip_goto_next_value(sip_header) != 0) {
return (EPROTO);
}
goto get_next_via_value;
}
if (sip_goto_next_value(sip_header) != 0) {
return (EPROTO);
}
goto get_next_via_value;
}
if (sip_skip_white_space(sip_header) != 0) {
if (sip_goto_next_value(sip_header) != 0) {
return (EPROTO);
}
goto get_next_via_value;
}
if (sip_find_white_space(sip_header) != 0) {
if (sip_goto_next_value(sip_header) != 0) {
return (EPROTO);
}
goto get_next_via_value;
}
if (sip_skip_white_space(sip_header) != 0) {
if (sip_goto_next_value(sip_header) != 0) {
return (EPROTO);
}
goto get_next_via_value;
}
if (sip_goto_next_value(sip_header) != 0) {
return (EPROTO);
}
goto get_next_via_value;
}
SIP_HCOLON, B_FALSE)) {
if (sip_goto_next_value(sip_header) != 0) {
return (EPROTO);
}
goto get_next_via_value;
}
if (sip_skip_white_space(sip_header) != 0) {
if (sip_goto_next_value(sip_header) != 0) {
return (EPROTO);
}
goto get_next_via_value;
}
/*
* We have a port number
*/
0) {
if (sip_goto_next_value(sip_header) != 0) {
return (EPROTO);
}
goto get_next_via_value;
}
}
/*
* Do some sanity checking.
*/
if (sip_goto_next_value(sip_header) != 0) {
return (EPROTO);
}
goto get_next_via_value;
}
} else if (ret != 0) {
return (ret);
}
break;
last_value = value;
(void) sip_skip_white_space(sip_header);
}
*header = parsed_header;
return (0);
}
/*
* Max-Forwards = "Max-Forwards" HCOLON 1*DIGIT
*/
int
{
}
/*
* Content-Type = ( "Content-Type" / "c" ) HCOLON media-type
* media-type = m-type SLASH m-subtype *(SEMI m-parameter)
* m-type = discrete-type / composite-type
* discrete-type = "text" / "image" / "audio" / "video"
* / "application" / extension-token
* composite-type = "message" / "multipart" / extension-token
* extension-token = ietf-token / x-token
* ietf-token = token
* x-token = "x-" token
* m-subtype = extension-token / iana-token
* iana-token = token
* m-parameter = m-attribute EQUAL m-value
* m-attribute = token
* m-value = token / quoted-string
*/
int
{
}
/*
* Content-Length = ( "Content-Length" / "l" ) HCOLON 1*DIGIT
*/
int
{
}
/*
* Generic parser for Contact, From, To, Route and Record-Route headers
*
* Contact = ("Contact" / "m" ) HCOLON
* ( STAR / (contact-param *(COMMA contact-param)))
* contact-param = (name-addr / addr-spec) *(SEMI contact-params)
* name-addr = [ display-name ] LAQUOT addr-spec RAQUOT
* addr-spec = SIP-URI / SIPS-URI / absoluteURI
* display-name = *(token LWS)/ quoted-string
* contact-params = c-p-q / c-p-expires
* / contact-extension
*
* From = ( "From" / "f" ) HCOLON from-spec
* from-spec = ( name-addr / addr-spec )
* *( SEMI from-param )
* from-param = tag-param / generic-param
* tag-param = "tag" EQUAL token
*
* To = ( "To" / "t" ) HCOLON ( name-addr
* / addr-spec ) *( SEMI to-param )
* to-param = tag-param / generic-param
*
* Route = "Route" HCOLON route-param *(COMMA route-param)
* route-param = name-addr *( SEMI rr-param )
*
* Record-Route = "Record-Route" HCOLON rec-route *(COMMA rec-route)
* rec-route = name-addr *( SEMI rr-param )
* rr-param = generic-param
*
* We could have multiple values for these headers. For the ones that have
* when parsing a value, we mark the value as bad and start paring the
* next value, if present. Before we start parsing the next value, we
* check for any parameters, if present.
*/
int
{
char *tmp_ptr;
char *tmp_ptr_2;
int ret;
return (ret);
return (0);
if (parsed_header == NULL)
return (ENOMEM);
return (ENOMEM);
}
if (last_value != NULL)
else
}
/*
* let's see if there is a display name
*/
/*
* According to 20.10 '<' may not have a leading
* space.
*/
if (quoted_name &&
if (sip_goto_next_value(sip_header) != 0) {
return (EPROTO);
}
goto get_next_cftr_value;
/*
* only a uri.
*/
/*
* It's an error not to have a uri.
*/
if (sip_goto_next_value(sip_header) !=
0) {
return (EPROTO);
}
goto get_next_cftr_value;
}
goto get_next_cftr_value;
}
/*
* This is needed to get rid of leading white spaces of
* display name or uri
*/
(void) sip_reverse_skip_white_space(sip_header);
if (sip_skip_white_space(sip_header) != 0) {
/*
* only a uri.
*/
/*
* It's an error not to have a uri.
*/
if (sip_goto_next_value(
sip_header) != 0) {
return (EPROTO);
}
goto get_next_cftr_value;
}
goto get_next_cftr_value;
}
}
/*
* No display name here.
*/
/*
* It's an error not to have a uri.
*/
if (sip_goto_next_value(sip_header) !=
0) {
return (EPROTO);
}
goto get_next_cftr_value;
}
goto get_params;
}
return (ENOMEM);
}
if (quoted_name)
}
if (sip_goto_next_value(sip_header) != 0) {
return (EPROTO);
}
goto get_next_cftr_value;
}
if (sip_skip_white_space(sip_header) != 0) {
if (sip_goto_next_value(sip_header) != 0) {
return (EPROTO);
}
goto get_next_cftr_value;
}
}
if (sip_goto_next_value(sip_header) != 0) {
return (EPROTO);
}
goto get_next_cftr_value;
}
if (sip_goto_next_value(sip_header) != 0) {
return (EINVAL);
}
goto get_next_cftr_value;
}
if (sip_goto_next_value(sip_header) != 0) {
return (EPROTO);
}
goto get_next_cftr_value;
}
} else if (ret != 0) {
return (ret);
}
/*
* Parse uri
*/
int error;
return (ENOMEM);
}
if (error != 0 || uri_errflags != 0) {
sip_header_functions->header_name) == 0) &&
sip_req_method == REGISTER) {
error = 0;
((_sip_uri_t *)value->
sip_uri_errflags = 0;
} else {
}
} else {
}
}
}
last_value = value;
(void) sip_skip_white_space(sip_header);
}
*header = parsed_header;
return (0);
}
/*
* PAssertedID = "P-Asserted-Identity" HCOLON PAssertedID-value
* *(COMMA PAssertedID-value)
* PAssertedID-value = name-addr / addr-spec
*/
int
{
B_TRUE));
}
/*
* PPreferredID = "P-Preferred-Identity" HCOLON PPreferredID-value
* *(COMMA PAssertedID-value)
* PPreferredID-value = name-addr / addr-spec
*/
int
{
B_TRUE));
}
/*
* We don't do anything for a header we don't understand
*/
/* ARGSUSED */
int
{
return (EINVAL);
}