/*******************************************************************************
    OpenAirInterface
    Copyright(c) 1999 - 2014 Eurecom

    OpenAirInterface is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.


    OpenAirInterface is distributed in the hope that 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 OpenAirInterface.The full GNU General Public License is
   included in this distribution in the file called "COPYING". If not,
   see <http://www.gnu.org/licenses/>.

  Contact Information
  OpenAirInterface Admin: openair_admin@eurecom.fr
  OpenAirInterface Tech : openair_tech@eurecom.fr
  OpenAirInterface Dev  : openair4g-devel@eurecom.fr

  Address      : Eurecom, Compus SophiaTech 450, route des chappes, 06451 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_re_synchronization_info;
  struct dict_object *dataobj_s6a_service_selection;
  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);
char *experimental_retcode_2_string(uint32_t ret_code);
char *retcode_2_string(uint32_t ret_code);


#endif /* S6A_DEFS_H_ */
