/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */

/*! \file 3gpp_129.244.h
 \brief
 \author Lionel Gauthier
 \company Eurecom
 \email: lionel.gauthier@eurecom.fr
 */

#ifndef FILE_3GPP_129_244_H_SEEN
#define FILE_3GPP_129_244_H_SEEN
#include "3gpp_29.274.h"
#include "common_root_types.h"
#include "conversions.hpp"
#include "logger.hpp" // for fmt::format in spdlog

#include <arpa/inet.h>
#include <stdint.h>
#include <string>
#include <vector>

namespace pfcp {

struct pfcp_exception : public std::exception {
  pfcp_exception() throw () {
    cause = 0;
    phrase.assign("PFCP Exception unknown cause");
  }

  pfcp_exception(int acause) throw () {
    cause = acause;
    phrase = fmt::format("PFCP Exception cause {}", cause);
  }
  const char* what() const throw () {
    return phrase.c_str();
  }
 public:
  int cause;
  std::string phrase;
};

struct pfcp_msg_bad_length_exception : public pfcp_exception {
 public:
  pfcp_msg_bad_length_exception(const uint8_t msg_type, const uint16_t hdr_size,
                                const uint16_t ie_size,
                                const uint16_t check_ie_size, const char *file,
                                const int line) throw () {
    phrase =
        fmt::format(
            "PFCP msg {} Bad Length hdr.length {}/ sum ie {} / check sum ie {} Exception {}:{}",
            msg_type, hdr_size, ie_size, check_ie_size, file, line);
  }
  pfcp_msg_bad_length_exception(std::string &aphrase) throw () {
    phrase = aphrase;
  }
  virtual ~pfcp_msg_bad_length_exception() throw () {
  }
};

struct pfcp_msg_unimplemented_ie_exception : public pfcp_exception {
 public:
  pfcp_msg_unimplemented_ie_exception(const uint8_t msg_type,
                                      const uint16_t ie_type,
                                      const uint8_t instance = 0) throw () {
    phrase = fmt::format(
        "PFCP msg {} Unimplemented {} IE Instance {} Exception", msg_type,
        ie_type, instance);
  }
  pfcp_msg_unimplemented_ie_exception(std::string &aphrase) throw () {
    phrase = aphrase;
  }
  virtual ~pfcp_msg_unimplemented_ie_exception() throw () {
  }
};

struct pfcp_msg_illegal_ie_exception : public pfcp_exception {
 public:
  pfcp_msg_illegal_ie_exception(const uint8_t msg_type, const uint16_t ie_type,
                                const char *file, const int line) throw () {
    phrase = fmt::format("PFCP msg {} Illegal IE {} Exception {}:{}", msg_type,
                         ie_type, file, line);
  }
  pfcp_msg_illegal_ie_exception(std::string &aphrase) throw () {
    phrase = aphrase;
  }
  virtual ~pfcp_msg_illegal_ie_exception() throw () {
  }
};

struct pfcp_ie_exception : public pfcp_exception {
 public:
  pfcp_ie_exception(uint16_t ie_type) throw () {
    phrase = fmt::format("PFCP IE {} Exception", ie_type);
  }
  pfcp_ie_exception(std::string &aphrase) throw () {
    phrase = aphrase;
  }
  virtual ~pfcp_ie_exception() throw () {
  }
};

struct pfcp_ie_unimplemented_exception : public pfcp_ie_exception {
 public:
  pfcp_ie_unimplemented_exception(uint16_t ie_type) throw ()
      :
      pfcp_ie_exception(ie_type) {
    phrase = fmt::format("PFCP IE {} Unimplemented Exception", ie_type);
  }
  virtual ~pfcp_ie_unimplemented_exception() throw () {
  }
};

struct pfcp_tlv_exception : public pfcp_ie_exception {
 public:
  pfcp_tlv_exception(uint16_t ie_type) throw ()
      :
      pfcp_ie_exception(ie_type) {
    phrase = fmt::format("PFCP IE TLV {} Exception", ie_type);
  }
  virtual ~pfcp_tlv_exception() throw () {
  }
};

struct pfcp_tlv_bad_length_exception : public pfcp_tlv_exception {
 public:
  pfcp_tlv_bad_length_exception(uint16_t ie_type, uint16_t ie_length,
                                const char *file, const int line) throw ()
      :
      pfcp_tlv_exception(ie_type) {
    phrase = fmt::format("PFCP IE TLV {} Bad Length {} Exception {}:{}",
                         ie_type, ie_length, file, line);
  }
  virtual ~pfcp_tlv_bad_length_exception() throw () {
  }
};

struct pfcp_ie_value_exception : public pfcp_ie_exception {
 public:
  pfcp_ie_value_exception(uint16_t ie_type, const char *field) throw ()
      :
      pfcp_ie_exception(ie_type) {
    phrase = fmt::format("PFCP IE {} Bad Value of {} Exception", ie_type,
                         field);
  }
  virtual ~pfcp_ie_value_exception() throw () {
  }
};

#define PFCP_IE_CREATE_PDR                                                             (1)
#define PFCP_IE_PDI                                                                    (2)
#define PFCP_IE_CREATE_FAR                                                             (3)
#define PFCP_IE_FORWARDING_PARAMETERS                                                  (4)
#define PFCP_IE_DUPLICATING_PARAMETERS                                                 (5)
#define PFCP_IE_CREATE_URR                                                             (6)
#define PFCP_IE_CREATE_QER                                                             (7)
#define PFCP_IE_CREATED_PDR                                                            (8)
#define PFCP_IE_UPDATE_PDR                                                             (9)
#define PFCP_IE_UPDATE_FAR                                                             (10)
#define PFCP_IE_UPDATE_FORWARDING_PARAMETERS                                           (11)
#define PFCP_IE_UPDATE_BAR_WITHIN_PFCP_SESSION_REPORT_RESPONSE                         (12)
#define PFCP_IE_UPDATE_URR                                                             (13)
#define PFCP_IE_UPDATE_QER                                                             (14)
#define PFCP_IE_REMOVE_PDR                                                             (15)
#define PFCP_IE_REMOVE_FAR                                                             (16)
#define PFCP_IE_REMOVE_URR                                                             (17)
#define PFCP_IE_REMOVE_QER                                                             (18)
#define PFCP_IE_CAUSE                                                                  (19)
#define PFCP_IE_SOURCE_INTERFACE                                                       (20)
#define PFCP_IE_F_TEID                                                                 (21)
#define PFCP_IE_NETWORK_INSTANCE                                                       (22)
#define PFCP_IE_SDF_FILTER                                                             (23)
#define PFCP_IE_APPLICATION_ID                                                         (24)
#define PFCP_IE_GATE_STATUS                                                            (25)
#define PFCP_IE_MBR                                                                    (26)
#define PFCP_IE_GBR                                                                    (27)
#define PFCP_IE_QER_CORRELATION_ID                                                     (28)
#define PFCP_IE_PRECEDENCE                                                             (29)
#define PFCP_IE_TRANSPORT_LEVEL_MARKING                                                (30)
#define PFCP_IE_VOLUME_THRESHOLD                                                       (31)
#define PFCP_IE_TIME_THRESHOLD                                                         (32)
#define PFCP_IE_MONITORING_TIME                                                        (33)
#define PFCP_IE_SUBSEQUENT_VOLUME_THRESHOLD                                            (34)
#define PFCP_IE_SUBSEQUENT_TIME_THRESHOLD                                              (35)
#define PFCP_IE_INACTIVITY_DETECTION_TIME                                              (36)
#define PFCP_IE_REPORTING_TRIGGERS                                                     (37)
#define PFCP_IE_REDIRECT_INFORMATION                                                   (38)
#define PFCP_IE_REPORT_TYPE                                                            (39)
#define PFCP_IE_OFFENDING_IE                                                           (40)
#define PFCP_IE_FORWARDING_POLICY                                                      (41)
#define PFCP_IE_DESTINATION_INTERFACE                                                  (42)
#define PFCP_IE_UP_FUNCTION_FEATURES                                                   (43)
#define PFCP_IE_APPLY_ACTION                                                           (44)
#define PFCP_IE_DOWNLINK_DATA_SERVICE_INFORMATION                                      (45)
#define PFCP_IE_DOWNLINK_DATA_NOTIFICATION_DELAY                                       (46)
#define PFCP_IE_DL_BUFFERING_DURATION                                                  (47)
#define PFCP_IE_DL_BUFFERING_SUGGESTED_PACKET_COUNT                                    (48)
#define PFCP_IE_PFCPSMREQ_FLAGS                                                        (49)
#define PFCP_IE_PFCPSRRSP_FLAGS                                                        (50)
#define PFCP_IE_LOAD_CONTROL_INFORMATION                                               (51)
#define PFCP_IE_SEQUENCE_NUMBER                                                        (52)
#define PFCP_IE_METRIC                                                                 (53)
#define PFCP_IE_OVERLOAD_CONTROL_INFORMATION                                           (54)
#define PFCP_IE_TIMER                                                                  (55)
#define PFCP_IE_PACKET_DETECTION_RULE_ID                                               (56)
#define PFCP_IE_F_SEID                                                                 (57)
#define PFCP_IE_APPLICATION_IDS_PFDS                                                   (58)
#define PFCP_IE_PFD                                                                    (59)
#define PFCP_IE_NODE_ID                                                                (60)
#define PFCP_IE_PFD_CONTENTS                                                           (61)
#define PFCP_IE_MEASUREMENT_METHOD                                                     (62)
#define PFCP_IE_USAGE_REPORT_TRIGGER                                                   (63)
#define PFCP_IE_MEASUREMENT_PERIOD                                                     (64)
#define PFCP_IE_FQ_CSID                                                                (65)
#define PFCP_IE_VOLUME_MEASUREMENT                                                     (66)
#define PFCP_IE_DURATION_MEASUREMENT                                                   (67)
#define PFCP_IE_APPLICATION_DETECTION_INFORMATION                                      (68)
#define PFCP_IE_TIME_OF_FIRST_PACKET                                                   (69)
#define PFCP_IE_TIME_OF_LAST_PACKET                                                    (70)
#define PFCP_IE_QUOTA_HOLDING_TIME                                                     (71)
#define PFCP_IE_DROPPED_DL_TRAFFIC_THRESHOLD                                           (72)
#define PFCP_IE_VOLUME_QUOTA                                                           (73)
#define PFCP_IE_TIME_QUOTA                                                             (74)
#define PFCP_IE_START_TIME                                                             (75)
#define PFCP_IE_END_TIME                                                               (76)
#define PFCP_IE_QUERY_URR                                                              (77)
#define PFCP_IE_USAGE_REPORT_WITHIN_SESSION_MODIFICATION_RESPONSE                      (78)
#define PFCP_IE_USAGE_REPORT_WITHIN_SESSION_DELETION_RESPONSE                          (79)
#define PFCP_IE_USAGE_REPORT_WITHIN_SESSION_REPORT_REQUEST                             (80)
#define PFCP_IE_URR_ID                                                                 (81)
#define PFCP_IE_LINKED_URR_ID                                                          (82)
#define PFCP_IE_DOWNLINK_DATA_REPORT                                                   (83)
#define PFCP_IE_OUTER_HEADER_CREATION                                                  (84)
#define PFCP_IE_CREATE_BAR                                                             (85)
#define PFCP_IE_UPDATE_BAR_WITHIN_PFCP_SESSION_MODIFICATION_REQUEST                    (86)
#define PFCP_IE_REMOVE_BAR                                                             (87)
#define PFCP_IE_BAR_ID                                                                 (88)
#define PFCP_IE_CP_FUNCTION_FEATURES                                                   (89)
#define PFCP_IE_USAGE_INFORMATION                                                      (90)
#define PFCP_IE_APPLICATION_INSTANCE_ID                                                (91)
#define PFCP_IE_FLOW_INFORMATION                                                       (92)
#define PFCP_IE_UE_IP_ADDRESS                                                          (93)
#define PFCP_IE_PACKET_RATE                                                            (94)
#define PFCP_IE_OUTER_HEADER_REMOVAL                                                   (95)
#define PFCP_IE_RECOVERY_TIME_STAMP                                                    (96)
#define PFCP_IE_DL_FLOW_LEVEL_MARKING                                                  (97)
#define PFCP_IE_HEADER_ENRICHMENT                                                      (98)
#define PFCP_IE_ERROR_INDICATION_REPORT                                                (99)
#define PFCP_IE_MEASUREMENT_INFORMATION                                                (100)
#define PFCP_IE_NODE_REPORT_TYPE                                                       (101)
#define PFCP_IE_USER_PLANE_PATH_FAILURE_REPORT                                         (102)
#define PFCP_IE_REMOTE_GTP_U_PEER                                                      (103)
#define PFCP_IE_UR_SEQN                                                                (104)
#define PFCP_IE_UPDATE_DUPLICATING_PARAMETERS                                          (105)
#define PFCP_IE_ACTIVATE_PREDEFINED_RULES                                              (106)
#define PFCP_IE_DEACTIVATE_PREDEFINED_RULES                                            (107)
#define PFCP_IE_FAR_ID                                                                 (108)
#define PFCP_IE_QER_ID                                                                 (109)
#define PFCP_IE_OCI_FLAGS                                                              (110)
#define PFCP_IE_PFCP_ASSOCIATION_RELEASE_REQUEST                                       (111)
#define PFCP_IE_GRACEFUL_RELEASE_PERIOD                                                (112)
#define PFCP_IE_PDN_TYPE                                                               (113)
#define PFCP_IE_FAILED_RULE_ID                                                         (114)
#define PFCP_IE_TIME_QUOTA_MECHANISM                                                   (115)
#define PFCP_IE_USER_PLANE_IP_RESOURCE_INFORMATION                                     (116)
#define PFCP_IE_USER_PLANE_INACTIVITY_TIMER                                            (117)
#define PFCP_IE_AGGREGATED_URRS                                                        (118)
#define PFCP_IE_MULTIPLIER                                                             (119)
#define PFCP_IE_AGGREGATED_URR_ID                                                      (120)
#define PFCP_IE_SUBSEQUENT_VOLUME_QUOTA                                                (121)
#define PFCP_IE_SUBSEQUENT_TIME_QUOTA                                                  (122)
#define PFCP_IE_RQI                                                                    (123)
#define PFCP_IE_QFI                                                                    (124)
#define PFCP_IE_QUERY_URR_REFERENCE                                                    (125)
#define PFCP_IE_ADDITIONAL_USAGE_REPORTS_INFORMATION                                   (126)
#define PFCP_IE_CREATE_TRAFFIC_ENDPOINT                                                (127)
#define PFCP_IE_CREATED_TRAFFIC_ENDPOINT                                               (128)
#define PFCP_IE_UPDATE_TRAFFIC_ENDPOINT                                                (129)
#define PFCP_IE_REMOVE_TRAFFIC_ENDPOINT                                                (130)
#define PFCP_IE_TRAFFIC_ENDPOINT_ID                                                    (131)
#define PFCP_IE_ETHERNET_PACKET_FILTER                                                 (132)
#define PFCP_IE_MAC_ADDRESS                                                            (133)
#define PFCP_IE_C_TAG                                                                  (134)
#define PFCP_IE_S_TAG                                                                  (135)
#define PFCP_IE_ETHERTYPE                                                              (136)
#define PFCP_IE_PROXYING                                                               (137)
#define PFCP_IE_ETHERNET_FILTER_ID                                                     (138)
#define PFCP_IE_ETHERNET_FILTER_PROPERTIES                                             (139)
#define PFCP_IE_SUGGESTED_BUFFERING_PACKETS_COUNT                                      (140)
#define PFCP_IE_USER_ID                                                                (141)
#define PFCP_IE_ETHERNET_PDU_SESSION_INFORMATION                                       (142)
#define PFCP_IE_ETHERNET_TRAFFIC_INFORMATION                                           (143)
#define PFCP_IE_MAC_ADDRESSES_DETECTED                                                 (144)
#define PFCP_IE_MAC_ADDRESSES_REMOVED                                                  (145)
#define PFCP_IE_ETHERNET_INACTIVITY_TIMER                                              (146)
#define PFCP_IE_ADDITIONAL_MONITORING_TIME                                             (147)
#define PFCP_IE_EVENT_INFORMATION                                                      (148)
#define PFCP_IE_EVENT_REPORTING                                                        (149)
#define PFCP_IE_EVENT_ID                                                               (150)
#define PFCP_IE_EVENT_THRESHOLD                                                        (151)
#define PFCP_IE_TRACE_INFORMATION                                                      (152)
#define PFCP_IE_FRAMED_ROUTE                                                           (153)
#define PFCP_IE_FRAMED_ROUTING                                                         (154)
#define PFCP_IE_FRAMED_IPV6_ROUTE                                                      (155)

#define PFCP_MESSAGE_RESERVED                                                (0)
// PFCP_NODE_RELATED_MESSAGES
#define PFCP_HEARTBEAT_REQUEST                                               (1)
#define PFCP_HEARTBEAT_RESPONSE                                              (2)
#define PFCP_PFCP_PFD_MANAGEMENT_REQUEST                                     (3)
#define PFCP_PFCP_PFD_MANAGEMENT_RESPONSE                                    (4)
#define PFCP_ASSOCIATION_SETUP_REQUEST                                       (5)
#define PFCP_ASSOCIATION_SETUP_RESPONSE                                      (6)
#define PFCP_ASSOCIATION_UPDATE_REQUEST                                      (7)
#define PFCP_ASSOCIATION_UPDATE_RESPONSE                                     (8)
#define PFCP_ASSOCIATION_RELEASE_REQUEST                                     (9)
#define PFCP_ASSOCIATION_RELEASE_RESPONSE                                    (10)
#define PFCP_VERSION_NOT_SUPPORTED_RESPONSE                                  (11)
#define PFCP_NODE_REPORT_REQUEST                                             (12)
#define PFCP_NODE_REPORT_RESPONSE                                            (13)
#define PFCP_SESSION_SET_DELETION_REQUEST                                    (14)
#define PFCP_SESSION_SET_DELETION_RESPONSE                                   (15)
//PFCP_SESSION_RELATED_MESSAGES
#define PFCP_SESSION_ESTABLISHMENT_REQUEST                                   (50)
#define PFCP_SESSION_ESTABLISHMENT_RESPONSE                                  (51)
#define PFCP_SESSION_MODIFICATION_REQUEST                                    (52)
#define PFCP_SESSION_MODIFICATION_RESPONSE                                   (53)
#define PFCP_SESSION_DELETION_REQUEST                                        (54)
#define PFCP_SESSION_DELETION_RESPONSE                                       (55)
#define PFCP_SESSION_REPORT_REQUEST                                          (56)
#define PFCP_SESSION_REPORT_RESPONSE                                         (57)
}

