/*******************************************************************************

  Eurecom OpenAirInterface
  Copyright(c) 1999 - 2013 Eurecom

  This program is free software; you can redistribute it and/or modify it
  under the terms and conditions of the GNU General Public License,
  version 2, as published by the Free Software Foundation.

  This program is distributed in the hope it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  more details.

  You should have received a copy of the GNU General Public License along with
  this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.

  The full GNU General Public License is included in this distribution in
  the file called "COPYING".

  Contact Information
  Openair Admin: openair_admin@eurecom.fr
  Openair Tech : openair_tech@eurecom.fr
  Forums       : http://forums.eurecom.fr/openairinterface
  Address      : EURECOM, Campus SophiaTech, 450 Route des Chappes
                 06410 Biot FRANCE

*******************************************************************************/

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include <freeDiameter/freeDiameter-host.h>
#include <freeDiameter/libfdcore.h>

#include "mme_config.h"
#include "queue.h"

#ifndef S6A_DEFS_H_
#define S6A_DEFS_H_

#ifndef S6A_DEBUG
# define S6A_DEBUG(x, args...) do { fprintf(stdout, "[S6A] [D]"x, ##args); } while(0)
#endif
#ifndef S6A_ERROR
# define S6A_ERROR(x, args...) do { fprintf(stderr, "[S6A] [E]"x, ##args); } while(0)
#endif

#define VENDOR_3GPP (10415)
#define APP_S6A     (16777251)

/* Errors that fall within the Permanent Failures category shall be used to
 * inform the peer that the request has failed, and should not be attempted
 * again. The Result-Code AVP values defined in Diameter Base Protocol RFC 3588
 * shall be applied. When one of the result codes defined here is included in a
 * response, it shall be inside an Experimental-Result AVP and the Result-Code
 * AVP shall be absent.
 */
#define DIAMETER_ERROR_USER_UNKNOWN             (5001)
#define DIAMETER_ERROR_ROAMING_NOT_ALLOWED      (5004)
#define DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION (5420)
#define DIAMETER_ERROR_RAT_NOT_ALLOWED          (5421)
#define DIAMETER_ERROR_EQUIPMENT_UNKNOWN        (5422)
#define DIAMETER_ERROR_UNKOWN_SERVING_NODE      (5423)

/* Result codes that fall within the transient failures category shall be used
 * to inform a peer that the request could not be satisfied at the time it was
 * received, but may be able to satisfy the request in the future. The
 * Result-Code AVP values defined in Diameter Base Protocol RFC 3588 shall be
 * applied. When one of the result codes defined here is included in a response,
 * it shall be inside an Experimental-Result AVP and the Result-Code AVP shall
 * be absent.
 */
#define DIAMETER_AUTHENTICATION_DATA_UNAVAILABLE (4181)

#define DIAMETER_ERROR_IS_VENDOR(x)                    \
   ((x == DIAMETER_ERROR_USER_UNKNOWN)              || \
    (x == DIAMETER_ERROR_ROAMING_NOT_ALLOWED)       || \
    (x == DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION)  || \
    (x == DIAMETER_ERROR_RAT_NOT_ALLOWED)           || \
    (x == DIAMETER_ERROR_EQUIPMENT_UNKNOWN)         || \
    (x == DIAMETER_AUTHENTICATION_DATA_UNAVAILABLE) || \
    (x == DIAMETER_ERROR_UNKOWN_SERVING_NODE))

typedef struct {
    struct dict_object *dataobj_s6a_vendor;     /* s6a vendor object */
    struct dict_object *dataobj_s6a_app;        /* s6a application object */

    /* Commands */
    struct dict_object *dataobj_s6a_air; /* s6a authentication request */
    struct dict_object *dataobj_s6a_aia; /* s6a authentication answer */
    struct dict_object *dataobj_s6a_ulr; /* s6a update location request */
    struct dict_object *dataobj_s6a_ula; /* s6a update location asnwer */
    struct dict_object *dataobj_s6a_pur; /* s6a purge ue request */
    struct dict_object *dataobj_s6a_pua; /* s6a purge ue answer */
    struct dict_object *dataobj_s6a_clr; /* s6a Cancel Location req */
    struct dict_object *dataobj_s6a_cla; /* s6a Cancel Location ans */

    /* Some standard basic AVPs */
    struct dict_object *dataobj_s6a_destination_host;
    struct dict_object *dataobj_s6a_destination_realm;
    struct dict_object *dataobj_s6a_user_name;
    struct dict_object *dataobj_s6a_session_id;
    struct dict_object *dataobj_s6a_auth_session_state;
    struct dict_object *dataobj_s6a_result_code;
    struct dict_object *dataobj_s6a_experimental_result;

    /* S6A specific AVPs */
    struct dict_object *dataobj_s6a_visited_plmn_id;
    struct dict_object *dataobj_s6a_rat_type;
    struct dict_object *dataobj_s6a_ulr_flags;
    struct dict_object *dataobj_s6a_ula_flags;
    struct dict_object *dataobj_s6a_subscription_data;
    struct dict_object *dataobj_s6a_req_eutran_auth_info;
    struct dict_object *dataobj_s6a_number_of_requested_vectors;
    struct dict_object *dataobj_s6a_immediate_response_pref;
    struct dict_object *dataobj_s6a_authentication_info;
    struct dict_object *dataobj_s6a_ue_srvcc_cap;

    /* Handlers */
    struct disp_hdl *aia_hdl;   /* Authentication Information Answer Handle */
    struct disp_hdl *ula_hdl;   /* Update Location Answer Handle */
    struct disp_hdl *pua_hdl;   /* Purge UE Answer Handle */
    struct disp_hdl *clr_hdl;   /* Cancel Location Request Handle */
} s6a_fd_cnf_t;

