/* $Id: pcp_msg_struct.h,v 1.3 2013/12/16 16:02:19 nanard Exp $ */
/* MiniUPnP project
 * Website : http://miniupnp.free.fr/
 * Author : Peter Tatrai

Copyright (c) 2013 by Cisco Systems, Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * The name of the author may not be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
 */

#define PCP_OPCODE_ANNOUNCE   0
#define PCP_OPCODE_MAP        1
#define PCP_OPCODE_PEER       2
#ifdef  PCP_SADSCP
#define PCP_OPCODE_SADSCP     3
#endif

/* Possible response codes sent by server, as a result of client request*/
#define PCP_SUCCESS                     0

#define PCP_ERR_UNSUPP_VERSION          1
/** The version number at the start of the PCP Request
 * header is not recognized by this PCP server.  This is a long
 * lifetime error.  This document describes PCP version 2.
 */

#define PCP_ERR_NOT_AUTHORIZED          2
/**The requested operation is disabled for this PCP
 * client, or the PCP client requested an operation that cannot be
 * fulfilled by the PCP server's security policy.  This is a long
 * lifetime error.
 */

#define PCP_ERR_MALFORMED_REQUEST       3
/**The request could not be successfully parsed.
 * This is a long lifetime error.
 */

#define PCP_ERR_UNSUPP_OPCODE           4
/** Unsupported Opcode.  This is a long lifetime error.
 */

#define PCP_ERR_UNSUPP_OPTION           5
/**Unsupported Option.  This error only occurs if the
 * Option is in the mandatory-to-process range.  This is a long
 * lifetime error.
 */

#define PCP_ERR_MALFORMED_OPTION        6
/**Malformed Option (e.g., appears too many times,
 * invalid length).  This is a long lifetime error.
 */

#define PCP_ERR_NETWORK_FAILURE         7
/**The PCP server or the device it controls are
 * experiencing a network failure of some sort (e.g., has not
 * obtained an External IP address).  This is a short lifetime error.
 */

#define PCP_ERR_NO_RESOURCES            8
/**Request is well-formed and valid, but the server has
 * insufficient resources to complete the requested operation at this
 * time.  For example, the NAT device cannot create more mappings at
 * this time, is short of CPU cycles or memory, or is unable to
 * handle the request due to some other temporary condition.  The
 * same request may succeed in the future.  This is a system-wide
 * error, different from USER_EX_QUOTA.  This can be used as a catch-
 * all error, should no other error message be suitable.  This is a
 * short lifetime error.
 */

#define PCP_ERR_UNSUPP_PROTOCOL         9
/**Unsupported transport protocol, e.g.  SCTP in a
 * NAT that handles only UDP and TCP.  This is a long lifetime error.
 */

#define PCP_ERR_USER_EX_QUOTA           10
/** This attempt to create a new mapping would exceed
 * this subscriber's port quota.  This is a short lifetime error.
 */

#define PCP_ERR_CANNOT_PROVIDE_EXTERNAL 11
/** The suggested external port and/or
 * external address cannot be provided.  This error MUST only be
 * returned for:
 *      *  MAP requests that included the PREFER_FAILURE Option
 *          (normal MAP requests will return an available external port)
 *      *  MAP requests for the SCTP protocol (PREFER_FAILURE is implied)
 *      *  PEER requests
 */

#define PCP_ERR_ADDRESS_MISMATCH        12
/** The source IP address of the request packet does
 * not match the contents of the PCP Client's IP Address field, due
 * to an unexpected NAT on the path between the PCP client and the
 * PCP-controlled NAT or firewall.  This is a long lifetime error.
 */

#define PCP_ERR_EXCESSIVE_REMOTE_PEERS  13
/** The PCP server was not able to create the
 * filters in this request.  This result code MUST only be returned
 * if the MAP request contained the FILTER Option.  See Section 13.3
 * for processing information.  This is a long lifetime error.
 */

typedef enum pcp_options  {
    PCP_OPTION_3RD_PARTY = 1,
    PCP_OPTION_PREF_FAIL = 2,
    PCP_OPTION_FILTER = 3,
#ifdef PCP_FLOWP
    PCP_OPTION_FLOW_PRIORITY = 4,  /*TODO: change it to correct value*/
#endif
} pcp_options_t;


#ifdef _WIN32
#pragma warning (push)
#pragma warning (disable:4200)
#endif /* _WIN32 */

#pragma pack(push, 1)

/* PCP common request header*/
typedef struct pcp_request {
  uint8_t     ver;
  uint8_t     r_opcode;
  uint16_t    reserved;
  uint32_t    req_lifetime;
  struct in6_addr    ip; /* ipv4 will be represented
                        by the ipv4 mapped ipv6 */
  uint8_t     next_data[0];
} pcp_request_t;