namespace pfcp {
//-------------------------------------
// 8.2.1 Cause
enum cause_value_e {
  /* Request / Initial message */
  CAUSE_VALUE_RESERVED = 0,
  CAUSE_VALUE_REQUEST_ACCEPTED = 1,
  CAUSE_VALUE_REQUEST_REJECTED = 64,
  CAUSE_VALUE_SESSION_CONTEXT_NOT_FOUND = 65,
  CAUSE_VALUE_MANDATORY_IE_MISSING = 66,
  CAUSE_VALUE_CONDITIONAL_IE_MISSING = 67,
  CAUSE_VALUE_INVALID_LENGTH = 68,
  CAUSE_VALUE_MANDATORY_IE_INCORRECT = 69,
  CAUSE_VALUE_INVALID_FORWARDING_POLICY = 70,
  CAUSE_VALUE_INVALID_FTEID_ALLOCATION_OPTION = 71,
  CAUSE_VALUE_NO_ESTABLISHED_PFCP_ASSOCIATION = 72,
  CAUSE_VALUE_RULE_CREATION_MODIFICATION_FAILURE = 73,
  CAUSE_VALUE_PFCP_ENTITY_IN_CONGESTION = 74,
  CAUSE_VALUE_NO_RESOURCES_AVAILABLE = 75,
  CAUSE_VALUE_SERVICE_NOT_SUPPORTED = 76,
  CAUSE_VALUE_SYSTEM_FAILURE = 77
};

typedef struct cause_s {
  uint8_t cause_value;

  bool operator==(const struct cause_s &i) const {
    return (i.cause_value == cause_value);
  }
  ;
  bool operator==(const uint8_t &cvalue) const {
    return (cvalue == cause_value);
  }
  ;
} cause_t;

//-------------------------------------
// 8.2.2 Source Interface
//  enum source_interface_value_e {
//    /* Request / Initial message */
//    ACCESS                        = 0,
//    CORE                          = 1,
//    SGI_LAN_N6_LAN                = 2,
//    CP_FUNCTION                   = 3
//  };
// see @  enum destination_interface_value_e

typedef struct source_interface_s {
  uint8_t interface_value;
  bool operator==(const struct source_interface_s &i) const {
    return (i.interface_value == interface_value);
  }
  ;
} source_interface_t;

//-------------------------------------
// 8.2.3 F-TEID
struct fteid_s {
  uint8_t chid :1;
  uint8_t ch :1;
  uint8_t v4 :1;
  uint8_t v6 :1;
  teid_t teid;
  struct in_addr ipv4_address;
  struct in6_addr ipv6_address;
  uint8_t choose_id;