extern s6a_fd_cnf_t s6a_fd_cnf;

#define ULR_SINGLE_REGISTRATION_IND      (1U)
#define ULR_S6A_S6D_INDICATOR            (1U << 1)
#define ULR_SKIP_SUBSCRIBER_DATA         (1U << 2)
#define ULR_GPRS_SUBSCRIPTION_DATA_IND   (1U << 3)
#define ULR_NODE_TYPE_IND                (1U << 4)
#define ULR_INITIAL_ATTACH_IND           (1U << 5)
#define ULR_PS_LCS_SUPPORTED_BY_UE       (1U << 6)

#define ULA_SEPARATION_IND          (1U)

#define FLAG_IS_SET(x, flag)   \
    ((x) & (flag))

#define FLAGS_SET(x, flags) \
    ((x) |= (flags))

#define FLAGS_CLEAR(x, flags)   \
    ((x) = (x) & ~(flags))

/* IANA defined IP address type */
#define IANA_IPV4   (0x1)
#define IANA_IPV6   (0x2)

#define AVP_CODE_VENDOR_ID                         (266)
#define AVP_CODE_EXPERIMENTAL_RESULT               (297)
#define AVP_CODE_EXPERIMENTAL_RESULT_CODE          (298)
#define AVP_CODE_SERVICE_SELECTION                 (493)
#define AVP_CODE_BANDWIDTH_UL                      (516)
#define AVP_CODE_BANDWIDTH_DL                      (515)
#define AVP_CODE_MSISDN                            (701)
#define AVP_CODE_SERVED_PARTY_IP_ADDRESS           (848)
#define AVP_CODE_QCI                               (1028)
#define AVP_CODE_ALLOCATION_RETENTION_PRIORITY     (1034)
#define AVP_CODE_PRIORITY_LEVEL                    (1046)
#define AVP_CODE_PRE_EMPTION_CAPABILITY            (1047)
#define AVP_CODE_PRE_EMPTION_VULNERABILITY         (1048)
#define AVP_CODE_SUBSCRIPTION_DATA                 (1400)
#define AVP_CODE_AUTHENTICATION_INFO               (1413)
#define AVP_CODE_E_UTRAN_VECTOR                    (1414)
#define AVP_CODE_NETWORK_ACCESS_MODE               (1417)
#define AVP_CODE_CONTEXT_IDENTIFIER                (1423)
#define AVP_CODE_SUBSCRIBER_STATUS                 (1424)
#define AVP_CODE_ACCESS_RESTRICTION_DATA           (1426)
#define AVP_CODE_ALL_APN_CONFIG_INC_IND            (1428)
#define AVP_CODE_APN_CONFIGURATION_PROFILE         (1429)
#define AVP_CODE_APN_CONFIGURATION                 (1430)
#define AVP_CODE_EPS_SUBSCRIBED_QOS_PROFILE        (1431)
#define AVP_CODE_AMBR                              (1435)
#define AVP_CODE_RAND                              (1447)
#define AVP_CODE_XRES                              (1448)
#define AVP_CODE_AUTN                              (1449)
#define AVP_CODE_KASME                             (1450)
#define AVP_CODE_PDN_TYPE                          (1456)
#define AVP_CODE_SUBSCRIBED_PERIODIC_RAU_TAU_TIMER (1619)

int s6a_init(const mme_config_t *mme_config);

int s6a_fd_new_peer(void);

void s6a_peer_connected_cb(struct peer_info *info, void *arg);

int s6a_fd_init_dict_objs(void);

int s6a_parse_subscription_data(struct avp *avp_subscription_data,
                                subscription_data_t *subscription_data);

int s6a_parse_experimental_result(struct avp *avp, s6a_experimental_result_t *ptr);
inline char *experimental_retcode_2_string(uint32_t ret_code);
inline char *retcode_2_string(uint32_t ret_code);

#endif /* S6A_DEFS_H_ */