/* PCP common response header*/
typedef struct pcp_response {
  uint8_t     ver;
  uint8_t     r_opcode;    /* R indicates Request (0) or Response (1)
                              Opcode is 7 bit value specifying operation MAP or PEER */
  uint8_t     reserved;    /* reserved bits, must be 0 on transmission and must be ignored on reception */
  uint8_t     result_code; /*  */
  uint32_t    lifetime;    /* an unsigned 32-bit integer, in seconds {0, 2^32-1}*/
  uint32_t    epochtime;   /* epoch indicates how long has PCP server had its current mappings
                              it increases by 1 every second */
  uint32_t    reserved1[3];/* For requests that were successfully parsed this must be sent as 0 */
  uint8_t     next_data[0];
} pcp_response_t;


typedef struct pcp_options_hdr {
  uint8_t     code;             /* Most significant bit indicates if this option is mandatory (0) or optional (1) */
  uint8_t     reserved;         /* MUST be set to 0 on transmission and MUST be ignored on reception */
  uint16_t    len;              /* indicates the length of the enclosed data in octets (see RFC) */
  uint8_t     next_data[0];     /* */
} pcp_options_hdr_t;

/* same for both request and response */
typedef struct pcp_map_v2 {
  uint32_t    nonce[3];
  uint8_t     protocol;   /* 6 = TCP, 17 = UDP, 0 = 'all protocols' */
  uint8_t     reserved[3];
  uint16_t    int_port;   /* 0 indicates 'all ports' */
  uint16_t    ext_port;   /* suggested external port */
  struct in6_addr ext_ip; /* suggested external IP address
      * ipv4 will be represented by the ipv4 mapped ipv6 */
  uint8_t     next_data[0];
} pcp_map_v2_t;

/* same for both request and response */
typedef struct pcp_map_v1 {
  uint8_t     protocol;
  uint8_t     reserved[3];
  uint16_t    int_port;
  uint16_t    ext_port;
  struct in6_addr ext_ip; /* ipv4 will be represented
                            by the ipv4 mapped ipv6 */
  uint8_t     next_data[0];
} pcp_map_v1_t;

/* same for both request and response */
typedef struct pcp_peer_v1 {
  uint8_t     protocol;
  uint8_t     reserved[3];
  uint16_t    int_port;
  uint16_t    ext_port;
  struct in6_addr ext_ip; /* ipv4 will be represented
                            by the ipv4 mapped ipv6 */
  uint16_t    peer_port;
  uint16_t    reserved1;
  struct in6_addr peer_ip;
  uint8_t     next_data[0];
} pcp_peer_v1_t;

/* same for both request and response */
typedef struct pcp_peer_v2 {
  uint32_t    nonce[3];
  uint8_t     protocol;
  uint8_t     reserved[3];
  uint16_t    int_port;
  uint16_t    ext_port;
  struct in6_addr ext_ip; /* ipv4 will be represented
                            by the ipv4 mapped ipv6 */
  uint16_t    peer_port;
  uint16_t    reserved1;
  struct in6_addr peer_ip;
  uint8_t     next_data[0];
} pcp_peer_v2_t;

#ifdef PCP_SADSCP
typedef struct pcp_sadscp_req {
    uint32_t  nonce[3];
    uint8_t   tolerance_fields;
    uint8_t   app_name_length;
    char      app_name[0];
}  pcp_sadscp_req_t;

typedef struct pcp_sadscp_resp {
    uint32_t  nonce[3];
#define PCP_SADSCP_MASK ((1<<6)-1)
    uint8_t   a_r_dscp_value;
    uint8_t   reserved[3];
}  pcp_sadscp_resp_t;
#endif

typedef struct pcp_prefer_fail_option {
   uint8_t   option;
   uint8_t   reserved;
   uint16_t  len;
   uint8_t   next_data[0];
} pcp_prefer_fail_option_t;

typedef struct pcp_3rd_party_option{
   uint8_t  option;
   uint8_t  reserved;
   uint16_t len;
   struct in6_addr ip;
   uint8_t  next_data[0];
} pcp_3rd_party_option_t;

#ifdef PCP_FLOWP
typedef struct pcp_flow_priority_option{
   uint8_t  option;
   uint8_t  reserved;
   uint16_t len;
   uint8_t  dscp_up;
   uint8_t  dscp_down;
#define PCP_DSCP_MASK ((1<<6)-1)
   uint8_t  reserved2;
   /* most significant bit is used for response */
   uint8_t  response_bit;
   uint8_t  next_data[0];
} pcp_flow_priority_option_t;
#endif

typedef struct pcp_filter_option {
    uint8_t  option;
    uint8_t  reserved1;
    uint16_t len;
    uint8_t  reserved2;
    uint8_t  prefix_len;
    uint16_t peer_port;
    struct in6_addr peer_ip;
}pcp_filter_option_t;

#pragma pack(pop)

#ifdef _WIN32
#pragma warning (pop)
#endif /* _WIN32 */