  bool operator==(const struct fteid_s &f) const {
    return (teid == f.teid) and (ipv4_address.s_addr == f.ipv4_address.s_addr)
        and (chid == f.chid) and (ch == f.ch) and (choose_id == f.choose_id)
        and (ipv6_address.s6_addr32[0] == f.ipv6_address.s6_addr32[0])
        and (ipv6_address.s6_addr32[1] == f.ipv6_address.s6_addr32[1])
        and (ipv6_address.s6_addr32[2] == f.ipv6_address.s6_addr32[2])
        and (ipv6_address.s6_addr32[3] == f.ipv6_address.s6_addr32[3])
        and (v4 == f.v4) and (v6 == f.v6);
  }
  bool is_zero() const {
    return ((!v4) and (!v6));
  }
};

typedef struct fteid_s fteid_t;
//-------------------------------------
// 8.2.4 Network Instance
typedef struct network_instance_s {
  std::string network_instance;
} network_instance_t;

//-------------------------------------
// 8.2.5 SDF Filter
typedef struct sdf_filter_s {
  uint8_t spare :3;
  uint8_t bid :1;
  uint8_t fl :1;
  uint8_t spi :1;
  uint8_t ttc :1;
  uint8_t fd :1;
  uint16_t length_of_flow_description;
  std::string flow_description;
  std::string tos_traffic_class;        // 2 octets
  std::string security_parameter_index;  // 4 octets
  std::string flow_label;  // 3 octets
  uint32_t sdf_filter_id;
} sdf_filter_t;

//-------------------------------------
//  8.2.6 Application ID
typedef struct application_id_s {
  std::string application_id;
} application_id_t;

//-------------------------------------
//  8.2.7 Gate Status
enum gate_status_e {
  /* Request / Initial message */
  OPEN = 0,
  CLOSED = 1
};
typedef struct gate_status_s {
  uint8_t ul_gate :2;
  uint8_t dl_gate :2;
} gate_status_t;

//-------------------------------------
// 8.2.8 MBR
typedef struct mbr_s {
  uint64_t ul_mbr;
  uint64_t dl_mbr;
} mbr_t;

//-------------------------------------
// 8.2.9 GBR
typedef struct gbr_s {
  uint64_t ul_gbr;
  uint64_t dl_gbr;
} gbr_t;

//-------------------------------------
// 8.2.10 QER Correlation ID
typedef struct qer_correlation_id_s {
  uint32_t qer_correlation_id;
} qer_correlation_id_t;

//-------------------------------------
// 8.2.11 Precedence
typedef struct precedence_s {
  uint32_t precedence;
  bool operator==(const struct precedence_s &i) const {
    return (i.precedence == precedence);
  }
  ;
} precedence_t;

//-------------------------------------
// 8.2.12 Transport Level Marking
typedef struct transport_level_marking_s {
  std::string transport_level_marking;  // 2 octets
} transport_level_marking_t;

//-------------------------------------
// 8.2.13 Volume Threshold
typedef struct volume_threshold_s {
  uint8_t tovol :1;
  uint8_t ulvol :1;
  uint8_t dlvol :1;
  uint8_t spare :5;
  uint64_t total_volume;
  uint64_t uplink_volume;
  uint64_t downlink_volume;
} volume_threshold_t;

//-------------------------------------
// 8.2.14 Time Threshold
typedef struct time_threshold_s {
  uint32_t time_threshold;
  bool operator==(const struct time_threshold_s &i) const {
    return (i.time_threshold == time_threshold);
  }
  ;
} time_threshold_t;

//-------------------------------------
// 8.2.15 Monitoring Time
typedef struct monitoring_time_s {
  uint32_t monitoring_time;
} monitoring_time_t;

//-------------------------------------
// 8.2.16 Subsequent Volume Threshold
typedef struct subsequent_volume_threshold_s {
  uint8_t tovol :1;
  uint8_t ulvol :1;
  uint8_t dlvol :1;
  uint8_t spare :5;
  uint64_t total_volume;
  uint64_t uplink_volume;
  uint64_t downlink_volume;
} subsequent_volume_threshold_t;

//-------------------------------------
// 8.2.17 Subsequent Time Threshold
typedef struct subsequent_time_threshold_s {
  uint32_t subsequent_time_threshold;
  bool operator==(const struct subsequent_time_threshold_s &i) const {
    return (i.subsequent_time_threshold == subsequent_time_threshold);
  }
  ;
} subsequent_time_threshold_t;

//-------------------------------------
// 8.2.18 Inactivity Detection Time
typedef struct inactivity_detection_time_s {
  uint32_t inactivity_detection_time;
  bool operator==(const struct inactivity_detection_time_s &i) const {
    return (i.inactivity_detection_time == inactivity_detection_time);
  }
  ;
} inactivity_detection_time_t;

//-------------------------------------
// 8.2.19 Reporting Triggers
typedef struct reporting_triggers_s {
  uint16_t liusa :1;
  uint16_t droth :1;
  uint16_t stop :1;
  uint16_t start :1;
  uint16_t quhti :1;
  uint16_t timth :1;
  uint16_t volth :1;
  uint16_t perio :1;
  uint16_t spare1 :1;
  uint16_t spare2 :1;
  uint16_t spare3 :1;
  uint16_t eveth :1;
  uint16_t macar :1;
  uint16_t envcl :1;
  uint16_t timqu :1;
  uint16_t volqu :1;
} reporting_triggers_t;

//-------------------------------------
// 8.2.20 Redirect Information
typedef struct redirect_information_s {
  uint8_t redirect_address_type :4;
  uint8_t spare :4;
  uint16_t redirect_server_address_length;
} redirect_information_t;

enum redirect_address_type_e {
  IPV4_ADDRESS = 0,
  IPV6_ADDRESS = 1,
  URL = 2,
  SIP_URI = 3
};

//-------------------------------------
// 8.2.21 Report Type
typedef struct report_type_s {
  uint8_t upir :1;
  uint8_t erir :1;
  uint8_t usar :1;
  uint8_t dldr :1;
  uint8_t spare :4;
} report_type_t;

//-------------------------------------
// 8.2.22 Offending IE
typedef struct offending_ie_s {
  uint16_t offending_ie;
  bool operator==(const struct offending_ie_s &i) const {
    return (i.offending_ie == offending_ie);
  }
  ;
} offending_ie_t;

//-------------------------------------
// 8.2.23 Forwarding Policy
typedef struct forwarding_policy_s {
  uint8_t forwarding_policy_identifier_length;
  std::string forwarding_policy_identifier;  // TODO CHECK TYPE
} forwarding_policy_t;

//-------------------------------------
// 8.2.24 Destination Interface
enum destination_interface_value_e {
  /* Request / Initial message */
  INTERFACE_VALUE_ACCESS = 0,
  INTERFACE_VALUE_CORE = 1,
  INTERFACE_VALUE_SGI_LAN_N6_LAN = 2,
  INTERFACE_VALUE_CP_FUNCTION = 3,
  INTERFACE_VALUE_LI_FUNCTION = 4
};

typedef struct destination_interface_s {
  uint8_t interface_value;
  bool operator==(const struct destination_interface_s &i) const {
    return (i.interface_value == interface_value);
  }
  ;
} destination_interface_t;

//-------------------------------------
// 8.2.25 UP Function Features
struct up_function_features_s {
  uint16_t bucp :1;
  uint16_t ddnd :1;
  uint16_t dlbd :1;
  uint16_t trst :1;
  uint16_t ftup :1;
  uint16_t pfdm :1;
  uint16_t heeu :1;
  uint16_t treu :1;

  uint16_t empu :1;
  uint16_t pdiu :1;
  uint16_t udbc :1;
  uint16_t quoac :1;
  uint16_t trace :1;
  uint16_t frrt :1;
  uint16_t spare :2;

  //up_function_features_s& operator=(up_function_features_s i)
  //{
  //  ...
  //  return *this;
  //}
  up_function_features_s()
      :
      bucp(0),
      ddnd(0),
      dlbd(0),
      trst(0),
      ftup(0),
      pfdm(0),
      heeu(0),
      treu(0),
      empu(0),
      pdiu(0),
      udbc(0),
      quoac(0),
      trace(0),
      frrt(0),
      spare(0) {
  }

