/*
 * 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_QUOTA (148)
#define PFCP_IE_EVENT_THRESHOLD (149)
#define PFCP_IE_SUBSEQUENT_EVENT_QUOTA (150)
#define PFCP_IE_SUBSEQUENT_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_IE_EVENT_TIME_STAMP (156)
#define PFCP_IE_AVERAGING_WINDOW (157)
#define PFCP_IE_PAGING_POLICY_INDICATOR (158)
#define PFCP_IE_APN_DNN (159)
#define PFCP_IE_3GPP_INTERFACE_TYPE (160)

#define PFCP_IE_PFCPSRREQ_FLAGS_3GPP (161)
#define PFCP_IE_PFCPAUREQ_FLAGS (162)
#define PFCP_IE_ACTIVATION_TIME (163)
#define PFCP_IE_DEACTIVATION_TIME (164)
#define PFCP_IE_CREATE_MAR (165)
#define PFCP_IE_ACCESS_FORWARDING_ACTION_INFORMATION_1 (166)
#define PFCP_IE_ACCESS_FORWARDING_ACTION_INFORMATION_2 (167)
#define PFCP_IE_REMOVE_MAR (168)
#define PFCP_IE_UPDATE_MAR (169)
#define PFCP_IE_MAR_ID (170)
#define PFCP_IE_STEERING_FUNCTIONALITY (171)
#define PFCP_IE_STEERING_MODE (172)
#define PFCP_IE_WEIGHT (173)
#define PFCP_IE_PRIORITY (174)
#define PFCP_IE_UPDATE_ACCESS_FORWARDING_ACTION_INFORMATION_1 (175)
#define PFCP_IE_UPDATE_ACCESS_FORWARDING_ACTION_INFORMATION_2 (176)
#define PFCP_IE_UE_IP_ADDRESS_POOL_IDENTITY (177)
#define PFCP_IE_ALTERNATIVE_SMF_IP_ADDRESS (178)
#define PFCP_IE_SPARED (179)

#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

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,
  CAUSE_VALUE_REDIRECTION_REQUESTED              = 78
};

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 v6 : 1;
  uint8_t v4 : 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 operator=(const struct fteid_s& f) {
    v4                  = f.v4;
    v6                  = f.v6;
    chid                = f.chid;
    ch                  = f.ch;
    choose_id           = f.choose_id;
    teid                = f.teid;
    ipv4_address.s_addr = f.ipv4_address.s_addr;
    ipv6_address        = f.ipv6_address;
    // ipv6_address.s6_addr32[0] = f.ipv6_address.s6_addr32[0];
    // ipv6_address.s6_addr32[1] = f.ipv6_address.s6_addr32[1];
    // ipv6_address.s6_addr32[2] = f.ipv6_address.s6_addr32[2];
    // ipv6_address.s6_addr32[3] = f.ipv6_address.s6_addr32[3];
  }

  std::string toString() const {
    std::string s = {};
    if ((v4) || (v6)) {
      s.append("TEID=").append(std::to_string(teid));
      if (v4) {
        s.append(", IPv4=").append(conv::toString(ipv4_address));
      }
      if (v6) {
        s.append(", IPv6=").append(conv::toString(ipv6_address));
      }
    } else {
      s.append("null_fteid");
    }
    return s;
  }

  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 pdu_session_type_value_e {
  /* Request / Initial message */
  IPV4     = 1,
  IPV6     = 2,
  IPV4V6   = 3,
  NON_IP   = 4,
  ETHERNET = 5
};

typedef struct pdu_session_type_s {
  uint8_t spare : 5;
  uint8_t pdu_session_type : 3;
} pdu_session_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 Subsequent Event Quota
typedef struct subsequent_event_quota_s {
  uint32_t subsequent_event_quota;
} subsequent_event_quota_t;

//-------------------------------------
// 8.2.107 Subsequent Event Threshold
typedef struct subsequent_event_threshold_s {
  uint32_t subsequent_event_threshold;
} subsequent_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;

//-------------------------------------
// TO BE REMOVED: 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.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;

//-------------------------------------
// 8.2.112 Event Quota
typedef struct event_quota_s {
  uint32_t event_quota;
} event_quota_t;

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

//-------------------------------------
// 8.2.114 Event Time Stamp
typedef struct event_time_stamp_s {
  uint32_t event_time_stamp;
} event_time_stamp_t;

//-------------------------------------
// 8.2.115 Averaging Window
typedef struct averaging_window_s {
  uint32_t averaging_window;
} averaging_window_t;

//-------------------------------------
// 8.2.116 Paging Policy Indicator (PPI)
typedef struct paging_policy_indicator_s {
  uint8_t spare : 4;
  uint8_t ppi_value : 4;
} paging_policy_indicator_t;

//-------------------------------------
// 8.2.117 APN/DNN
typedef struct apn_dnn_s {
  std::string apn_dnn;
} apn_dnn_t;

