Files
open5gs/lib/pfcp/context.h
Pau Espin Pedrol dd5abb79b4 [PFCP] Fix wrong endianess enc of some URR values (#1433)
* [PFCP] Fix trailing whitespace

* [PFCP] Fix wrong endianess enc of some URR values

u32 tlvs are already converted to big endian automatically. Manually
doing so ends up in double conversion and hence in wrong endianness
being sent over the wire.
Similar issue was also fixed recently in the PFCP decoding path.
Related: https://github.com/open5gs/open5gs/issues/1349
2022-03-15 13:34:22 +09:00

468 lines
14 KiB
C

/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#if !defined(OGS_PFCP_INSIDE) && !defined(OGS_PFCP_COMPILATION)
#error "This header cannot be included directly."
#endif
#ifndef OGS_PFCP_CONTEXT_H
#define OGS_PFCP_CONTEXT_H
#ifdef __cplusplus
extern "C" {
#endif
#define OGS_PFCP_DEFAULT_PDR_PRECEDENCE 255
#define OGS_PFCP_INDIRECT_PDR_PRECEDENCE 1
#define OGS_PFCP_UP2CP_PDR_PRECEDENCE 1
#define OGS_PFCP_CP2UP_PDR_PRECEDENCE 1000
#define OGS_PFCP_DEFAULT_CHOOSE_ID 5
#define OGS_PFCP_INDIRECT_DATA_FORWARDING_CHOOSE_ID 10
#define OGS_MAX_NUM_OF_DEV 16
#define OGS_MAX_NUM_OF_SUBNET 16
typedef struct ogs_pfcp_node_s ogs_pfcp_node_t;
typedef struct ogs_pfcp_context_s {
uint32_t pfcp_port; /* PFCP local port */
const char *tun_ifname; /* PFCP TUN Interface Name */
ogs_list_t pfcp_list; /* PFCP IPv4 Server List */
ogs_list_t pfcp_list6; /* PFCP IPv6 Server List */
ogs_sock_t *pfcp_sock; /* PFCP IPv4 Socket */
ogs_sock_t *pfcp_sock6; /* PFCP IPv6 Socket */
ogs_sockaddr_t *pfcp_addr; /* PFCP IPv4 Address */
ogs_sockaddr_t *pfcp_addr6; /* PFCP IPv6 Address */
uint32_t pfcp_started; /* UTC time when the PFCP entity started */
/* CP Function Features */
ogs_pfcp_cp_function_features_t cp_function_features;
/* UP Function Features */
ogs_pfcp_up_function_features_t up_function_features;
int up_function_features_len;
ogs_list_t pfcp_peer_list; /* PFCP Node List */
ogs_pfcp_node_t *pfcp_node; /* Iterator for Peer round-robin */
ogs_list_t dev_list; /* Tun Device List */
ogs_list_t subnet_list; /* UE Subnet List */
ogs_hash_t *object_teid_hash; /* hash table for PFCP OBJ(TEID) */
ogs_hash_t *far_f_teid_hash; /* hash table for FAR(TEID+ADDR) */
ogs_hash_t *far_teid_hash; /* hash table for FAR(TEID) */
} ogs_pfcp_context_t;
#define OGS_SETUP_PFCP_NODE(__cTX, __pNODE) \
do { \
ogs_assert((__cTX)); \
ogs_assert((__pNODE)); \
(__cTX)->pfcp_node = __pNODE; \
} while(0)
typedef struct ogs_pfcp_node_s {
ogs_lnode_t lnode; /* A node of list_t */
ogs_sockaddr_t *sa_list; /* Socket Address List Candidate */
ogs_sock_t *sock; /* Socket Instance */
ogs_sockaddr_t addr; /* Remote Address */
ogs_list_t local_list;
ogs_list_t remote_list;
ogs_fsm_t sm; /* A state machine */
ogs_timer_t *t_association; /* timer to retry to associate peer node */
ogs_timer_t *t_no_heartbeat; /* heartbeat timer to check aliveness */
uint16_t tac[OGS_MAX_NUM_OF_TAI];
uint8_t num_of_tac;
const char* dnn[OGS_MAX_DNN_LEN+1];
uint8_t num_of_dnn;
uint32_t e_cell_id[OGS_MAX_NUM_OF_CELL_ID];
uint8_t num_of_e_cell_id;
uint64_t nr_cell_id[OGS_MAX_NUM_OF_CELL_ID];
uint8_t num_of_nr_cell_id;
/* flag to enable/ disable full list RR for this node */
uint8_t rr_enable;
ogs_list_t gtpu_resource_list; /* User Plane IP Resource Information */
ogs_pfcp_up_function_features_t up_function_features;
int up_function_features_len;
} ogs_pfcp_node_t;
typedef enum {
OGS_PFCP_OBJ_BASE = 0,
OGS_PFCP_OBJ_SESS_TYPE,
OGS_PFCP_OBJ_PDR_TYPE,
OGS_PFCP_OBJ_TOP,
} ogs_pfcp_object_type_e;
typedef struct ogs_pfcp_object_s {
ogs_lnode_t lnode;
ogs_pfcp_object_type_e type;
} ogs_pfcp_object_t;
typedef struct ogs_pfcp_sess_s ogs_pfcp_sess_t;
typedef struct ogs_pfcp_pdr_s ogs_pfcp_pdr_t;
typedef struct ogs_pfcp_far_s ogs_pfcp_far_t;
typedef struct ogs_pfcp_urr_s ogs_pfcp_urr_t;
typedef struct ogs_pfcp_qer_s ogs_pfcp_qer_t;
typedef struct ogs_pfcp_bar_s ogs_pfcp_bar_t;
typedef struct ogs_pfcp_pdr_s {
ogs_pfcp_object_t obj;
uint32_t index;
struct {
struct {
int len;
uint32_t key;
} teid;
} hash;
uint8_t *id_node; /* Pool-Node for ID */
ogs_pfcp_pdr_id_t id;
ogs_pfcp_precedence_t precedence;
ogs_pfcp_interface_t src_if;
union {
char *apn;
char *dnn;
};
ogs_pfcp_ue_ip_addr_t ue_ip_addr;
int ue_ip_addr_len;
ogs_pfcp_f_teid_t f_teid;
int f_teid_len;
bool chid;
uint8_t choose_id;
ogs_pfcp_outer_header_removal_t outer_header_removal;
int outer_header_removal_len;
uint8_t qfi;
ogs_pfcp_far_t *far;
ogs_pfcp_urr_t *urr;
ogs_pfcp_qer_t *qer;
int num_of_flow;
char *flow_description[OGS_MAX_NUM_OF_FLOW_IN_PDR];
ogs_list_t rule_list; /* Rule List */
/* Related Context */
ogs_pfcp_sess_t *sess;
void *gnode; /* For CP-Function */
} ogs_pfcp_pdr_t;
typedef struct ogs_pfcp_far_hash_f_teid_s {
uint32_t teid;
uint32_t addr[4];
} ogs_pfcp_far_hash_f_teid_t;
typedef struct ogs_pfcp_far_s {
ogs_lnode_t lnode;
struct {
struct {
int len;
ogs_pfcp_far_hash_f_teid_t key;
} f_teid;
struct {
int len;
uint32_t key;
} teid;
} hash;
uint8_t *id_node; /* Pool-Node for ID */
ogs_pfcp_far_id_t id;
ogs_pfcp_apply_action_t apply_action;
ogs_pfcp_interface_t dst_if;
ogs_pfcp_outer_header_creation_t outer_header_creation;
int outer_header_creation_len;
ogs_pfcp_smreq_flags_t smreq_flags;
uint32_t num_of_buffered_packet;
ogs_pkbuf_t *buffered_packet[OGS_MAX_NUM_OF_PACKET_BUFFER];
struct {
bool prepared;
} handover; /* Saved from N2-Handover Request Acknowledge */
/* Related Context */
ogs_pfcp_sess_t *sess;
void *gnode;
} ogs_pfcp_far_t;
typedef struct ogs_pfcp_urr_s {
ogs_lnode_t lnode;
uint8_t *id_node; /* Pool-Node for ID */
ogs_pfcp_urr_id_t id;
ogs_pfcp_measurement_method_t meas_method;
ogs_pfcp_reporting_triggers_t rep_triggers;
ogs_pfcp_measurement_period_t meas_period;
ogs_pfcp_volume_threshold_t vol_threshold;
ogs_pfcp_volume_quota_t vol_quota;
ogs_pfcp_event_threshold_t event_threshold;
ogs_pfcp_event_quota_t event_quota;
ogs_pfcp_time_threshold_t time_threshold;
ogs_pfcp_time_quota_t time_quota;
ogs_pfcp_quota_holding_time_t quota_holding_time;
ogs_pfcp_dropped_dl_traffic_threshold_t dropped_dl_traffic_threshold;
ogs_pfcp_quota_validity_time_t quota_validity_time;
ogs_pfcp_sess_t *sess;
} ogs_pfcp_urr_t;
typedef struct ogs_pfcp_qer_s {
ogs_lnode_t lnode;
uint8_t *id_node; /* Pool-Node for ID */
ogs_pfcp_qer_id_t id;
ogs_pfcp_gate_status_t gate_status;
ogs_pfcp_bitrate_t mbr;
ogs_pfcp_bitrate_t gbr;
uint8_t qfi;
ogs_pfcp_sess_t *sess;
} ogs_pfcp_qer_t;
typedef struct ogs_pfcp_bar_s {
ogs_lnode_t lnode;
uint8_t *id_node; /* Pool-Node for ID */
ogs_pfcp_bar_id_t id;
ogs_pfcp_sess_t *sess;
} ogs_pfcp_bar_t;
typedef struct ogs_pfcp_sess_s {
ogs_pfcp_object_t obj;
ogs_list_t pdr_list; /* PDR List */
ogs_list_t far_list; /* FAR List */
ogs_list_t urr_list; /* URR List */
ogs_list_t qer_list; /* QER List */
ogs_pfcp_bar_t *bar; /* BAR Item */
OGS_POOL(pdr_id_pool, uint8_t);
OGS_POOL(far_id_pool, uint8_t);
OGS_POOL(urr_id_pool, uint8_t);
OGS_POOL(qer_id_pool, uint8_t);
OGS_POOL(bar_id_pool, uint8_t);
} ogs_pfcp_sess_t;
typedef struct ogs_pfcp_subnet_s ogs_pfcp_subnet_t;
typedef struct ogs_pfcp_ue_ip_s {
uint32_t addr[4];
bool static_ip;
/* Related Context */
ogs_pfcp_subnet_t *subnet;
} ogs_pfcp_ue_ip_t;
typedef struct ogs_pfcp_dev_s {
ogs_lnode_t lnode;
char ifname[OGS_MAX_IFNAME_LEN];
ogs_socket_t fd;
ogs_poll_t *poll;
bool is_tap;
uint8_t mac_addr[6];
} ogs_pfcp_dev_t;
typedef struct ogs_pfcp_subnet_s {
ogs_lnode_t lnode;
ogs_ipsubnet_t sub; /* Subnet : 2001:db8:cafe::0/48 */
ogs_ipsubnet_t gw; /* Gateway : 2001:db8:cafe::1 */
char dnn[OGS_MAX_DNN_LEN+1]; /* DNN : "internet", "volte", .. */
#define OGS_MAX_NUM_OF_SUBNET_RANGE 16
struct {
const char *low;
const char *high;
} range[OGS_MAX_NUM_OF_SUBNET_RANGE];
int num_of_range;
int family; /* AF_INET or AF_INET6 */
uint8_t prefixlen; /* prefixlen */
OGS_POOL(pool, ogs_pfcp_ue_ip_t);
ogs_pfcp_dev_t *dev; /* Related Context */
} ogs_pfcp_subnet_t;
typedef struct ogs_pfcp_rule_s {
ogs_lnode_t lnode;
union {
struct {
ED6(uint8_t spare1:3;,
uint8_t bid:1;,
uint8_t fl:1;,
uint8_t spi:1;,
uint8_t ttc:1;,
uint8_t fd:1;)
};
uint8_t flags;
};
ogs_ipfw_rule_t ipfw;
uint32_t sdf_filter_id;
/* Related Context */
ogs_pfcp_pdr_t *pdr;
} ogs_pfcp_rule_t;
void ogs_pfcp_context_init(void);
void ogs_pfcp_context_final(void);
ogs_pfcp_context_t *ogs_pfcp_self(void);
int ogs_pfcp_context_parse_config(const char *local, const char *remote);
ogs_pfcp_node_t *ogs_pfcp_node_new(ogs_sockaddr_t *sa_list);
void ogs_pfcp_node_free(ogs_pfcp_node_t *node);
ogs_pfcp_node_t *ogs_pfcp_node_add(
ogs_list_t *list, ogs_sockaddr_t *addr);
ogs_pfcp_node_t *ogs_pfcp_node_find(
ogs_list_t *list, ogs_sockaddr_t *addr);
void ogs_pfcp_node_remove(ogs_list_t *list, ogs_pfcp_node_t *node);
void ogs_pfcp_node_remove_all(ogs_list_t *list);
ogs_gtpu_resource_t *ogs_pfcp_find_gtpu_resource(ogs_list_t *list,
char *dnn, ogs_pfcp_interface_t source_interface);
int ogs_pfcp_setup_far_gtpu_node(ogs_pfcp_far_t *far);
int ogs_pfcp_setup_pdr_gtpu_node(ogs_pfcp_pdr_t *pdr);
void ogs_pfcp_sess_clear(ogs_pfcp_sess_t *sess);
ogs_pfcp_pdr_t *ogs_pfcp_pdr_add(ogs_pfcp_sess_t *sess);
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find(
ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id);
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_or_add(
ogs_pfcp_sess_t *sess, ogs_pfcp_pdr_id_t id);
void ogs_pfcp_object_teid_hash_set(
ogs_pfcp_object_type_e type, ogs_pfcp_pdr_t *pdr);
ogs_pfcp_object_t *ogs_pfcp_object_find_by_teid(uint32_t teid);
ogs_pfcp_pdr_t *ogs_pfcp_pdr_find_by_choose_id(
ogs_pfcp_sess_t *sess, uint8_t choose_id);
void ogs_pfcp_pdr_reorder_by_precedence(
ogs_pfcp_pdr_t *pdr, ogs_pfcp_precedence_t precedence);
void ogs_pfcp_pdr_associate_far(ogs_pfcp_pdr_t *pdr, ogs_pfcp_far_t *far);
void ogs_pfcp_pdr_associate_urr(ogs_pfcp_pdr_t *pdr, ogs_pfcp_urr_t *urr);
void ogs_pfcp_pdr_associate_qer(ogs_pfcp_pdr_t *pdr, ogs_pfcp_qer_t *qer);
void ogs_pfcp_pdr_remove(ogs_pfcp_pdr_t *pdr);
void ogs_pfcp_pdr_remove_all(ogs_pfcp_sess_t *sess);
ogs_pfcp_far_t *ogs_pfcp_far_add(ogs_pfcp_sess_t *sess);
ogs_pfcp_far_t *ogs_pfcp_far_find(
ogs_pfcp_sess_t *sess, ogs_pfcp_far_id_t id);
ogs_pfcp_far_t *ogs_pfcp_far_find_or_add(
ogs_pfcp_sess_t *sess, ogs_pfcp_far_id_t id);
void ogs_pfcp_far_f_teid_hash_set(ogs_pfcp_far_t *far);
ogs_pfcp_far_t *ogs_pfcp_far_find_by_error_indication(ogs_pkbuf_t *pkbuf);
void ogs_pfcp_far_teid_hash_set(ogs_pfcp_far_t *far);
ogs_pfcp_far_t *ogs_pfcp_far_find_by_teid(uint32_t teid);
void ogs_pfcp_far_remove(ogs_pfcp_far_t *far);
void ogs_pfcp_far_remove_all(ogs_pfcp_sess_t *sess);
ogs_pfcp_urr_t *ogs_pfcp_urr_add(ogs_pfcp_sess_t *sess);
ogs_pfcp_urr_t *ogs_pfcp_urr_find(
ogs_pfcp_sess_t *sess, ogs_pfcp_urr_id_t id);
ogs_pfcp_urr_t *ogs_pfcp_urr_find_or_add(
ogs_pfcp_sess_t *sess, ogs_pfcp_urr_id_t id);
void ogs_pfcp_urr_remove(ogs_pfcp_urr_t *urr);
void ogs_pfcp_urr_remove_all(ogs_pfcp_sess_t *sess);
ogs_pfcp_qer_t *ogs_pfcp_qer_add(ogs_pfcp_sess_t *sess);
ogs_pfcp_qer_t *ogs_pfcp_qer_find(
ogs_pfcp_sess_t *sess, ogs_pfcp_qer_id_t id);
ogs_pfcp_qer_t *ogs_pfcp_qer_find_or_add(
ogs_pfcp_sess_t *sess, ogs_pfcp_qer_id_t id);
void ogs_pfcp_qer_remove(ogs_pfcp_qer_t *qer);
void ogs_pfcp_qer_remove_all(ogs_pfcp_sess_t *sess);
ogs_pfcp_bar_t *ogs_pfcp_bar_new(ogs_pfcp_sess_t *sess);
void ogs_pfcp_bar_delete(ogs_pfcp_bar_t *bar);
ogs_pfcp_rule_t *ogs_pfcp_rule_add(ogs_pfcp_pdr_t *pdr);
ogs_pfcp_rule_t *ogs_pfcp_rule_find_by_sdf_filter_id(
ogs_pfcp_sess_t *sess, uint32_t sdf_filter_id);
void ogs_pfcp_rule_remove(ogs_pfcp_rule_t *rule);
void ogs_pfcp_rule_remove_all(ogs_pfcp_pdr_t *pdr);
int ogs_pfcp_ue_pool_generate(void);
ogs_pfcp_ue_ip_t *ogs_pfcp_ue_ip_alloc(
uint8_t *cause_value, int family, const char *dnn, uint8_t *addr);
void ogs_pfcp_ue_ip_free(ogs_pfcp_ue_ip_t *ip);
ogs_pfcp_dev_t *ogs_pfcp_dev_add(const char *ifname);
void ogs_pfcp_dev_remove(ogs_pfcp_dev_t *dev);
void ogs_pfcp_dev_remove_all(void);
ogs_pfcp_dev_t *ogs_pfcp_dev_find_by_ifname(const char *ifname);
ogs_pfcp_subnet_t *ogs_pfcp_subnet_add(
const char *ipstr, const char *mask_or_numbits,
const char *dnn, const char *ifname);
ogs_pfcp_subnet_t *ogs_pfcp_subnet_next(ogs_pfcp_subnet_t *subnet);
void ogs_pfcp_subnet_remove(ogs_pfcp_subnet_t *subnet);
void ogs_pfcp_subnet_remove_all(void);
ogs_pfcp_subnet_t *ogs_pfcp_find_subnet(int family);
ogs_pfcp_subnet_t *ogs_pfcp_find_subnet_by_dnn(int family, const char *dnn);
void ogs_pfcp_pool_init(ogs_pfcp_sess_t *sess);
void ogs_pfcp_pool_final(ogs_pfcp_sess_t *sess);
#ifdef __cplusplus
}
#endif
#endif /* OGS_PFCP_CONTEXT_H */