  up_function_features_s(const up_function_features_s &i) {
    bucp = i.bucp;
    ddnd = i.ddnd;
    dlbd = i.dlbd;
    trst = i.trst;
    ftup = i.ftup;
    pfdm = i.pfdm;
    heeu = i.heeu;
    treu = i.treu;

    empu = i.empu;
    pdiu = i.pdiu;
    udbc = i.udbc;
    quoac = i.quoac;
    trace = i.trace;
    frrt = i.frrt;
    spare = i.spare;
  }
};
//typedef struct up_function_features_s up_function_features_t;

//-------------------------------------
// 8.2.26 Apply Action
typedef struct apply_action_s {
  uint8_t spare :3;
  uint8_t dupl :1;
  uint8_t nocp :1;
  uint8_t buff :1;
  uint8_t forw :1;
  uint8_t drop :1;
} apply_action_t;

//-------------------------------------
// 8.2.27 Downlink Data Service Information
typedef struct downlink_data_service_information_s {
  uint8_t spare :6;
  uint8_t qfii :1;
  uint8_t ppi :1;
  uint8_t Paging_Policy_Indication;
  uint8_t qfi;
} downlink_data_service_information_t;

//-------------------------------------
// 8.2.28 Downlink Data Notification Delay
typedef struct downlink_data_notification_delay_s {
  uint8_t delay;  // Delay Value in integer multiples of 50 millisecs, or zero
} downlink_data_notification_delay_t;

//-------------------------------------
// 8.2.29 DL Buffering Duration
typedef struct dl_buffering_duration_s {
  uint8_t timer_unit :3;
  uint8_t timer_value :5;
} dl_buffering_duration_t;

//-------------------------------------
// 8.2.30 DL Buffering Suggested Packet Count
typedef struct dl_buffering_suggested_packet_count_s {
  uint16_t packet_count;
} dl_buffering_suggested_packet_count_t;

//-------------------------------------
// 8.2.31 PFCPSMReq-Flags
typedef struct pfcpsmreq_flags_s {
  uint8_t spare :5;
  uint8_t qaurr :1;
  uint8_t sndem :1;
  uint8_t drobu :1;
} pfcpsmreq_flags_t;

//-------------------------------------
// 8.2.32 PFCPSRRsp-Flags
typedef struct pfcpsrrsp_flags_s {
  uint8_t spare :7;
  uint8_t drobu :1;
} pfcpsrrsp_flags_t;

//-------------------------------------
// 8.2.33 Sequence Number
typedef struct sequence_number_s {
  uint32_t sequence_number;
  bool operator==(const struct sequence_number_s &i) const {
    return (i.sequence_number == sequence_number);
  }
  ;
} sequence_number_t;

//-------------------------------------
// 8.2.34 Metric
typedef struct metric_s {
  uint8_t metric;  // It indicates a percentage and may take binary coded integer values from
  // and including 0 up to and including 100. Other values shall be considered as 0.
  bool operator==(const struct metric_s &i) const {
    return (i.metric == metric);
  }
  ;
} metric_t;

//-------------------------------------
// 8.2.35 Timer
typedef struct timer_s {
  uint8_t timer_unit :3;
  uint8_t timer_value :5;
} timer_t;

//-------------------------------------
// 8.2.36 Packet Detection Rule ID (PDR ID)
typedef struct pdr_id_s {
  uint16_t rule_id;
  pdr_id_s()
      :
      rule_id(0) {
  }
  pdr_id_s(const uint8_t &p)
      :
      rule_id(p) {
  }
  pdr_id_s(const struct pdr_id_s &p)
      :
      rule_id(p.rule_id) {
  }
  bool operator==(const struct pdr_id_s &i) const {
    return (i.rule_id == rule_id);
  }
  ;
} pdr_id_t;

//-------------------------------------
// 8.2.37 F-SEID
typedef struct fseid_s {
  uint8_t spare :6;
  uint8_t v4 :1;
  uint8_t v6 :1;
  uint64_t seid;
  struct in_addr ipv4_address;
  struct in6_addr ipv6_address;

  bool operator==(const struct fseid_s &i) const {
    if ((i.seid == this->seid) && (i.v4 == this->v4)
        && (i.ipv4_address.s_addr == this->ipv4_address.s_addr)
        && (i.v6 == this->v6)
        && (i.ipv6_address.s6_addr32[0] == this->ipv6_address.s6_addr32[0])
        && (i.ipv6_address.s6_addr32[1] == this->ipv6_address.s6_addr32[1])
        && (i.ipv6_address.s6_addr32[2] == this->ipv6_address.s6_addr32[2])
        && (i.ipv6_address.s6_addr32[3] == this->ipv6_address.s6_addr32[3])) {
      return true;
    } else {
      return false;
    }
  }
  ;
  bool operator<(const struct fseid_s &i) const {
    if (i.seid < this->seid)
      return true;
    else if (i.seid > this->seid)
      return false;
    if (i.v4 == this->v4) {
      if (i.ipv4_address.s_addr > this->ipv4_address.s_addr)
        return true;
      else if (i.ipv4_address.s_addr < this->ipv4_address.s_addr)
        return false;
    } else if (this->v4)
      return true;
    if (i.v6 == this->v6) {
      uint64_t i64 = ((uint64_t) i.ipv6_address.s6_addr32[0] << 32)
          | ((uint64_t) i.ipv6_address.s6_addr32[1]);
      uint64_t this64 = ((uint64_t) this->ipv6_address.s6_addr32[0] << 32)
          | ((uint64_t) this->ipv6_address.s6_addr32[1]);

      if (i64 < this64)
        return true;
      else if (i64 > this64)
        return false;
      i64 = ((uint64_t) i.ipv6_address.s6_addr32[2] << 32)
          | ((uint64_t) i.ipv6_address.s6_addr32[3]);
      this64 = ((uint64_t) this->ipv6_address.s6_addr32[2] << 32)
          | ((uint64_t) this->ipv6_address.s6_addr32[3]);
      if (i64 < this64)
        return true;
      else if (i64 > this64)
        return false;
    } else if (this->v6)
      return true;
    return false;
  }
  ;
} fseid_t;

//-------------------------------------
// 8.2.38 Node ID
enum node_id_type_value_e {
  /* Request / Initial message */
  NODE_ID_TYPE_IPV4_ADDRESS = 0,
  NODE_ID_TYPE_IPV6_ADDRESS = 1,
  NODE_ID_TYPE_FQDN = 2,
};

struct node_id_s {
  uint8_t spare :4;
  uint8_t node_id_type :4;
  union {
    struct in_addr ipv4_address;
    struct in6_addr ipv6_address;
  } u1;
  std::string fqdn;  // should be in union but problem with virtual ~
  bool operator==(const struct node_id_s &i) const {
    if ((i.node_id_type == this->node_id_type)
        && (i.u1.ipv4_address.s_addr == this->u1.ipv4_address.s_addr)
        && (i.fqdn == this->fqdn)
        && (i.u1.ipv6_address.s6_addr32[0] == this->u1.ipv6_address.s6_addr32[0])
        && (i.u1.ipv6_address.s6_addr32[1] == this->u1.ipv6_address.s6_addr32[1])
        && (i.u1.ipv6_address.s6_addr32[2] == this->u1.ipv6_address.s6_addr32[2])
        && (i.u1.ipv6_address.s6_addr32[3] == this->u1.ipv6_address.s6_addr32[3])) {
      return true;
    } else {
      return false;
    }
  }
  ;
};
typedef struct node_id_s node_id_t;
//-------------------------------------
// 8.2.39 PFD Contents
typedef struct pfd_contents_s {
  uint8_t spare :4;
  uint8_t cp :1;
  uint8_t dn :1;
  uint8_t url_ :1;
  uint8_t fd :1;
  uint16_t length_of_flow_description;
  std::string flow_description;
  uint16_t length_of_url;
  std::string url;
  uint16_t length_of_domain_name;
  std::string domain_name;
  uint16_t length_of_custom_pfd_contents;
  std::string custom_pfd_contents;
} pfd_contents_t;

//-------------------------------------
// 8.2.40 Measurement Method
typedef struct measurement_method_s {
  uint16_t spare :5;
  uint16_t event :1;
  uint16_t volum :1;
  uint16_t durat :1;
} measurement_method_t;

//-------------------------------------
// 8.2.41 Usage Report Trigger
typedef struct usage_report_trigger_s {
  uint16_t immer :1;
  uint16_t droth :1;
  uint16_t stop :1;
  uint16_t start :1;
  uint16_t quhti :1;
  uint16_t timth :1;
  uint16_t volth :1;
  uint16_t perio :1;
  uint16_t eveth :1;
  uint16_t macar :1;
  uint16_t envcl :1;
  uint16_t monit :1;
  uint16_t termr :1;
  uint16_t liusa :1;
  uint16_t timqu :1;
  uint16_t volqu :1;
} usage_report_trigger_t;

//-------------------------------------
// 8.2.42 Measurement Period
typedef struct measurement_period_s {
  uint32_t measurement_period;
} measurement_period_t;

//-------------------------------------
// 8.2.43 Fully qualified PDN Connection Set Identifier (FQ-CSID)
//typedef fq_csid_t fq_csid_t;

//-------------------------------------
// 8.2.44 Volume Measurement
typedef struct volume_measurement_s {
  uint8_t spare :5;
  uint8_t dlvol :1;
  uint8_t ulvol :1;
  uint8_t tovol :1;
  uint64_t total_volume;
  uint64_t uplink_volume;
  uint64_t downlink_volume;
} volume_measurement_t;

//-------------------------------------
// 8.2.45 Duration Measurement
typedef struct duration_measurement_s {
  uint32_t duration;
} duration_measurement_t;

//-------------------------------------
// 8.2.46 Time of First Packet
typedef struct time_of_first_packet_s {
  uint32_t time_of_first_packet;
} time_of_first_packet_t;

//-------------------------------------
// 8.2.47 Time of Last Packet
typedef struct time_of_last_packet_s {
  uint32_t time_of_last_packet;
} time_of_last_packet_t;

//-------------------------------------
// 8.2.48 Quota Holding Time
typedef struct quota_holding_time_s {
  uint32_t quota_holding_time;
} quota_holding_time_t;

//-------------------------------------
// 8.2.49 Dropped DL Traffic Threshold
typedef struct dropped_dl_traffic_threshold_s {
  uint8_t spare :6;
  uint8_t dlby :1;
  uint8_t dlpa :1;
  uint64_t downlink_packets;
  uint64_t number_of_bytes_of_downlink_data;
} dropped_dl_traffic_threshold_t;

//-------------------------------------
// 8.2.50 Volume Quota
typedef struct volume_quota_s {
  uint8_t spare :5;
  uint8_t dlvol :1;
  uint8_t ulvol :1;
  uint8_t tovol :1;
  uint64_t total_volume;
  uint64_t uplink_volume;
  uint64_t downlink_volume;
} volume_quota_t;

//-------------------------------------
// 8.2.51 Time Quota
typedef struct time_quota_s {
  uint32_t time_quota;
} time_quota_t;

//-------------------------------------
// 8.2.52 Start Time
typedef struct start_time_s {
  uint32_t start_time;
} start_time_t;

//-------------------------------------
// 8.2.53 End Time
typedef struct end_time_s {
  uint32_t end_time;
} end_time_t;

//-------------------------------------
// 8.2.54 URR ID
typedef struct urr_id_s {
  uint32_t urr_id;
} urr_id_t;

//-------------------------------------
// 8.2.55 Linked URR ID IE
typedef struct linked_urr_id_s {
  uint32_t linked_urr_id;
} linked_urr_id_t;

//-------------------------------------
// 8.2.56 Outer Header Creation
enum outer_header_creation_description_value_e {
  OUTER_HEADER_CREATION_GTPU_UDP_IPV4 = 0x0100,
  OUTER_HEADER_CREATION_GTPU_UDP_IPV6 = 0x0200,
  OUTER_HEADER_CREATION_UDP_IPV4 = 0x0400,
  OUTER_HEADER_CREATION_UDP_IPV6 = 0x0800
};

typedef struct outer_header_creation_s {
  uint16_t outer_header_creation_description;
  uint32_t teid;
  struct in_addr ipv4_address;
  struct in6_addr ipv6_address;
  uint16_t port_number;
} outer_header_creation_t;

//-------------------------------------
// 8.2.57 BAR ID
typedef struct bar_id_s {
  uint8_t bar_id;
} bar_id_t;

//-------------------------------------
// 8.2.58 CP Function Features
struct cp_function_features_s {
  uint8_t spare :6;
  uint8_t ovrl :1;
  uint8_t load :1;
  //cp_function_features_s& operator=(cp_function_features_s i)
  //{
  //  ...
  //  return *this;
  //}
  cp_function_features_s()
      :
      spare(0),
      ovrl(0),
      load(0) {
  }
  cp_function_features_s(const cp_function_features_s &i)
      :
      spare(i.spare),
      ovrl(i.ovrl),
      load(i.load) {
  }
};
typedef struct cp_function_features_s cp_function_features_t;
//-------------------------------------
// 8.2.59 Usage Information
typedef struct usage_information_s {
  uint8_t spare :4;
  uint8_t ube :1;
  uint8_t uae :1;
  uint8_t aft :1;
  uint8_t bef :1;
} usage_information_t;

//-------------------------------------
// 8.2.60 Application Instance ID
typedef struct application_instance_id_s {
  std::string application_instance_identifier;
} application_instance_id_t;

//-------------------------------------
// 8.2.61 Flow Information
enum flow_direction_value_e {
  UNSPECIFIED = 0,
  DOWNLINK = 1,
  UPLINK = 2,
  BIDIRECTIONAL = 3
};

typedef struct flow_information_s {
  uint8_t spare :5;
  uint8_t flow_direction :3;
  uint16_t length_of_flow_description :3;
  std::string flow_description;
} flow_information_t;

//-------------------------------------
// 8.2.62 UE IP Address
typedef struct ue_ip_address_s {
  uint8_t ipv6d :1;  // This bit is only applicable to the UE IP address IE in the PDI IE and whhen V6 bit is set to "1". If this bit is set to "1", then the IPv6 Prefix Delegation Bits field shall be present, otherwise the UP function shall consider IPv6 prefix is default /64.
  uint8_t sd :1;  // This bit is only applicable to the UE IP Address IE in the PDI IE. It shall be set to "0" and ignored by the receiver in IEs other than PDI IE. In the PDI IE, if this bit is set to "0", this indicates a Source IP address; if this bit is set to "1", this indicates a Destination IP address.
  uint8_t v4 :1;  // If this bit is set to "1", then the IPv4 address field shall be present in the UE IP Address, otherwise the IPv4 address field shall not be present.
  uint8_t v6 :1;  // If this bit is set to "1", then the IPv6 address field shall be present in the UE IP Address, otherwise the IPv6 address field shall not be present.
  struct in_addr ipv4_address;
  struct in6_addr ipv6_address;
  uint8_t ipv6_prefix_delegation_bits;
} ue_ip_address_t;

//-------------------------------------
// 8.2.63 Packet Rate
typedef struct packet_rate_s {
  uint8_t dlpr :1;
  uint8_t ulpr :1;
  uint8_t uplink_time_unit :3;
  uint8_t downlink_time_unit :3;
  uint16_t maximum_uplink_packet_rate;
  uint16_t maximum_downlink_packet_rate;
} packet_rate_t;

//-------------------------------------
// 8.2.64 Outer Header Removal
#define OUTER_HEADER_REMOVAL_GTPU_UDP_IPV4 0
#define OUTER_HEADER_REMOVAL_GTPU_UDP_IPV6 1
#define OUTER_HEADER_REMOVAL_UDP_IPV4      2
#define OUTER_HEADER_REMOVAL_UDP_IPV6      3
typedef struct outer_header_removal_s {
  uint8_t outer_header_removal_description;
} outer_header_removal_t;

//-------------------------------------
// 8.2.65 Recovery Time Stamp
typedef struct recovery_time_stamp_s {
  uint32_t recovery_time_stamp;
  bool operator==(const struct recovery_time_stamp_s &a) const {
    return (recovery_time_stamp == a.recovery_time_stamp);
  }
} recovery_time_stamp_t;

//-------------------------------------
// 8.2.66 DL Flow Level Marking
typedef struct dl_flow_level_marking_s {
  uint8_t spare :6;
  uint8_t sci :1;
  uint8_t ttc :1;
  uint16_t tos_traffic_class;
  uint16_t service_class_indicator;
} dl_flow_level_marking_t;

//-------------------------------------
// 8.2.67 Header Enrichment
typedef struct header_enrichment_s {
  uint8_t spare :3;
  uint8_t header_type :5;
  uint8_t lenght_of_header_field_name;
  std::string header_field_name;
  uint8_t lenght_of_header_field_value;
  std::string header_field_value;
} header_enrichment_t;

//-------------------------------------
// 8.2.68 Measurement Information
typedef struct measurement_information_s {
  uint8_t spare :5;
  uint8_t radi :1;
  uint8_t inam :1;
  uint8_t mbqe :1;
} measurement_information_t;

//-------------------------------------
// 8.2.69 Node Report Type
typedef struct node_report_type_s {
  uint8_t spare :7;
  uint8_t upfr :1;
} node_report_type_t;

//-------------------------------------
// 8.2.70 Remote GTP-U Peer
typedef struct remote_gtp_u_peer_s {
  uint8_t spare :6;
  uint8_t v4 :1;
  uint8_t v6 :1;
  struct in_addr ipv4_address;
  struct in6_addr ipv6_address;
} remote_gtp_u_peer_t;

//-------------------------------------
// 8.2.71 UR-SEQN
typedef struct ur_seqn_s {
  uint32_t ur_seqn;
} ur_seqn_t;

//-------------------------------------
// 8.2.72 Activate Predefined Rules
typedef struct activate_predefined_rules_s {
  std::string predefined_rules_name;
} activate_predefined_rules_t;

//-------------------------------------
// 8.2.73 Deactivate Predefined Rules
typedef struct deactivate_predefined_rules_s {
  std::string predefined_rules_name;
} deactivate_predefined_rules_t;

//-------------------------------------
// 8.2.74 FAR ID
struct far_id_s {
  uint32_t far_id;
  far_id_s()
      :
      far_id(0) {
  }
  far_id_s(const uint8_t &f)
      :
      far_id(f) {
  }
  far_id_s(const struct far_id_s &f)
      :
      far_id(f.far_id) {
  }
  bool operator==(const struct far_id_s &i) const {
    return (i.far_id == far_id);
  }
  ;
};
typedef struct far_id_s far_id_t;
//-------------------------------------
// 8.2.75 QER ID
typedef struct qer_id_s {
  uint32_t qer_id;
} qer_id_t;

//-------------------------------------
// 8.2.76 OCI Flags
typedef struct oci_flags_s {
  uint8_t spare :7;
  uint8_t aoci :1;
} oci_flags_t;

//-------------------------------------
// 8.2.77 PFCP Association Release Request
typedef struct pfcp_association_release_request_s {
  uint8_t spare :7;
  uint8_t sarr :1;
} pfcp_association_release_request_t;

//-------------------------------------
// 8.2.78 Graceful Release Period
typedef struct graceful_release_period_s {
  uint8_t timer_unit :3;
  uint8_t timer_value :5;
} graceful_release_period_t;

//-------------------------------------
// 8.2.79 PDN Type
enum pdn_type_value_e {
  /* Request / Initial message */
  IPV4 = 1,
  IPV6 = 2,
  IPV4V6 = 3,
  NON_IP = 4,
  ETHERNET = 5
};

typedef struct pdn_type_s {
  uint8_t spare :5;
  uint8_t pdn_type :3;
} pdn_type_t;

//-------------------------------------
// 8.2.80 Failed Rule ID
enum rule_id_type_e {
  /* Request / Initial message */
  FAILED_RULE_ID_TYPE_PDR = 0,
  FAILED_RULE_ID_TYPE_FAR,
  FAILED_RULE_ID_TYPE_QER,
  FAILED_RULE_ID_TYPE_URR,
  FAILED_RULE_ID_TYPE_BAR
};
typedef struct failed_rule_id_s {
  uint8_t spare :3;
  uint8_t rule_id_type :5;
  uint32_t rule_id_value;
} failed_rule_id_t;

//-------------------------------------
// 8.2.81 Time Quota Mechanism
enum base_time_interval_type_value_e {
  /* Request / Initial message */
  CTP = 0,
  DTP = 1
};

typedef struct time_quota_mechanism_s {
  uint8_t spare :6;
  uint8_t btit :3;
  uint32_t base_time_interval;
} time_quota_mechanism_t;

//-------------------------------------
// 8.2.82 User Plane IP Resource Information
typedef struct user_plane_ip_resource_information_s {
  uint8_t spare :1;
  uint8_t assosi :1;
  uint8_t assoni :1;
  uint8_t teidri :3;
  uint8_t v6 :1;
  uint8_t v4 :1;
  uint8_t teid_range;
  struct in_addr ipv4_address;
  struct in6_addr ipv6_address;
  uint16_t network_instance;
  uint8_t source_interface;
} user_plane_ip_resource_information_t;

//-------------------------------------
// 8.2.83 User Plane Inactivity Timer
typedef struct user_plane_inactivity_timer_s {
  uint32_t user_plane_inactivity_timer;
} user_plane_inactivity_timer_t;

//-------------------------------------
// 8.2.84 Multiplier
typedef struct multiplier_s {
  uint64_t value_digits;
  uint32_t exponent;
} multiplier_t;

//-------------------------------------
// 8.2.85 Aggregated URR ID IE
typedef struct aggregated_urr_id_s {
  uint32_t urr_id;
} aggregated_urr_id_t;

//-------------------------------------
// 8.2.86 Subsequent Volume Quota
typedef struct subsequent_volume_quota_s {
  uint8_t dlvol :1;
  uint8_t ulvol :1;
  uint8_t tovol :1;
  uint64_t total_volume;
  uint64_t uplink_volume;
  uint64_t downlink_volume;
} subsequent_volume_quota_t;

//-------------------------------------
// 8.2.87 Subsequent Time Quota
typedef struct subsequent_time_quota_s {
  uint64_t time_quota;
} subsequent_time_quota_t;

//-------------------------------------
// 8.2.88 RQI
typedef struct rqi_s {
  uint8_t spare :7;
  uint8_t rqi :1;
} rqi_t;

//-------------------------------------
// 8.2.89 QFI
typedef struct qfi_s {
  uint8_t spare :2;
  uint8_t qfi :6;
  qfi_s()
      :
      qfi(0),
      spare(0) {
  }
  qfi_s(const uint8_t &q)
      :
      qfi(q),
      spare(0) {
  }
  qfi_s(const struct qfi_s &q)
      :
      qfi(q.qfi),
      spare(q.spare) {
  }
  inline bool operator==(const struct qfi_s &rhs) const {
    return ((qfi == rhs.qfi) && (spare == rhs.spare));
  }
  inline bool operator!=(const struct qfi_s &rhs) const {
    return !((qfi == rhs.qfi) && (spare == rhs.spare));
  }
} qfi_t;

//-------------------------------------
// 8.2.90 Query URR Reference
typedef struct query_urr_reference_s {
  uint32_t query_urr_reference;
} query_urr_reference_t;

//-------------------------------------
// 8.2.91 Additional Usage Reports Information
typedef struct additional_usage_reports_information_s {
  uint8_t spare :7;
  uint8_t auri :1;
  uint16_t number_of_additional_usage_reports_value;
} additional_usage_reports_information_t;

//-------------------------------------
// 8.2.92 Traffic Endpoint ID
typedef struct traffic_endpoint_id_s {
  uint8_t traffic_endpoint_id;
} traffic_endpoint_id_t;

//-------------------------------------
// 8.2.93 MAC address
typedef struct mac_address_s {
  uint8_t spare :4;
  uint8_t udes :1;
  uint8_t usou :1;
  uint8_t dest;
  uint8_t sour;
  uint8_t source_mac_address[6];
  uint8_t destination_mac_address[6];
  uint8_t upper_source_mac_address[6];
  uint8_t upper_destination_mac_address[6];
} mac_address_t;

//-------------------------------------
// 8.2.94 C-TAG (Customer-VLAN tag)
typedef struct c_tag_s {
  uint8_t spare :1;
  uint8_t vid :1;
  uint8_t dei :1;
  uint8_t pcp :1;
  uint8_t dei_flag :1;
  uint8_t pcp_value :3;
  uint16_t cvid_value;
} c_tag_t;

//-------------------------------------
// 8.2.95 S-TAG (Service-VLAN tag)
typedef struct s_tag_s {
  uint8_t spare :1;
  uint8_t vid :1;
  uint8_t dei :1;
  uint8_t pcp :1;
  uint8_t dei_flag :1;
  uint8_t pcp_value :3;
  uint16_t svid_value;
} s_tag_t;

//-------------------------------------
// 8.2.96 Ethertype
typedef struct ethertype_s {
  uint16_t ethertype;
} ethertype_t;

//-------------------------------------
// 8.2.97 Proxying
typedef struct proxying_s {
  uint8_t spare :6;
  uint8_t ins :1;
  uint8_t arp :1;
} proxying_t;

//-------------------------------------
// 8.2.98 Ethernet Filter ID
typedef struct ethernet_filter_id_s {
  uint32_t ethernet_filter_id;
} ethernet_filter_id_t;

//-------------------------------------
// 8.2.99 Ethernet Filter Properties
typedef struct ethernet_filter_properties_s {
  uint8_t spare :7;
  uint8_t bide :1;
} ethernet_filter_properties_t;

//-------------------------------------
// 8.2.100 Suggested Buffering Packets Count
typedef struct suggested_buffering_packets_count_s {
  uint8_t packets_count_value;
} suggested_buffering_packets_count_t;

//-------------------------------------
// 8.2.101 User ID
typedef struct user_id_s {
  uint8_t spare :4;
  uint8_t naif :1;
  uint8_t msisdnf :1;
  uint8_t imeif :1;
  uint8_t imsif :1;
  uint8_t length_of_imsi;
  imsi_t imsi;
  uint8_t length_of_imei;
  std::string imei;
  uint8_t length_of_msisdn;
  msisdn_t msisdn;
  uint8_t length_of_nai;
  std::string nai;
} user_id_t;

//-------------------------------------
// 8.2.102 Ethernet PDU Session Information
typedef struct ethernet_pdu_session_information_s {
  uint8_t spare :7;
  uint8_t ethi :1;
} ethernet_pdu_session_information_t;

//-------------------------------------
// 8.2.103 MAC addresses Detected
typedef struct mac_addresses_detected_s {
  uint8_t number_of_mac_addresses;
  //std::vector<mac_address> mac_addresses;
} mac_addresses_detected_t;

//-------------------------------------
// 8.2.104 MAC addresses Removed
typedef struct mac_addresses_removed_s {
  uint8_t number_of_mac_addresses;
  //std::vector<mac_address> mac_addresses;
} mac_addresses_removed_t;

//-------------------------------------
// 8.2.105 Ethernet Inactivity Timer
typedef struct ethernet_inactivity_timer_s {
  uint32_t ethernet_inactivity_timer;
} ethernet_inactivity_timer_t;

//-------------------------------------
// 8.2.106 Event ID
typedef struct event_id_s {
  uint32_t event_id;
} event_id_t;

//-------------------------------------
// 8.2.107 Event Threshold
typedef struct event_threshold_s {
  uint32_t event_threshold;
} event_threshold_t;

//-------------------------------------
// 8.2.108 Trace Information
typedef struct trace_information_s {
  uint8_t mcc_digit2 :4;
  uint8_t mcc_digit1 :4;
  uint8_t mnc_digit3 :4;
  uint8_t mcc_digit3 :4;
  uint8_t mnc_digit2 :4;
  uint8_t mnc_digit1 :4;
  uint32_t trace_id;
  uint8_t length_of_triggered_events;
  // TODO CONTINUE
} trace_information_t;

//-------------------------------------
// 8.2.109 Framed-Route
typedef struct framed_route_s {
  std::string framed_route;
} framed_route_t;

//-------------------------------------
// 8.2.110 Framed-Routing
typedef struct framed_routing_s {
  uint32_t framed_routing;
} framed_routing_t;

//-------------------------------------
// 8.2.111 Framed-IPv6-Route
typedef struct framed_ipv6_route_s {
  std::string framed_ipv6_route;
} framed_ipv6_route_t;

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Specific IEs
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//  // Table 7.4.3.1-3: PFD
//  typedef struct pfd_s {
//    pfd_contents_t pfd_contents;
//  } pfd_t;
//
//  // Table 7.4.3.1-2: Application ID's PFDs
//  typedef struct application_ids_pfds_s {
//    application_id_t application_id;
//    std::vector<pfd_t> pfds;
//  } application_ids_pfds_t;
//
//  // Table 7.4.5.1.2-1: User Plane Path Failure IE within PFCP Node Report Request
//  typedef struct user_plane_path_failure_report_s {
//    remote_gtp_u_peer_t remote_gtp_u_peer;
//  } user_plane_path_failure_report_t;
//
//  // Table 7.5.2.2-3: Ethernet Packet Filter IE within PFCP Session Establishment Request
//  typedef struct ethernet_packet_filter_s {
//    ethernet_filter_id_t        ethernet_filter_id;
//    ethernet_filter_properties_t ethernet_filter_properties;
//    mac_address_t               mac_address;
//    ethertype_t                 ethertype;
//    c_tag_t                     c_tag;
//    s_tag_t                     s_tag;
//    sdf_filter_t                sdf_filter;
//  } ethernet_packet_filter_t;
//
//  // Table 7.5.2.2-2: PDI IE within PFCP Session Establishment Request
//  typedef struct pdi_s {
//    source_interface_t          source_interface;
//    fteid_t                     local_fteid;
//    network_instance_t          network_instance;
//    ue_ip_address_t             ue_ip_address;
//    traffic_endpoint_id_t       traffic_endpoint_id;
//    sdf_filter_t                sdf_filter;
//    application_id_t            application_id;
//    ethernet_packet_filter_t    ethernet_packet_filter;
//    qfi_t                       qfi;
//    framed_route_t              framed_route;
//    framed_routing_t            framed_routing;
//    framed_ipv6_route_t         framed_ipv6_route;
//  } pdi_t;
//
//  // Table 7.5.2.2-1: Create PDR IE within PFCP Session Establishment Request
//  typedef struct create_pdr_s {
//    pdr_id_t                    pdr_id;
//    precedence_t                precedence;
//    pdi_t                       pdi;
//    far_id_t                    far_id;
//    urr_id_t                    urr_id;
//    qer_id_t                    qer_id;
//    activate_predefined_rules_t activate_predefined_rules;
//  } create_pdr_t;
//
//  // Table 7.5.2.3-2: Forwarding Parameters IE in FAR
//  typedef struct forwarding_parameters_s {
//    destination_interface_t     destination_interface;
//    network_instance_t          network_instance;
//    redirect_information_t      redirect_information;
//    outer_header_creation_t     outer_header_creation;
//    transport_level_marking_t   transport_level_marking;
//    forwarding_policy_t         forwarding_policy;
//    header_enrichment_t         header_enrichment;
//    traffic_endpoint_id_t       linked_traffic_endpoint_id_t;
//    proxying_t                  proxying;
//  } forwarding_parameters_t;
//
//  // Table 7.5.2.3-3: Duplicating Parameters IE in FAR
//  typedef struct duplicating_parameters_s {
//    destination_interface_t     destination_interface;
//    outer_header_creation_t     outer_header_creation;
//    transport_level_marking_t   transport_level_marking;
//    forwarding_policy_t         forwarding_policy;
//  } duplicating_parameters_t;
//
//  // Table 7.5.2.3-1: Create FAR IE within PFCP Session Establishment Request
//  typedef struct create_far_s {
//    far_id_t                    far_id;
//    apply_action_t              apply_action;
//    forwarding_parameters_t     forwarding_parameters;
//    duplicating_parameters_t    duplicating_parameters;
//    bar_id_t                    bar_id;
//  } create_far_t;
//
//  // Table 7.5.2.4-2: Aggregated URRs
//  typedef struct aggregated_urrs_s {
//    aggregated_urr_id_t         aggregated_urr_id;
//    multiplier_t                multiplier;
//  } aggregated_urrs_t;
//
//  // Table 7.5.2.4-3: Additional Monitoring Time
//  typedef struct additional_monitoring_time_s {
//    monitoring_time_t           monitoring_time;
//    subsequent_volume_threshold_t subsequent_volume_threshold;
//    subsequent_time_threshold_t subsequent_time_threshold;
//    subsequent_volume_quota_t   subsequent_volume_quota;
//    subsequent_time_quota_t     subsequent_time_quota;
//  } additional_monitoring_time_t;
//
//  // Table 7.5.2.4-4: Event Information
//  typedef struct event_information_s {
//    event_id_t           event_id;
//    event_threshold_t    event_threshold;
//  } event_information_t;
//
//
//  // Table 7.5.2.4-1: Create URR IE within PFCP Session Establishment Request
//  typedef struct create_urr_s {
//    urr_id_t                    urr_id;
//    measurement_method_t        measurement_method;
//    reporting_triggers_t        reporting_triggers;
//    measurement_period_t        measurement_period;
//    volume_threshold_t          volume_threshold;
//    volume_quota_t              volume_quota;
//    time_threshold_t            time_threshold;
//    time_quota_t                time_quota;
//    quota_holding_time_t        quota_holding_time;
//    dropped_dl_traffic_threshold_t  dropped_dl_traffic_threshold;
//    monitoring_time_t           monitoring_time;
//    event_information_t         event_information;
//    subsequent_volume_threshold_t subsequent_volume_threshold;
//    subsequent_time_threshold_t subsequent_time_threshold;
//    subsequent_volume_quota_t   subsequent_volume_quota;
//    subsequent_time_quota_t     subsequent_time_quota;
//    inactivity_detection_time_t inactivity_detection_time;
//    linked_urr_id_t             linked_urr_id;
//    measurement_information_t   measurement_information;
//    time_quota_mechanism_t      time_quota_mechanism;
//    aggregated_urrs_t           aggregated_urrs;
//    far_id_t                    far_id_for_quota_action;
//    ethernet_inactivity_timer_t ethernet_inactivity_timer;
//    additional_monitoring_time_t additional_monitoring_time;
//  } create_urr_t;
//
//  // Table 7.5.2.5-1: Create QER IE within PFCP Session Establishment Request
//  typedef struct create_qer_s {
//    qer_id_t                    qer_id;
//    qer_correlation_id_t        qer_correlation_id;
//    gate_status_t               gate_status;
//    mbr_t                       maximum_bitrate;
//    gbr_t                       guaranteed_bitrate;
//    packet_rate_t               packet_rate;
//    dl_flow_level_marking_t     dl_flow_level_marking;
//    qfi_t                       qos_flow_identifier;
//    rqi_t                       reflective_qos;
//  } create_qer_t;
//
//  // Table 7.5.2.6-1: Create BAR IE within PFCP Session Establishment Request
//  typedef struct create_bar_s {
//    bar_id_t                    bar_id;
//    downlink_data_notification_delay_t  downlink_data_notification_delay;
//    suggested_buffering_packets_count_t suggested_buffering_packets_count;
//  } create_bar_t;
//
//  // Table 7.5.2.7-1: Create Traffic Endpoint IE within PFCP Session Establishment Request
//  typedef struct create_traffic_endpoint_s {
//    traffic_endpoint_id_t       traffic_endpoint_id;
//    fteid_t                     local_fteid;
//    network_instance_t          network_instance;
//    ue_ip_address_t             ue_ip_address;
//    ethernet_pdu_session_information_t ethernet_pdu_session_information;
//    framed_route_t              framed_route;
//    framed_routing_t            framed_routing;
//    framed_ipv6_route_t         framed_ipv6_route;
//  } create_traffic_endpoint_t;
//
//  // Table 7.5.3.2-1: Created PDR IE within PFCP Session Establishment Response
//  typedef struct created_pdr_s {
//    pdr_id_t                    pdr_id;
//    fteid_t                     local_fteid;
//  } created_pdr_t;
//
//  // Table 7.5.3.3-1: Load Control Information IE within PFCP Session Establishment Response
//  typedef struct load_control_information_s {
//    sequence_number_t           load_control_sequence_number;
//    metric_t                    load_metric;
//  } load_control_information_t;
//
//  // Table 7.5.3.4-1: Overload Control Information IE within PFCP Session Establishment Response
//  typedef struct overload_control_information_s {
//    sequence_number_t           overload_control_sequence_number;
//    metric_t                    overload_reduction_metric;
//    timer_t                     period_of_validity;
//    oci_flags_t                 overload_control_information_flags;
//  } overload_control_information_t;
//
//  // Table 7.5.4.2-1: Update PDR IE within PFCP Session Modification Request
//  typedef struct update_pdr_s {
//    pdr_id_t                    pdr_id;
//    outer_header_removal_t      outer_header_removal;
//    precedence_t                precedence;
//    pdi_t                       pdi;
//    far_id_t                    far_id;
//    urr_id_t                    urr_id;
//    qer_id_t                    qer_id;
//    activate_predefined_rules_t activate_predefined_rules;
//    deactivate_predefined_rules_t deactivate_predefined_rules;
//  } update_pdr_t;
//
//  // Table 7.5.4.3-2: Update Forwarding Parameters IE in FAR
//  typedef struct update_forwarding_parameters_s {
//    destination_interface_t     destination_interface;
//    network_instance_t          network_instance;
//    outer_header_creation_t     outer_header_creation;
//    transport_level_marking_t   transport_level_marking;
//    forwarding_policy_t         forwarding_policy;
//    header_enrichment_t         header_enrichment;
//    pfcpsmreq_flags_t           pfcpsmreq_flags;
//    traffic_endpoint_id_t       linked_traffic_endpoint_id;
//  } update_forwarding_parameters_t;
//
//  // Table 7.5.4.3-3: Update Duplicating Parameters IE in FAR
//  typedef struct update_duplicating_parameters_s {
//    destination_interface_t     destination_interface;
//    outer_header_creation_t     outer_header_creation;
//    transport_level_marking_t   transport_level_marking;
//    forwarding_policy_t         forwarding_policy;
//  } update_duplicating_parameters_t;
//
//  // Table 7.5.4.3-1: Update FAR IE within PFCP Session Modification Request
//  typedef struct update_far_s {
//    far_id_t                    far_id;
//    apply_action_t              apply_action;
//    update_forwarding_parameters_t update_forwarding_parameters;
//    update_duplicating_parameters_t update_duplicating_parameters;
//    bar_id_t                    bar_id;
//  } update_far_t;
//
//  // Table 7.5.4.4-1: Update URR IE within PFCP Session Modification Request
//  typedef struct update_urr_s {
//    urr_id_t                    urr_id;
//    measurement_method_t        measurement_method;
//    reporting_triggers_t        reporting_triggers;
//    measurement_period_t        measurement_period;
//    volume_threshold_t          volume_threshold;
//    volume_quota_t              volume_quota;
//    time_threshold_t            time_threshold;
//    time_quota_t                time_quota;
//    quota_holding_time_t        quota_holding_time;
//    dropped_dl_traffic_threshold_t  dropped_dl_traffic_threshold;
//    monitoring_time_t           monitoring_time;
//    event_information_t         event_information;
//    subsequent_volume_threshold_t subsequent_volume_threshold;
//    subsequent_time_threshold_t subsequent_time_threshold;
//    subsequent_volume_quota_t   subsequent_volume_quota;
//    subsequent_time_quota_t     subsequent_time_quota;
//    inactivity_detection_time_t inactivity_detection_time;
//    linked_urr_id_t             linked_urr_id;
//    measurement_information_t   measurement_information;
//    time_quota_mechanism_t      time_quota_mechanism;
//    aggregated_urrs_t           aggregated_urrs;
//    far_id_t                    far_id_for_quota_action;
//    ethernet_inactivity_timer_t ethernet_inactivity_timer;
//    additional_monitoring_time_t additional_monitoring_time;
//  } update_urr_t;
//
//  // Table 7.5.4.5-1: Update QER IE within PFCP Session Modification Request
//  typedef struct update_qer_s {
//    qer_id_t                    qer_id;
//    qer_correlation_id_t        qer_correlation_id;
//    gate_status_t               gate_status;
//    mbr_t                       maximum_bitrate;
//    gbr_t                       guaranteed_bitrate;
//    packet_rate_t               packet_rate;
//    dl_flow_level_marking_t     dl_flow_level_marking;
//    qfi_t                       qos_flow_identifier;
//    rqi_t                       reflective_qos;
//  } update_qer_t;
//
//  // Table 7.5.4.6-1: Remove PDR IE within PFCP Session Modification Request
//  typedef struct remove_pdr_s {
//    pdr_id_t                    pdr_id;
//  } remove_pdr_t;
//
//  // Table 7.5.4.7-1: Remove FAR IE within PFCP Session Modification Request
//  typedef struct remove_far_s {
//    far_id_t                    far_id;
//  } remove_far_t;
//
//  // Table 7.5.4.8-1: Remove URR IE within PFCP Session Modification Request
//  typedef struct remove_urr_s {
//    urr_id_t                    urr_id;
//  } remove_urr_t;
//
//  // Table 7.5.4.9-1: Remove QER IE PFCP Session Modification Request
//  typedef struct remove_qer_s {
//    qer_id_t                    qer_id;
//  } remove_qer_t;
//
//  // Table 7.5.4.10-1: Query URR IE within PFCP Session Modification Request
//  typedef struct query_urr_s {
//    urr_id_t                    urr_id;
//  } query_urr_t;
//
//  // Table 7.5.4.11-1: Update BAR IE within PFCP Session Modification Request
//  typedef struct update_bar_within_pfcp_session_modification_request_s {
//    bar_id_t                            bar_id;
//    downlink_data_notification_delay_t  downlink_data_notification_delay;
//    suggested_buffering_packets_count_t suggested_buffering_packets_count;
//  } update_bar_within_pfcp_session_modification_request_t;
//
//  // Table 7.5.4.12-1: Remove BAR IE within PFCP Session Modification Request
//  typedef struct remove_bar_s {
//    bar_id_t                            bar_id;
//  } remove_bar_t;
//
//
//  // Table 7.5.3.5-1: Created Traffic Endpoint IE within Sx Session Establishment Response
//  typedef struct created_traffic_endpoint_s {
//    traffic_endpoint_id_t       traffic_endpoint_id;
//    fteid_t                     local_fteid;
//  } created_traffic_endpoint_t;
//
//  // Table 7.5.4.13-1: Update Traffic Endpoint IE within Sx Session Modification Request
//  typedef struct update_traffic_endpoint_s {
//    traffic_endpoint_id_t       traffic_endpoint_id;
//    fteid_t                     local_fteid;
//    network_instance_t          network_instance;
//    ue_ip_address_t             ue_ip_address;
//    framed_route_t              framed_route;
//    framed_routing_t            framed_routing;
//    framed_ipv6_route_t         framed_ipv6_route;
//  } update_traffic_endpoint_t;
//
//  // Table 7.5.4.14-1: Remove Traffic Endpoint IE within Sx Session Modification Request
//  typedef struct remove_traffic_endpoint_s {
//    traffic_endpoint_id_t       traffic_endpoint_id;
//  } remove_traffic_endpoint_t;
//
//  // Table 7.5.8.3-3: Ethernet Traffic Information IE within Usage Report IE
//  typedef struct ethernet_traffic_information_s {
//    mac_addresses_detected_t             mac_addresses_detected;
//    mac_addresses_removed_t              mac_addresses_removed;
//  } ethernet_traffic_information_t;
//
//  // Table 7.5.5.2-1: Usage Report IE within PFCP Session Modification Response
//  typedef struct usage_report_within_pfcp_session_modification_response_s {
//    urr_id_t                    urr_id;
//    ur_seqn_t                   ur_seqn;
//    usage_report_trigger_t      usage_report_trigger;
//    start_time_t                start_time;
//    end_time_t                  end_time;
//    volume_measurement_t        volume_measurement;
//    duration_measurement_t      duration_measurement;
//    time_of_first_packet_t      time_of_first_packet;
//    time_of_last_packet_t       time_of_last_packet;
//    usage_information_t         usage_information;
//    query_urr_reference_t       query_urr_reference;
//    ethernet_traffic_information_t ethernet_traffic_information;
//  } usage_report_within_pfcp_session_modification_response_t;
//
//  // Table 7.5.7.2-1: Usage Report IE within PFCP Session Deletion Response
//  typedef struct usage_report_within_pfcp_session_deletion_response_s {
//    urr_id_t                    urr_id;
//    ur_seqn_t                   ur_seqn;
//    usage_report_trigger_t      usage_report_trigger;
//    start_time_t                start_time;
//    end_time_t                  end_time;
//    volume_measurement_t        volume_measurement;
//    duration_measurement_t      duration_measurement;
//    time_of_first_packet_t      time_of_first_packet;
//    time_of_last_packet_t       time_of_last_packet;
//    usage_information_t         usage_information;
//    ethernet_traffic_information_t ethernet_traffic_information;
//  } usage_report_within_pfcp_session_deletion_response_t;
//
//  // Table 7.5.8.2-1: Downlink Data Report IE within PFCP Session Report Request
//  typedef struct downlink_data_report_s {
//    pdr_id_t                    pdr_id;
//    downlink_data_service_information_t  downlink_data_service_information;
//  } downlink_data_report_t;
//
//  // Table 7.5.8.3-2: Application Detection Information IE within Usage Report IE
//  typedef struct application_detection_information_s {
//    application_id_t                    application_id;
//    application_instance_id_t           application_instance_id;
//    flow_information_t                  flow_information;
//  } application_detection_information_t;
//
//  // Table 7.5.8.3-2A: Event Reporting IE within Usage Report IE
//  typedef struct event_reporting_s {
//    event_id_t                    event_id;
//  } event_reporting_t;
//
//  //
//  // Table 7.5.8.3-1: Usage Report IE within PFCP Session Report Request
//  typedef struct usage_report_within_pfcp_session_report_request_s {
//    urr_id_t                    urr_id;
//    ur_seqn_t                   ur_seqn;
//    usage_report_trigger_t      usage_report_trigger;
//    start_time_t                start_time;
//    end_time_t                  end_time;
//    volume_measurement_t        volume_measurement;
//    duration_measurement_t      duration_measurement;
//    application_detection_information_t application_detection_information;
//    ue_ip_address_t             ue_ip_address;
//    network_instance_t          network_instance;
//    time_of_first_packet_t      time_of_first_packet;
//    time_of_last_packet_t       time_of_last_packet;
//    usage_information_t         usage_information;
//    query_urr_reference_t       query_urr_reference;
//    event_reporting_t           event_reporting;
//    ethernet_traffic_information_t ethernet_traffic_information;
//  } usage_report_within_pfcp_session_report_request_t;
//
//  // Table 7.5.8.4-1: Error Indication Report IE within PFCP Session Report Request
//  typedef struct error_indication_report_s {
//    fteid_t                     remote_fteid;
//  } error_indication_report_t;
//
//  // Table 7.5.9.2-1: Update BAR IE in PFCP Session Report Response
//  typedef struct update_bar_within_pfcp_session_report_response_s {
//    bar_id_t                              bar_id;
//    downlink_data_notification_delay_t    downlink_data_notification_delay;
//    dl_buffering_duration_t               dl_buffering_duration;
//    dl_buffering_suggested_packet_count_t dl_buffering_buffering_suggested_packet_count;
//    suggested_buffering_packets_count_t   suggested_buffering_packets_count;
//  } update_bar_within_pfcp_session_report_response_t;
}

