blob: afdbebe623c0b5200a12bdeaf88ca9c542480685 [file] [log] [blame]
/*
**************************************************************************
* Copyright (c) 2014,2015,2017-2020 The Linux Foundation. All rights reserved.
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all copies.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**************************************************************************
*/
/*
* Listener
* Listeners are entities that monitor database events
*/
struct ecm_db_listener_instance;
typedef void (*ecm_db_listener_final_callback_t)(void *arg); /* Finaliser callback */
/*
* Interface
* An interface represents an interface of this device to which nodes may be reached
*/
struct ecm_db_iface_instance;
/*
* Node
* A node instance is the ethernet representation of the host, i.e. the mac address to send packets to when reaching the host
*/
struct ecm_db_node_instance;
/*
* Host
* A host instance identifies a node by IP address
*/
struct ecm_db_host_instance;
/*
* Host owner events
*/
typedef void (*ecm_db_host_final_callback_t)(void *arg); /* Finaliser callback */
/*
* Host listener events
*/
typedef void (*ecm_db_host_listener_added_callback_t)(void *arg, struct ecm_db_host_instance *hi); /* Added callback */
typedef void (*ecm_db_host_listener_removed_callback_t)(void *arg, struct ecm_db_host_instance *hi); /* Removed callback */
/*
* Mapping
* A mapping defines a port number. Non-port based protocols will use -1 so they will all share to the same mapping instance.
*/
struct ecm_db_mapping_instance;
/*
* Mapping owner events
*/
typedef void (*ecm_db_mapping_final_callback_t)(void *arg); /* Finaliser callback */
/*
* Mapping listener events
*/
typedef void (*ecm_db_mapping_listener_added_callback_t)(void *arg, struct ecm_db_mapping_instance *mi); /* Added callback */
typedef void (*ecm_db_mapping_listener_removed_callback_t)(void *arg, struct ecm_db_mapping_instance *mi); /* Removed callback */
/*
* Node
*/
typedef void (*ecm_db_node_final_callback_t)(void *arg); /* Finaliser callback */
typedef void (*ecm_db_node_listener_added_callback_t)(void *arg, struct ecm_db_node_instance *ni); /* Added callback */
typedef void (*ecm_db_node_listener_removed_callback_t)(void *arg, struct ecm_db_node_instance *ni); /* Removed callback */
/*
* Interface
*/
typedef void (*ecm_db_iface_final_callback_t)(void *arg); /* Finaliser callback */
typedef void (*ecm_db_iface_listener_added_callback_t)(void *arg, struct ecm_db_iface_instance *ii); /* Added callback */
typedef void (*ecm_db_iface_listener_removed_callback_t)(void *arg, struct ecm_db_iface_instance *ii); /* Removed callback */
/*
* Time out values - in seconds - used to configure timer groups
*/
#define ECM_DB_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT 5
#define ECM_DB_CONNECTION_GENERIC_TIMEOUT 240
#define ECM_DB_CONNECTION_TCP_RST_TIMEOUT 240
#define ECM_DB_CONNECTION_TCP_SHORT_TIMEOUT 240
#define ECM_DB_CONNECTION_TCP_CLOSED_TIMEOUT 10
#define ECM_DB_CONNECTION_TCP_LONG_TIMEOUT 3600
#define ECM_DB_CONNECTION_UDP_TIMEOUT 300
#define ECM_DB_CONNECTION_IGMP_TIMEOUT 240
#define ECM_DB_CONNECTION_ICMP_TIMEOUT 60
#define ECM_DB_CONNECTION_PPTP_DATA_TIMEOUT 300
#define ECM_DB_CONNECTION_RTCP_TIMEOUT 1800
#define ECM_DB_CONNECTION_RTSP_FAST_TIMEOUT 5
#define ECM_DB_CONNECTION_RTSP_SLOW_TIMEOUT 120
#define ECM_DB_CONNECTION_DNS_TIMEOUT 30
#define ECM_DB_CONNECTION_FTP_TIMEOUT 60
#define ECM_DB_CONNECTION_H323_TIMEOUT 28800
#define ECM_DB_CONNECTION_IKE_TIMEOUT 54000
#define ECM_DB_CONNECTION_ESP_TIMEOUT 7800
#define ECM_DB_CONNECTION_ESP_PENDING_TIMEOUT 3
#define ECM_DB_CONNECTION_SDP_TIMEOUT 120
#define ECM_DB_CONNECTION_SIP_TIMEOUT 28800
#define ECM_DB_CONNECTION_BITTORRENT_TIMEOUT 120
#define ECM_DB_CONNECTION_DEFUNCT_RETRY_TIMEOUT 5
/*
* ECM database object direction.
*/
enum ecm_db_obj_dir {
ECM_DB_OBJ_DIR_FROM,
ECM_DB_OBJ_DIR_TO,
ECM_DB_OBJ_DIR_FROM_NAT,
ECM_DB_OBJ_DIR_TO_NAT,
ECM_DB_OBJ_DIR_MAX
};
typedef enum ecm_db_obj_dir ecm_db_obj_dir_t;
/*
* Extern decleration of common array that maps
* the object direction to a string.
*/
extern char *ecm_db_obj_dir_strings[ECM_DB_OBJ_DIR_MAX];
/*
* Timer groups.
* WARNING: Only connections may use a connection timer group as these are subject to reaping.
*/
enum ecm_db_timer_groups {
ECM_DB_TIMER_GROUPS_CLASSIFIER_DETERMINE_GENERIC_TIMEOUT = 0,
/* Generic timeout for a classifier in determine phase */
ECM_DB_TIMER_GROUPS_CONNECTION_GENERIC_TIMEOUT, /* Generic timeout for a connection */
ECM_DB_TIMER_GROUPS_CONNECTION_UDP_GENERIC_TIMEOUT, /* Standard UDP Timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_UDP_WKP_TIMEOUT, /* Standard UDP Timeout for all connections where at least one port is < 1024 */
ECM_DB_TIMER_GROUPS_CONNECTION_ICMP_TIMEOUT, /* Standard ICMP Timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_TCP_SHORT_TIMEOUT, /* TCP Short timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_TCP_RESET_TIMEOUT, /* TCP Reset timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_TCP_CLOSED_TIMEOUT, /* TCP Closed timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_TCP_LONG_TIMEOUT, /* TCP Long timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_PPTP_DATA_TIMEOUT, /* PPTP Tunnel Data timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_RTCP_TIMEOUT, /* RTCP timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_TIMEOUT, /* RTSP connection timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_FAST_TIMEOUT, /* RTSP fast static NAT connection timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_RTSP_SLOW_TIMEOUT, /* RTSP slow static NAT connection timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_DNS_TIMEOUT, /* DNS timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_FTP_TIMEOUT, /* FTP connection timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_H323_TIMEOUT, /* H323 timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_IKE_TIMEOUT, /* IKE timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_ESP_TIMEOUT, /* ESP timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_ESP_PENDING_TIMEOUT, /* ESP Pending connection timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_SDP_TIMEOUT, /* SDP timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_SIP_TIMEOUT, /* SIP timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_IGMP_TIMEOUT, /* IGMP timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_BITTORRENT_TIMEOUT, /* Bittorrent connections timeout */
ECM_DB_TIMER_GROUPS_CONNECTION_DEFUNCT_RETRY_TIMEOUT, /* Defunct retry timeout */
ECM_DB_TIMER_GROUPS_MAX /* Always the last one */
};
typedef enum ecm_db_timer_groups ecm_db_timer_group_t;
typedef void (*ecm_db_timer_group_entry_callback_t)(void *arg); /* Timer entry has expired */
/*
* Ignore IP version check in connection instance
*/
#define ECM_DB_IP_VERSION_IGNORE 0
#ifdef ECM_MULTICAST_ENABLE
struct ecm_db_multicast_tuple_instance;
/*
* Need to set this flag when Multicast is attached to ci and added to tuple hash table
*/
#define ECM_DB_MULTICAST_TUPLE_INSTANCE_FLAGS_INSERTED 0x1
/*
* This flag is used to find out whether a bridge device is present or not in a
* multicast destination interface list, struct ecm_db_multicast_connection_instance
* flags field use this flag.
*/
#define ECM_DB_MULTICAST_CONNECTION_BRIDGE_DEV_SET_FLAG 0x10
/*
* Maximum number of destination interfaces for
* a multicast connection
*/
#define ECM_DB_MULTICAST_IF_MAX 16
/*
* struct ecm_multicast_if_update
* This is used for storing processed updates to the destination
* interface list of a multicast connection. The updates are
* received from multicast routing or bridge snooper due to IGMP
* join or leave events
*/
struct ecm_multicast_if_update {
uint32_t if_join_cnt;
uint32_t if_join_idx[ECM_DB_MULTICAST_IF_MAX];
uint32_t join_dev[ECM_DB_MULTICAST_IF_MAX];
uint32_t if_leave_cnt;
uint32_t if_leave_idx[ECM_DB_MULTICAST_IF_MAX];
};
#endif
/*
* struct ecm_db_timer_group_entry
* Time entry structure used to request timer service
* WARNING: Do NOT inspect any of these fields - they are for exclusive use of the DB timer code. Use the API's to control the timer and inspect its state.
*/
struct ecm_db_timer_group_entry {
struct ecm_db_timer_group_entry *next; /* Link to the next entry in the timer group chain */
struct ecm_db_timer_group_entry *prev; /* Link to the previous entry in the timer group chain */
uint32_t timeout; /* Time this entry expires providing the timer group is not the ECM_DB_TIMER_GROUPS_MAX */
ecm_db_timer_group_t group; /* The timer group to which this entry belongs, if this is ECM_DB_TIMER_GROUPS_MAX then the timer is not running */
void *arg; /* Argument returned in callback */
ecm_db_timer_group_entry_callback_t fn; /* Function called when timer expires */
};
/*
* Connection
* A connection links two mappings (hence two hosts). This forms a channel of communication between two hosts.
*/
struct ecm_db_connection_instance;
enum ecm_db_directions {
ECM_DB_DIRECTION_EGRESS_NAT, /* LAN->WAN NAT */
ECM_DB_DIRECTION_INGRESS_NAT, /* WAN->LAN NAT */
ECM_DB_DIRECTION_NON_NAT, /* NET<>NET */
ECM_DB_DIRECTION_BRIDGED, /* BRIDGED */
};
typedef enum ecm_db_directions ecm_db_direction_t;
/*
* Connection listener events
*/
typedef void (*ecm_db_connection_listener_added_callback_t)(void *arg, struct ecm_db_connection_instance *ci); /* Connection added callback */
typedef void (*ecm_db_connection_listener_removed_callback_t)(void *arg, struct ecm_db_connection_instance *ci); /* Connection removed callback */
/*
* Connection creator events
*/
typedef void (*ecm_db_connection_final_callback_t)(void *arg); /* Finaliser callback */
/*
* Connection defunct event
*/
typedef bool (*ecm_db_connection_defunct_callback_t)(void *arg, int *accel_mode); /* Defunct callback */
/*
* Device Type for IPSec Tunnel devices
*/
#define ECM_ARPHRD_IPSEC_TUNNEL_TYPE 31 /* GGG Should be part of the kernel as a general ARPHRD_XYZ but is not */
/*
* Interface types
*/
enum ecm_db_iface_types {
ECM_DB_IFACE_TYPE_ETHERNET = 0, /* Interface is an ethernet type */
ECM_DB_IFACE_TYPE_PPPOE, /* Interface is a PPPoE interface (a specific form of PPP that we recognise in the ECM) */
ECM_DB_IFACE_TYPE_LAG, /* Interface is a Link Aggregated interface */
ECM_DB_IFACE_TYPE_VLAN, /* Interface is a VLAN interface (802.1Q) */
ECM_DB_IFACE_TYPE_BRIDGE, /* Interface is a bridge interface */
ECM_DB_IFACE_TYPE_LOOPBACK, /* Interface is a loopback interface */
ECM_DB_IFACE_TYPE_IPSEC_TUNNEL, /* Interface is a IPSec tunnel interface */
ECM_DB_IFACE_TYPE_UNKNOWN, /* Interface is unknown to the ECM */
ECM_DB_IFACE_TYPE_SIT, /* IPv6 in IPv4 tunnel (SIT) interface */
ECM_DB_IFACE_TYPE_TUNIPIP6, /* IPIP6 Tunnel (TUNNEL6) interface */
ECM_DB_IFACE_TYPE_PPPOL2TPV2, /* Interface is a PPPoL2TPV2 interface (a specific form of PPP that we recognise in the ECM) */
ECM_DB_IFACE_TYPE_PPTP, /* Interface is a PPTP interface */
ECM_DB_IFACE_TYPE_MAP_T, /* Interface is a MAP-T interface */
ECM_DB_IFACE_TYPE_GRE_TUN, /* Interface is a GRE TUN tunnel interface */
ECM_DB_IFACE_TYPE_GRE_TAP, /* Interface is a GRE TAP tunnel interface */
ECM_DB_IFACE_TYPE_RAWIP, /* Interface is a RAWIP interface */
ECM_DB_IFACE_TYPE_OVPN, /* Interface is a OVPN interface */
ECM_DB_IFACE_TYPE_VXLAN, /* Interface is a VxLAN interface */
ECM_DB_IFACE_TYPE_OVS_BRIDGE, /* Interface is a OpenvSwitch bridge interface */
ECM_DB_IFACE_TYPE_MACVLAN, /* Interface is a MACVLAN interface */
ECM_DB_IFACE_TYPE_COUNT, /* Number of interface types */
};
typedef enum ecm_db_iface_types ecm_db_iface_type_t;
/*
* Interface information as stored in the ECM db for known types of interface
*/
struct ecm_db_interface_info_ethernet { /* type == ECM_DB_IFACE_TYPE_ETHERNET */
uint8_t address[ETH_ALEN]; /* MAC Address of this Interface */
};
#ifdef ECM_INTERFACE_VXLAN_ENABLE
struct ecm_db_interface_info_vxlan { /* type == ECM_DB_IFACE_TYPE_VXLAN */
uint32_t vni; /* VxLAN network identifier */
uint32_t if_type; /* VxLAN interface type */
};
#endif
#ifdef ECM_INTERFACE_VLAN_ENABLE
struct ecm_db_interface_info_vlan { /* type == ECM_DB_IFACE_TYPE_VLAN */
uint8_t address[ETH_ALEN]; /* MAC Address of this Interface */
uint16_t vlan_tpid; /* VLAN tag protocol id */
uint16_t vlan_tag; /* VLAN tag of this interface */
};
#endif
#ifdef ECM_INTERFACE_MACVLAN_ENABLE
struct ecm_db_interface_info_macvlan { /* type == ECM_DB_IFACE_TYPE_MACVLAN */
uint8_t address[ETH_ALEN]; /* MAC Address of this Interface */
};
#endif
#ifdef ECM_INTERFACE_BOND_ENABLE
struct ecm_db_interface_info_lag { /* type == ECM_DB_IFACE_TYPE_LAG */
uint8_t address[ETH_ALEN]; /* MAC Address of this Interface */
};
#endif
struct ecm_db_interface_info_bridge { /* type == ECM_DB_IFACE_TYPE_BRIDGE */
uint8_t address[ETH_ALEN]; /* MAC Address of this Interface */
};
#ifdef ECM_INTERFACE_OVS_BRIDGE_ENABLE
struct ecm_db_interface_info_ovs_bridge { /* type == ECM_DB_IFACE_TYPE_OVS_BRIDGE */
uint8_t address[ETH_ALEN]; /* MAC Address of this Interface */
};
#endif
#ifdef ECM_INTERFACE_PPPOE_ENABLE
struct ecm_db_interface_info_pppoe { /* type == ECM_DB_IFACE_TYPE_PPPOE */
uint16_t pppoe_session_id; /* PPPoE session ID on this interface, when applicable */
uint8_t remote_mac[ETH_ALEN]; /* MAC Address of the PPPoE concentrator */
};
#endif
#ifdef ECM_INTERFACE_L2TPV2_ENABLE
struct ecm_db_interface_info_pppol2tpv2 { /* type == ECM_DB_IFACE_TYPE_PPPOL2TPV2 */
struct {
struct {
uint32_t tunnel_id;
uint32_t peer_tunnel_id;
} tunnel;
struct {
uint32_t session_id;
uint32_t peer_session_id;
} session;
} l2tp;
struct {
uint16_t sport, dport;
} udp;
struct {
uint32_t saddr, daddr;
} ip;
};
#endif
#ifdef ECM_INTERFACE_PPTP_ENABLE
struct ecm_db_interface_info_pptp {
uint32_t src_ip;
uint32_t dst_ip;
uint16_t src_call_id;
uint16_t dst_call_id;
};
#endif
#ifdef ECM_INTERFACE_MAP_T_ENABLE
struct ecm_db_interface_info_map_t { /* type == ECM_DB_IFACE_TYPE_MAP_T */
int32_t if_index;
};
#endif
#ifdef ECM_INTERFACE_GRE_TUN_ENABLE
struct ecm_db_interface_info_gre_tun { /* type == ECM_DB_IFACE_TYPE_GRE_TUN */
int32_t if_index;
ip_addr_t local_ip;
ip_addr_t remote_ip;
};
#endif
struct ecm_db_interface_info_unknown { /* type == ECM_DB_IFACE_TYPE_UNKNOWN */
uint32_t os_specific_ident; /* Operating system specific identifier (known only by front end) */
};
struct ecm_db_interface_info_loopback { /* type == ECM_DB_IFACE_TYPE_LOOPBACK */
uint32_t os_specific_ident; /* Operating system specific identifier (known only by front end) */
};
#ifdef ECM_INTERFACE_IPSEC_ENABLE
struct ecm_db_interface_info_ipsec_tunnel { /* type == ECM_DB_IFACE_TYPE_IPSEC_TUNNEL */
uint32_t os_specific_ident; /* Operating system specific identifier (known only by front end) */
// GGG TODO Flesh this out with tunnel endpoint addressing detal
};
#endif
#ifdef ECM_INTERFACE_SIT_ENABLE
struct ecm_db_interface_info_sit { /* type == ECM_DB_IFACE_TYPE_SIT */
ip_addr_t saddr; /* Tunnel source address */
ip_addr_t daddr; /* Tunnel destination addresss */
uint8_t tos; /* Tunnel tos field */
uint8_t ttl; /* Tunnel ttl field */
};
#endif
#ifdef ECM_INTERFACE_TUNIPIP6_ENABLE
struct ecm_db_interface_info_tunipip6 { /* type == ECM_DB_IFACE_TYPE_TUNIPIP6 */
ip_addr_t saddr; /* Tunnel source address */
ip_addr_t daddr; /* Tunnel destination address */
uint32_t flowlabel; /* Tunnel ipv6 flowlabel */
uint32_t flags; /* Tunnel additional flags */
uint8_t hop_limit; /* Tunnel ipv6 hop limit */
};
#endif
#ifdef ECM_INTERFACE_RAWIP_ENABLE
struct ecm_db_interface_info_rawip { /* type == ECM_DB_IFACE_TYPE_RAWIP */
uint8_t address[ETH_ALEN]; /* TODO: Random MAC Address generated by kernel */
};
#endif
#ifdef ECM_INTERFACE_OVPN_ENABLE
struct ecm_db_interface_info_ovpn { /* type == ECM_DB_IFACE_TYPE_OVPN */
int32_t tun_ifnum; /* Tunnel interface number */
};
#endif
/*
* Interface Heirarchy
* Each connection instance keeps four lists of interfaces.
* These lists record the 'interface heirarchy' in the from or to direction for the connection for both NAT and non-NAT.
* For example, a connection that is 'from' a vlan might have two interfaces in its 'from' heirarchy:
* The raw interface, e.g. eth0 and the vlan interface perhaps eth0.1.
* NOTE: Commonly referred to as "inner to outermost" interfaces.
* For a connection the ci->mi->hi->ni->ii records the interfaces that the connection 'sees' for the from/to paths. I.e. Innermost.
* But heirarchy lists record the path from the ii to the actual outward facing interface - well, as far as is possible to detect.
* A heirarchy list is recorded in reverse so in the example here it would list eth0 followed by eth0.1.
* Therefore the first interface in the list is the outermost interface, which is for acceleration, hopefully an accel engine supported interface.
* Lists have a finite size.
*/
#define ECM_DB_IFACE_HEIRARCHY_MAX 9 /* This is the number of interfaces allowed in a heirarchy */
#ifdef ECM_MULTICAST_ENABLE
/*
* Buffer size for multicast destination interface list
*/
#define ECM_DB_TO_MCAST_INTERFACES_SIZE (sizeof(struct ecm_db_iface_instance *) * ECM_DB_MULTICAST_IF_MAX * ECM_DB_IFACE_HEIRARCHY_MAX)
/*
* ecm_db_multicast_if_heirarchy_get()
* Returns the address of next heirarchy row from base address of the current heirarchy.
*/
static inline struct ecm_db_iface_instance *ecm_db_multicast_if_heirarchy_get(struct ecm_db_iface_instance *heirarchy_base, uint32_t index)
{
unsigned long *heirarchy_instance = (unsigned long *)heirarchy_base;
DEBUG_ASSERT(heirarchy_instance, "Bad memory, multicast interfaces list has been already freed\n");
DEBUG_ASSERT((index <= ECM_DB_MULTICAST_IF_MAX), "Bad index %u\n", index);
return (struct ecm_db_iface_instance *)(heirarchy_instance + (index * ECM_DB_IFACE_HEIRARCHY_MAX));
}
/*
* ecm_db_multicast_if_instance_get_at_index()
* Returns a single interface instance pointer from heirarchy at position index.
*/
static inline struct ecm_db_iface_instance *ecm_db_multicast_if_instance_get_at_index(struct ecm_db_iface_instance *heirarchy_start, uint32_t index)
{
unsigned long *iface_instance = (unsigned long *)heirarchy_start;
DEBUG_ASSERT(iface_instance, "Bad memory, multicast interfaces list has been already freed\n");
DEBUG_ASSERT((index <= ECM_DB_IFACE_HEIRARCHY_MAX), "Bad first %u\n", index);
return (struct ecm_db_iface_instance *)(iface_instance + index);
}
/*
* ecm_db_multicast_if_first_get_at_index()
* Returns a index of the first interface in the list at index position.
*/
static inline int32_t *ecm_db_multicast_if_first_get_at_index(int32_t *if_first, uint32_t index)
{
DEBUG_ASSERT(if_first, "Bad memory, multicast interfaces first has been already freed\n");
DEBUG_ASSERT((index <= ECM_DB_MULTICAST_IF_MAX), "Bad first %u\n", index);
return (if_first + index);
}
/*
* ecm_db_multicast_if_num_get_at_index()
* Returns a pointer to 'if_index' entry in an array at index position.
*/
static inline int32_t *ecm_db_multicast_if_num_get_at_index(int32_t *if_num, uint32_t index)
{
DEBUG_ASSERT(if_num, "Bad memory, ifindex list has been already freed\n");
return (if_num + index);
}
/*
* ecm_db_multicast_copy_if_heirarchy()
* Copy a heirarchy into an array of pointers starting from the heirarchy.
*/
static inline void ecm_db_multicast_copy_if_heirarchy(struct ecm_db_iface_instance *if_hr[], struct ecm_db_iface_instance *heirarchy_start)
{
unsigned long *iface_instance = (unsigned long *)heirarchy_start;
struct ecm_db_iface_instance **heirarchy;
int i;
DEBUG_ASSERT(iface_instance, "Bad memory, multicast interfaces list has been already freed\n");
for (i = 0; i < ECM_DB_IFACE_HEIRARCHY_MAX; i++) {
heirarchy = (struct ecm_db_iface_instance **)iface_instance;
if_hr[i] = *heirarchy;
iface_instance = iface_instance + 1;
}
}
#endif