//-------------------------------------
// 8.2.118. 3GPP Interface Type
enum _3gpp_interface_type_e {
  _3GPP_INTERFACE_TYPE_S1_U                         = 0,
  _3GPP_INTERFACE_TYPE_S5_S8_U                      = 1,
  _3GPP_INTERFACE_TYPE_S4_U                         = 2,
  _3GPP_INTERFACE_TYPE_S11_U                        = 3,
  _3GPP_INTERFACE_TYPE_S12_U                        = 4,
  _3GPP_INTERFACE_TYPE_GN_GP_U                      = 5,
  _3GPP_INTERFACE_TYPE_S2A_U                        = 6,
  _3GPP_INTERFACE_TYPE_S2B_U                        = 7,
  _3GPP_INTERFACE_TYPE_ENODEB_GTP_U_DL              = 8,
  _3GPP_INTERFACE_TYPE_ENODEB_GTP_U_UL              = 9,
  _3GPP_INTERFACE_TYPE_SGW_UPF_GTP_U_DL             = 10,
  _3GPP_INTERFACE_TYPE_N3_3GPP_ACCESS               = 11,
  _3GPP_INTERFACE_TYPE_N3_TRUSTED_NON_3GPP_ACCESS   = 12,
  _3GPP_INTERFACE_TYPE_N3_UNTRUSTED_NON_3GPP_ACCESS = 13,
  _3GPP_INTERFACE_TYPE_N3                           = 14,
  _3GPP_INTERFACE_TYPE_N9                           = 15
};

typedef struct _3gpp_interface_type_s {
  uint8_t spare : 2;
  uint8_t interface_type_value : 6;
} _3gpp_interface_type_t;

//-------------------------------------
// 8.2.119 PFCPSRReq-Flags
typedef struct pfcpsrreq_flags_s {
  uint8_t spare : 7;
  uint8_t psdbu : 1;
} pfcpsrreq_flags_t;

//-------------------------------------
// 8.2.120 PFCPAUReq-Flags
typedef struct pfcpaureq_flags_s {
  uint8_t spare : 7;
  uint8_t parps : 1;
} pfcpaureq_flags_t;

//-------------------------------------
// 8.2.121 Activation Time
typedef struct activation_time_s {
  uint32_t activation_time;
} activation_time_t;

//-------------------------------------
// 8.2.122 Deactivation Time
typedef struct deactivation_time_s {
  uint32_t deactivation_time;
} deactivation_time_t;

//-------------------------------------
// 8.2.123 MAR ID
typedef struct mar_id_s {
  uint8_t mar_id;
} mar_id_t;

//-------------------------------------
// 8.2.124 Steering Functionality
typedef struct steering_functionality_s {
  uint8_t spare : 4;
  uint8_t steering_functionality_value : 4;
} steering_functionality_t;

enum steering_functionality_value_e {
  STEERING_FUNCTIONALITY_ATSSS_LL = 0,
  STEERING_FUNCTIONALITY_MPTCP    = 1,
  STEERING_FUNCTIONALITY_SPARE    = 2
};

//-------------------------------------
// 8.2.125 Steering Mode
typedef struct steering_mode_s {
  uint8_t spare : 4;
  uint8_t steering_mode_value : 4;
} steering_mode_t;

enum steering_mode_value_e {
  STEERING_MODE_ACTIVE_STANDBY = 0,
  STEERING_MODE_SMALLEST_DELAY = 1,
  STEERING_MODE_LOAD_BALANCING = 2,
  STEERING_MODE_PRIORITY_BASED = 3,
  STEERING_MODE_SPARED         = 4
};

//-------------------------------------
// 8.2.126 Weight
typedef struct weight_s {
  uint8_t weight_value;
} weight_t;

//-------------------------------------
// 8.2.127 Priority
typedef struct priority_s {
  uint8_t spare : 4;
  uint8_t priority_value : 4;
} priority_t;
enum priority_value_e {
  PRIORITY_VALUE_ACTIVE  = 0,
  PRIORITY_VALUE_STANDBY = 1,
  PRIORITY_VALUE_HIGH    = 2,
  PRIORITY_VALUE_LOW     = 3,
  PRIORITY_VALUE_SPARED  = 4
};

//-------------------------------------
// 8.2.128 UE IP address Pool Identity
typedef struct ue_ip_address_pool_identity_s {
  std::string ue_ip_address_pool_identity;
} ue_ip_address_pool_identity_t;

//-------------------------------------
// 8.2.129 Alternative SMF IP Address
typedef struct alternative_smf_ip_address_s {
  uint8_t spare : 6;
  uint8_t v4 : 1;
  uint8_t v6 : 1;
  struct in_addr ipv4_address;
  struct in6_addr ipv6_address;
} alternative_smf_ip_address_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 pfcp

namespace std {

template<>
struct hash<pfcp::fseid_t> {
  std::size_t operator()(const pfcp::fseid_t& k) const {
    using std::hash;
    using std::size_t;
    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::hash;
    using std::size_t;
    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;
    }
  }
};
}  // namespace std
#endif /* FILE_3GPP_129_244_H_SEEN */