namespace std {

template<>
struct hash<pfcp::fseid_t> {

  std::size_t operator()(const pfcp::fseid_t &k) const {
    using std::size_t;
    using std::hash;
    std::size_t h;
    if (k.v4) {
      h = k.ipv4_address.s_addr ^ (k.seid);
      return h;
    }
    if (k.v6) {
      h = k.seid
          ^ (k.ipv6_address.s6_addr32[0] ^ k.ipv6_address.s6_addr32[1]
              ^ k.ipv6_address.s6_addr32[2] ^ k.ipv6_address.s6_addr32[3]);
      return h;
    }
    return k.seid;

  }
};

template<>
class hash<pfcp::node_id_t> {
 public:
  size_t operator()(const pfcp::node_id_t &k) const {
    using std::size_t;
    using std::hash;
    std::size_t h = 0;
    switch (k.node_id_type) {
      case pfcp::NODE_ID_TYPE_IPV4_ADDRESS:
        h = std::hash<uint32_t>()(k.u1.ipv4_address.s_addr);
        return h;
        break;
      case pfcp::NODE_ID_TYPE_IPV6_ADDRESS:
        h = k.u1.ipv6_address.s6_addr32[0] ^ k.u1.ipv6_address.s6_addr32[1]
            ^ k.u1.ipv6_address.s6_addr32[2] ^ k.u1.ipv6_address.s6_addr32[3];
        return h;
        break;
      case pfcp::NODE_ID_TYPE_FQDN:
        h = std::hash<std::string>()(k.fqdn);
        return h;
      default:
        return h;
    }
  }
};
}
#endif /* FILE_3GPP_129_244_H_SEEN */
