aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/interceptor/linux_internal.h
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/interceptor/linux_internal.h')
-rw-r--r--drivers/interceptor/linux_internal.h819
1 files changed, 819 insertions, 0 deletions
diff --git a/drivers/interceptor/linux_internal.h b/drivers/interceptor/linux_internal.h
new file mode 100644
index 0000000..ebd0c9f
--- /dev/null
+++ b/drivers/interceptor/linux_internal.h
@@ -0,0 +1,819 @@
+/* Netfilter Driver for IPSec VPN Client
+ *
+ * Copyright(c) 2012 Samsung Electronics
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * linux_internal.h
+ *
+ * Internal header file for the linux interceptor.
+ *
+ */
+
+#ifndef LINUX_INTERNAL_H
+#define LINUX_INTERNAL_H
+
+#include "sshincludes.h"
+
+/* Parameters used to tune the interceptor. */
+#include "linux_versions.h"
+#include "linux_params.h"
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <net/pkt_sched.h>
+
+#include <linux/interrupt.h>
+#include <linux/inetdevice.h>
+
+#include <net/ip.h>
+#include <net/inet_common.h>
+
+#ifdef SSH_LINUX_INTERCEPTOR_IPV6
+#include <net/ipv6.h>
+#include <net/addrconf.h>
+#endif /* SSH_LINUX_INTERCEPTOR_IPV6 */
+
+#ifndef SSH_IPSEC_IP_ONLY_INTERCEPTOR
+#include <linux/if_arp.h>
+#endif /* SSH_IPSEC_IP_ONLY_INTERCEPTOR */
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
+#include <linux/netfilter_bridge.h>
+#include <linux/netfilter_arp.h>
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/cpumask.h>
+#include <linux/rcupdate.h>
+
+#ifdef LINUX_NEED_IF_ADDR_H
+#include <linux/if_addr.h>
+#endif /* LINUX_NEED_IF_ADDR_H */
+
+#include <net/ip.h>
+#include <net/route.h>
+#include <net/inet_common.h>
+
+#ifdef SSH_LINUX_INTERCEPTOR_IPV6
+#include <net/ipv6.h>
+#include <net/addrconf.h>
+#include <net/ip6_fib.h>
+#include <net/ip6_route.h>
+#include <net/flow.h>
+#endif /* SSH_LINUX_INTERCEPTOR_IPV6 */
+
+#include <linux/threads.h>
+
+#include "engine.h"
+#include "kernel_includes.h"
+#include "kernel_mutex.h"
+#include "interceptor.h"
+#include "sshinet.h"
+#include "sshdebug.h"
+
+#include "linux_packet_internal.h"
+#include "linux_mutex_internal.h"
+#include "linux_virtual_adapter_internal.h"
+
+/****************************** Sanity checks ********************************/
+
+#ifndef MODULE
+#error "VPNClient can only be compiled as a MODULE"
+#endif /* MODULE */
+
+#ifndef CONFIG_NETFILTER
+#error "Kernel is not compiled with CONFIG_NETFILTER"
+#endif /* CONFIG_NETFILTER */
+
+/* Check that SSH_LINUX_FWMARK_EXTENSION_SELECTOR is in range. */
+#ifdef SSH_LINUX_FWMARK_EXTENSION_SELECTOR
+#if (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0)
+#if (SSH_LINUX_FWMARK_EXTENSION_SELECTOR >= \
+ SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS)
+#error "Invalid value specified for SSH_LINUX_FWMARK_EXTENSION_SELECTOR"
+#endif
+#endif /* (SSH_INTERCEPTOR_NUM_EXTENSION_SELECTORS > 0) */
+#endif /* SSH_LINUX_FWMARK_EXTENSION_SELECTOR */
+
+
+/****************************** Internal defines *****************************/
+
+#define SSH_LINUX_INTERCEPTOR_NR_CPUS NR_CPUS
+
+/* Flags for ssh_engine_start */
+#define SSH_LINUX_ENGINE_FLAGS 0
+
+#define SSH_LINUX_INTERCEPTOR_MODULE_DESCRIPTION "VPNClient"
+
+/********************** Kernel version specific wrapper macros ***************/
+
+#ifdef LINUX_HAS_DEV_GET_FLAGS
+#define SSH_LINUX_DEV_GET_FLAGS(dev) dev_get_flags(dev)
+#else /* LINUX_HAS_DEV_GET_FLAGS */
+#define SSH_LINUX_DEV_GET_FLAGS(dev) ((dev)->flags)
+#endif /* LINUX_HAS_DEV_GET_FLAGS */
+
+#ifdef LINUX_NF_HOOK_SKB_IS_POINTER
+typedef struct sk_buff SshHookSkb;
+#define SSH_HOOK_SKB_PTR(_skb) _skb
+#else /* LINUX_NF_HOOK_SKB_IS_POINTER */
+typedef struct sk_buff *SshHookSkb;
+#define SSH_HOOK_SKB_PTR(_skb) *_skb
+#endif /* LINUX_NF_HOOK_SKB_IS_POINTER */
+
+#ifdef LINUX_HAS_SKB_MARK
+#define SSH_SKB_MARK(__skb) ((__skb)->mark)
+#else /* LINUX_HAS_SKB_MARK */
+#define SSH_SKB_MARK(__skb) ((__skb)->nfmark)
+#endif /* LINUX_HAS_SKB_MARK */
+
+#ifdef LINUX_HAS_DST_MTU
+#define SSH_DST_MTU(__dst) (dst_mtu((__dst)))
+#else /* LINUX_HAS_DST_MTU */
+#define SSH_DST_MTU(__dst) (dst_pmtu((__dst)))
+#endif /* LINUX_HAS_DST_MTU */
+
+/* Before 2.6.22 kernels, the net devices were accessed
+ using directly global variables.
+ 2.6.22 -> 2.6.23 introduced new functions accessing
+ the net device list.
+ 2.6.24 -> these new functions started taking new
+ arguments. */
+#ifndef LINUX_HAS_NETDEVICE_ACCESSORS
+/* For 2.4.x -> 2.6.21 kernels */
+#define SSH_FIRST_NET_DEVICE() dev_base
+#define SSH_NEXT_NET_DEVICE(_dev) _dev->next
+
+#else /* LINUX_HAS_NETDEVICE_ACCESSORS */
+#ifndef LINUX_NET_DEVICE_HAS_ARGUMENT
+/* For 2.6.22 -> 2.6.23 kernels */
+#define SSH_FIRST_NET_DEVICE() first_net_device()
+#define SSH_NEXT_NET_DEVICE(_dev) next_net_device(_dev)
+
+#else /* LINUX_NET_DEVICE_HAS_ARGUMENT */
+/* For 2.6.24 -> kernels */
+#define SSH_FIRST_NET_DEVICE() first_net_device(&init_net)
+#define SSH_NEXT_NET_DEVICE(_dev) next_net_device(_dev)
+
+#endif /* LINUX_NET_DEVICE_HAS_ARGUMENT */
+#endif /* LINUX_HAS_NETDEVICE_ACCESSORS */
+
+/* This HAVE_NET_DEVICE_OPS was removed in 3.1.x */
+#ifdef LINUX_HAS_NET_DEVICE_OPS
+#ifndef HAVE_NET_DEVICE_OPS
+#define HAVE_NET_DEVICE_OPS 1
+#endif /* HAVE_NET_DEVICE_OPS */
+#endif /* LINUX_HAS_NET_DEVICE_OPS */
+
+#ifdef LINUX_NET_DEVICE_HAS_ARGUMENT
+#define SSH_DEV_GET_BY_INDEX(_i) dev_get_by_index(&init_net, (_i))
+#else /* LINUX_NET_DEVICE_HAS_ARGUMENT */
+#define SSH_DEV_GET_BY_INDEX(_i) dev_get_by_index((_i))
+#endif /* LINUX_NET_DEVICE_HAS_ARGUMENT */
+
+#ifdef LINUX_HAS_SKB_DATA_ACCESSORS
+/* On new kernel versions the skb->end, skb->tail, skb->network_header,
+ skb->mac_header, and skb->transport_header are either pointers to
+ skb->data (on 32bit platforms) or offsets from skb->data
+ (on 64bit platforms). */
+
+#define SSH_SKB_GET_END(__skb) (skb_end_pointer((__skb)))
+
+#define SSH_SKB_GET_TAIL(__skb) (skb_tail_pointer((__skb)))
+#define SSH_SKB_SET_TAIL(__skb, __ptr) \
+ (skb_set_tail_pointer((__skb), (__ptr) - (__skb)->data))
+#define SSH_SKB_RESET_TAIL(__skb) (skb_reset_tail_pointer((__skb)))
+
+#define SSH_SKB_GET_NETHDR(__skb) (skb_network_header((__skb)))
+#define SSH_SKB_SET_NETHDR(__skb, __ptr) \
+ (skb_set_network_header((__skb), (__ptr) - (__skb)->data))
+#define SSH_SKB_RESET_NETHDR(__skb) (skb_reset_network_header((__skb)))
+
+#define SSH_SKB_GET_MACHDR(__skb) (skb_mac_header((__skb)))
+#define SSH_SKB_SET_MACHDR(__skb, __ptr) \
+ (skb_set_mac_header((__skb), (__ptr) - (__skb)->data))
+#define SSH_SKB_RESET_MACHDR(__skb) (skb_reset_mac_header((__skb)))
+
+#define SSH_SKB_GET_TRHDR(__skb) (skb_transport_header((__skb)))
+#define SSH_SKB_SET_TRHDR(__skb, __ptr) \
+ (skb_set_transport_header((__skb), (__ptr) - (__skb)->data))
+#define SSH_SKB_RESET_TRHDR(__skb) (skb_reset_transport_header((__skb)))
+
+#else /* LINUX_HAS_SKB_DATA_ACCESSORS */
+
+#define SSH_SKB_GET_END(__skb) ((__skb)->end)
+
+#define SSH_SKB_GET_TAIL(__skb) ((__skb)->tail)
+#define SSH_SKB_SET_TAIL(__skb, __ptr) ((__skb)->tail = (__ptr))
+#define SSH_SKB_RESET_TAIL(__skb) ((__skb)->tail = NULL)
+
+#define SSH_SKB_GET_NETHDR(__skb) ((__skb)->nh.raw)
+#define SSH_SKB_SET_NETHDR(__skb, __ptr) ((__skb)->nh.raw = (__ptr))
+#define SSH_SKB_RESET_NETHDR(__skb) ((__skb)->nh.raw = NULL)
+
+#define SSH_SKB_GET_MACHDR(__skb) ((__skb)->mac.raw)
+#define SSH_SKB_SET_MACHDR(__skb, __ptr) ((__skb)->mac.raw = (__ptr))
+#define SSH_SKB_RESET_MACHDR(__skb) ((__skb)->mac.raw = NULL)
+
+#define SSH_SKB_GET_TRHDR(__skb) ((__skb)->h.raw)
+#define SSH_SKB_SET_TRHDR(__skb, __ptr) ((__skb)->h.raw = (__ptr))
+#define SSH_SKB_RESET_TRHDR(__skb) ((__skb)->h.raw = NULL)
+
+#endif /* LINUX_HAS_SKB_DATA_ACCESSORS */
+
+#ifdef LINUX_HAS_SKB_CSUM_OFFSET
+/* On linux-2.6.20 and later skb->csum is split into
+ a union of csum and csum_offset. */
+#define SSH_SKB_CSUM_OFFSET(__skb) ((__skb)->csum_offset)
+#define SSH_SKB_CSUM(__skb) ((__skb)->csum)
+#else /* LINUX_HAS_SKB_CSUM_OFFSET */
+#define SSH_SKB_CSUM_OFFSET(__skb) ((__skb)->csum)
+#define SSH_SKB_CSUM(__skb) ((__skb)->csum)
+#endif /* LINUX_HAS_SKB_CSUM_OFFSET */
+
+#ifdef LINUX_NF_INET_HOOKNUMS
+
+#define SSH_NF_IP_PRE_ROUTING NF_INET_PRE_ROUTING
+#define SSH_NF_IP_LOCAL_IN NF_INET_LOCAL_IN
+#define SSH_NF_IP_FORWARD NF_INET_FORWARD
+#define SSH_NF_IP_LOCAL_OUT NF_INET_LOCAL_OUT
+#define SSH_NF_IP_POST_ROUTING NF_INET_POST_ROUTING
+#define SSH_NF_IP_PRI_FIRST INT_MIN
+
+#define SSH_NF_IP6_PRE_ROUTING NF_INET_PRE_ROUTING
+#define SSH_NF_IP6_LOCAL_IN NF_INET_LOCAL_IN
+#define SSH_NF_IP6_FORWARD NF_INET_FORWARD
+#define SSH_NF_IP6_LOCAL_OUT NF_INET_LOCAL_OUT
+#define SSH_NF_IP6_POST_ROUTING NF_INET_POST_ROUTING
+#define SSH_NF_IP6_PRI_FIRST INT_MIN
+
+#else /* LINUX_UNIFIED_NETFILTER_IP_HOOKNUMS */
+
+#define SSH_NF_IP_PRE_ROUTING NF_IP_PRE_ROUTING
+#define SSH_NF_IP_LOCAL_IN NF_IP_LOCAL_IN
+#define SSH_NF_IP_FORWARD NF_IP_FORWARD
+#define SSH_NF_IP_LOCAL_OUT NF_IP_LOCAL_OUT
+#define SSH_NF_IP_POST_ROUTING NF_IP_POST_ROUTING
+#define SSH_NF_IP_PRI_FIRST NF_IP_PRI_FIRST
+
+#define SSH_NF_IP6_PRE_ROUTING NF_IP6_PRE_ROUTING
+#define SSH_NF_IP6_LOCAL_IN NF_IP6_LOCAL_IN
+#define SSH_NF_IP6_FORWARD NF_IP6_FORWARD
+#define SSH_NF_IP6_LOCAL_OUT NF_IP6_LOCAL_OUT
+#define SSH_NF_IP6_POST_ROUTING NF_IP6_POST_ROUTING
+#define SSH_NF_IP6_PRI_FIRST NF_IP6_PRI_FIRST
+
+#endif /* LINUX_NF_INET_HOOKNUMS */
+
+#ifdef LINUX_HAS_NFPROTO_ARP
+#define SSH_NFPROTO_ARP NFPROTO_ARP
+#else /* LINUX_HAS_NFPROTO_ARP */
+#define SSH_NFPROTO_ARP NF_ARP
+#endif /* LINUX_HAS_NFPROTO_ARP */
+
+/*
+ Since 2.6.31 there is now skb->dst pointer and
+ functions skb_dst() and skb_dst_set() should be used.
+
+ The code is modified to use the functions. For older
+ version corresponding macros are defined.
+ */
+#ifdef LINUX_HAS_SKB_DST_FUNCTIONS
+#define SSH_SKB_DST(__skb) skb_dst((__skb))
+#define SSH_SKB_DST_SET(__skb, __dst) skb_dst_set((__skb), (__dst))
+#else /* LINUX_HAS_SKB_DST_FUNCTIONS */
+#define SSH_SKB_DST(__skb) ((__skb)->dst)
+#define SSH_SKB_DST_SET(__skb, __dst) ((void)((__skb)->dst = (__dst)))
+#endif /* LINUX_HAS_SKB_DST_FUNCTIONS */
+
+#ifdef IP6CB
+#define SSH_LINUX_IP6CB(skbp) IP6CB(skbp)
+#else /* IP6CB */
+#define SSH_LINUX_IP6CB(skbp) ((struct inet6_skb_parm *) ((skbp)->cb))
+#endif /* IP6CB */
+
+/* Stating from linux 2.6.35 the IPv6 address list needs to be iterated
+ using the list_for_each_* macros. */
+#ifdef LINUX_RT_DST_IS_NOT_IN_UNION
+#define SSH_RT_DST(_rt) ((_rt)->dst)
+#else /* LINUX_RT_DST_IS_NOT_IN_UNION */
+#define SSH_RT_DST(_rt) ((_rt)->u.dst)
+#endif /* LINUX_RT_DST_IS_NOT_IN_UNION */
+
+/* Starting from linux 2.6.35 the IPv6 address list needs to be iterated
+ using the list_for_each_* macros. */
+#ifdef LINUX_HAS_INET6_IFADDR_LIST_HEAD
+#define SSH_INET6_IFADDR_LIST_FOR_EACH(item, next, list) \
+ list_for_each_entry_safe((item), (next), &(list), if_list)
+#else /* LINUX_HAS_INET6_IFADDR_LIST_HEAD */
+#define SSH_INET6_IFADDR_LIST_FOR_EACH(item, next, list) \
+ for ((item) = (list), (next) = NULL; \
+ (item) != NULL; \
+ (item) = (item)->if_next)
+#endif /* LINUX_HAS_INET6_IFADDR_LIST_HEAD */
+
+#if defined(LINUX_DST_ALLOC_HAS_MANY_ARGS)
+#define SSH_DST_ALLOC(_dst) dst_alloc((_dst)->ops, NULL, 0, 0, 0)
+#elif defined(LINUX_DST_ALLOC_HAS_REFCOUNT)
+#define SSH_DST_ALLOC(_dst) dst_alloc((_dst)->ops, 0)
+#else /* defined(LINUX_DST_ALLOC_HAS_REFCOUNT) */
+#define SSH_DST_ALLOC(_dst) dst_alloc((_dst)->ops)
+#endif /* defined(LINUX_DST_ALLOC_HAS_REFCOUNT) */
+
+#if defined(LINUX_SSH_RTABLE_FIRST_ELEMENT_NEEDED)
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,38)
+#define SSH_RTABLE_FIRST_MEMBER(_rt) ((_rt)->fl)
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
+#define SSH_RTABLE_FIRST_MEMBER(_rt) ((_rt)->rt_key_dst)
+#endif /* LINUX_VERSION_CODE */
+#endif /* defined(LINUX_SSH_RTABLE_FIRST_ELEMENT_NEEDED) */
+
+/* Linux 2.6.39 removed fl4_dst and fl6_dst defines. We like to use
+ those so redefinig those for our purposes. */
+#ifdef LINUX_FLOWI_NO_FL4_ACCESSORS
+#define fl4_dst u.ip4.daddr
+#define fl4_src u.ip4.saddr
+#define fl4_tos u.ip4.__fl_common.flowic_tos
+#define oif u.ip4.__fl_common.flowic_oif
+#define proto u.ip4.__fl_common.flowic_proto
+#define fl4_scope u.ip4.__fl_common.flowic_scope
+#endif /* LINUX_FLOWI_NO_FL4_ACCESSORS */
+
+#ifdef LINUX_FLOWI_NO_FL6_ACCESSORS
+#define fl6_dst u.ip6.daddr
+#define fl6_src u.ip6.saddr
+#endif /* LINUX_FLOWI_NO_FL6_ACCESSORS */
+
+/****************************** Statistics helper macros *********************/
+
+#ifdef DEBUG_LIGHT
+
+#define SSH_LINUX_STATISTICS(interceptor, block) \
+do \
+ { \
+ if ((interceptor)) \
+ { \
+ spin_lock_bh(&(interceptor)->statistics_lock); \
+ block; \
+ spin_unlock_bh(&(interceptor)->statistics_lock); \
+ } \
+ } \
+while (0)
+
+#else /* DEBUG_LIGHT */
+
+#define SSH_LINUX_STATISTICS(interceptor, block)
+
+#endif /* DEBUG_LIGHT */
+
+/****************************** Interface handling ***************************/
+
+/* Sanity check that the interface index 'ifnum' fits into
+ the SshInterceptorIfnum data type. 'ifnum' may be equal to
+ SSH_INTERCEPTOR_INVALID_IFNUM. */
+#define SSH_LINUX_ASSERT_IFNUM(ifnum) \
+SSH_ASSERT(((SshUInt32) (ifnum)) < ((SshUInt32) SSH_INTERCEPTOR_MAX_IFNUM) \
+|| ((SshUInt32) (ifnum)) == ((SshUInt32) SSH_INTERCEPTOR_INVALID_IFNUM))
+
+/* Sanity check that the interface index 'ifnum' is a valid
+ SshInterceptorIfnum. */
+#define SSH_LINUX_ASSERT_VALID_IFNUM(ifnum) \
+SSH_ASSERT(((SshUInt32) (ifnum)) < ((SshUInt32) SSH_INTERCEPTOR_MAX_IFNUM) \
+&& ((SshUInt32) (ifnum)) != ((SshUInt32) SSH_INTERCEPTOR_INVALID_IFNUM))
+
+/* Interface structure for caching "ifindex->dev" mapping. */
+typedef struct SshInterceptorInternalInterfaceRec
+*SshInterceptorInternalInterface;
+
+struct SshInterceptorInternalInterfaceRec
+{
+ /* Next entry in the hashtable chain */
+ SshInterceptorInternalInterface next;
+ /* Interface index */
+ SshUInt32 ifindex;
+ /* Linux net_device structure */
+ struct net_device *dev;
+
+ /* This field is used to mark existing interfaces,
+ and to remove disappeared interfaces from the hashtable. */
+ SshUInt8 generation;
+
+ /* Pointer to private data. This is currently used only by Octeon. */
+ void *context;
+};
+
+/* Number of hashtable slots in the interface hashtable. */
+#define SSH_LINUX_IFACE_HASH_SIZE 256
+
+/* Maximum number of entries in the interface hashtable.
+ Currently equal to maximum interface number. */
+#define SSH_LINUX_IFACE_TABLE_SIZE SSH_INTERCEPTOR_MAX_IFNUM
+
+/****************************** Proc entries *********************************/
+
+#define SSH_PROC_ROOT "vpnclient"
+#define SSH_PROC_ENGINE "engine"
+#define SSH_PROC_VERSION "version"
+
+/* Ipm receive buffer size. This must be big enough to fit a maximum sized
+ IP packet + internal packet data + ipm message header. There is only
+ one receive buffer. */
+#define SSH_LINUX_IPM_RECV_BUFFER_SIZE 66000
+
+/* Ipm channel message structure. These structures are used for queueing
+ messages from kernel to userspace. The maximum number of allocated messages
+ is limited by SSH_LINUX_MAX_IPM_MESSAGES (in linux_params.h). */
+typedef struct SshInterceptorIpmMsgRec
+SshInterceptorIpmMsgStruct, *SshInterceptorIpmMsg;
+
+struct SshInterceptorIpmMsgRec
+{
+ /* Send queue is doubly linked, freelist uses only `next'. */
+ SshInterceptorIpmMsg next;
+ SshInterceptorIpmMsg prev;
+
+ SshUInt8 reliable : 1; /* message is reliable. */
+ SshUInt8 emergency_mallocated : 1; /* message is allocated from heap */
+
+ /* Offset for partially sent message */
+ size_t offset;
+
+ /* Message length and data. */
+ size_t len;
+ unsigned char *buf;
+};
+
+/* Ipm structure */
+typedef struct SshInterceptorIpmRec
+{
+ /* RW lock for protecting the send message queue and the message freelist. */
+ rwlock_t lock;
+
+ /* Is ipm channel open */
+ atomic_t open;
+
+ /* Message freelist and number of allocated messages. */
+ SshInterceptorIpmMsg msg_freelist;
+ SshUInt32 msg_allocated;
+
+ /* Output message queue */
+ SshInterceptorIpmMsg send_queue;
+ SshInterceptorIpmMsg send_queue_tail;
+
+ /* Number of unreliable messages in the sed queue. */
+ SshUInt32 send_queue_num_unreliable;
+
+} SshInterceptorIpmStruct, *SshInterceptorIpm;
+
+
+/* Structure for ipm channel /proc entry. */
+typedef struct SshInterceptorIpmProcEntryRec
+{
+ /* /proc filesystem inode */
+ struct proc_dir_entry *entry;
+
+ /* RW lock for protecting the proc entry */
+ rwlock_t lock;
+
+ /* Is an userspace application using this entry */
+ Boolean open;
+
+ /* Is another read ongoing? When this is TRUE
+ then `send_msg' is owned by the reader. */
+ Boolean read_active;
+
+ /* Is another write ongoing? When this is TRUE
+ then `recv_buf' is owned by the writer. */
+ Boolean write_active;
+
+ /* Wait queue for blocking mode reads and writes. */
+ wait_queue_head_t wait_queue;
+
+ /* Output message under processing. */
+ SshInterceptorIpmMsg send_msg;
+
+ /* Input message length */
+ size_t recv_len;
+
+ /* Input message buffer */
+ size_t recv_buf_size;
+ unsigned char *recv_buf;
+
+} SshInterceptorIpmProcEntryStruct, *SshInterceptorIpmProcEntry;
+
+
+/* Structure for other /proc entries. */
+typedef struct SshInterceptorProcEntryRec
+{
+ /* /proc filesystem entry */
+ struct proc_dir_entry *entry;
+
+ /* RW lock for protecting the proc entry */
+ rwlock_t lock;
+
+ /* Is an userspace application using this entry */
+ Boolean open;
+
+ /* Is another read or write ongoing? When this is TRUE
+ then `buf' is owned by the reader/writer. */
+ Boolean active;
+
+ /* Number of bytes returned to the userpace application */
+ size_t buf_len;
+
+ /* Preallocated buffer for read and write operations. */
+ char buf[1024];
+
+} SshInterceptorProcEntryStruct, *SshInterceptorProcEntry;
+
+/****************************** Dst entry cache ******************************/
+#define SSH_DST_ENTRY_TBL_SIZE 128
+typedef struct SshDstEntryRec
+{
+ struct dst_entry *dst_entry;
+
+ unsigned long allocation_time;
+ SshUInt32 dst_entry_id;
+
+ struct SshDstEntryRec *next;
+} *SshDstEntry, SshDstEntryStruct;
+
+
+/****************************** Interceptor Object ***************************/
+
+struct SshInterceptorRec
+{
+ /* Function pointers to netfilter infrastructure */
+ struct
+ {
+ int (*ip_rcv_finish) (struct sk_buff *);
+ int (*ip_finish_output) (struct sk_buff *);
+#ifdef SSH_LINUX_INTERCEPTOR_IPV6
+ int (*ip6_rcv_finish) (struct sk_buff *);
+ int (*ip6_output_finish) (struct sk_buff *);
+#endif /* SSH_LINUX_INTERCEPTOR_IPV6 */
+#ifndef SSH_IPSEC_IP_ONLY_INTERCEPTOR
+ int (*arp_process) (struct sk_buff *);
+#endif /* !SSH_IPSEC_IP_ONLY_INTERCEPTOR */
+ } linux_fn;
+
+ SshVirtualAdapter virtual_adapters[SSH_LINUX_MAX_VIRTUAL_ADAPTERS];
+
+ Boolean hooks_installed;
+
+ /* Interface information used in ssh_interceptor_send()
+ (and elsewhere obviously, but the aforementioned
+ is the reason it is here). 'if_hash', 'if_table_size',
+ and 'if_generation' are protected by 'if_table_lock' rwlock. */
+ SshInterceptorInternalInterface if_hash[SSH_LINUX_IFACE_HASH_SIZE];
+
+ SshInterceptorInternalInterface if_table;
+ SshUInt32 if_table_size;
+ SshUInt8 if_generation;
+
+ /* Protected by interceptor_lock */
+ int num_interface_callbacks;
+
+ /* Notifiers, notifies when interfaces change. */
+ Boolean iface_notifiers_installed;
+
+ struct notifier_block notifier_netdev;
+ struct notifier_block notifier_inetaddr;
+#ifdef SSH_LINUX_INTERCEPTOR_IPV6
+ struct notifier_block notifier_inet6addr;
+#endif /* SSH_LINUX_INTERCEPTOR_IPV6 */
+
+ /* Reader Writer lock for interface table manipulation */
+ rwlock_t if_table_lock;
+
+ /* Registered callbacks */
+
+ /* Interface callback. Protected by 'interceptor_lock' */
+ SshInterceptorInterfacesCB interfaces_callback;
+
+ /* Unused and unprotected */
+ SshInterceptorRouteChangeCB route_callback;
+
+ /* Callback for packet. Protected by rcu. */
+ SshInterceptorPacketCB packet_callback;
+
+ /* Context for interface, route and packet callbacks. */
+ void *callback_context;
+
+ /* Engine context */
+ SshEngine engine;
+ Boolean engine_open;
+
+ /* Intercept packets. */
+ Boolean enable_interception;
+
+ /* Name of related engine-instance */
+ char *name;
+
+ /* Ipm channel */
+ SshInterceptorIpmStruct ipm;
+
+ /* /proc filesystem entries */
+ struct proc_dir_entry *proc_dir;
+
+ SshInterceptorIpmProcEntryStruct ipm_proc_entry;
+
+ SshInterceptorProcEntryStruct version_proc_entry;
+
+ /* Main mutex for interceptor use */
+ SshKernelMutex interceptor_lock;
+
+ /* Mutex for memory map manipulation */
+ SshKernelMutex memory_lock;
+
+ /* Mutex for packet handling */
+ SshKernelMutex packet_lock;
+
+ SshKernelMutex dst_entry_cache_lock;
+ Boolean dst_entry_cache_timeout_registered;
+ SshUInt32 dst_entry_id;
+ struct timer_list dst_cache_timer;
+ SshUInt32 dst_entry_cached_items;
+ SshDstEntry dst_entry_table[SSH_DST_ENTRY_TBL_SIZE];
+
+#ifdef DEBUG_LIGHT
+ /* Statistics spin lock */
+ spinlock_t statistics_lock;
+
+ struct {
+ /* Statistics */
+ SshUInt64 num_packets_out;
+ SshUInt64 num_packets_in;
+ SshUInt64 num_bytes_out;
+ SshUInt64 num_bytes_in;
+ SshUInt64 num_passthrough;
+ SshUInt64 num_fastpath_packets_in;
+ SshUInt64 num_fastpath_packets_out;
+ SshUInt64 num_fastpath_bytes_in;
+ SshUInt64 num_fastpath_bytes_out;
+ SshUInt64 num_errors;
+ SshUInt64 num_packets_sent;
+ SshUInt64 num_bytes_sent;
+ SshUInt64 allocated_memory;
+ SshUInt64 allocated_memory_max;
+ SshUInt64 num_allocations;
+ SshUInt64 num_allocations_large;
+ SshUInt64 num_allocations_total;
+ SshUInt64 num_allocated_packets;
+ SshUInt64 num_allocated_packets_total;
+ SshUInt64 num_copied_packets;
+ SshUInt64 num_failed_allocs;
+ SshUInt64 num_light_locks;
+ SshUInt64 num_light_interceptor_locks;
+ SshUInt64 num_heavy_locks;
+ SshUInt64 ipm_send_queue_len;
+ SshUInt64 ipm_send_queue_bytes;
+ } stats;
+#endif /* DEBUG_LIGHT */
+};
+
+typedef struct SshInterceptorRec SshInterceptorStruct;
+
+/****************************** Function prototypes **************************/
+
+/* Call packet_callback */
+#define SSH_LINUX_INTERCEPTOR_PACKET_CALLBACK(interceptor, pkt) \
+ do { \
+ rcu_read_lock(); \
+ (interceptor)->packet_callback((pkt), (interceptor)->callback_context); \
+ rcu_read_unlock(); \
+ } while (0)
+
+/* Proc entries */
+Boolean ssh_interceptor_proc_init(SshInterceptor interceptor);
+void ssh_interceptor_proc_uninit(SshInterceptor interceptor);
+
+/* Ipm channel */
+
+/* init / uninit */
+Boolean ssh_interceptor_ipm_init(SshInterceptor interceptor);
+void ssh_interceptor_ipm_uninit(SshInterceptor interceptor);
+
+/* open / close. These functions handle ipm message queue flushing. */
+void interceptor_ipm_open(SshInterceptor interceptor);
+void interceptor_ipm_close(SshInterceptor interceptor);
+
+/* open / close notifiers. These functions notify engine. */
+void ssh_interceptor_notify_ipm_open(SshInterceptor interceptor);
+void ssh_interceptor_notify_ipm_close(SshInterceptor interceptor);
+
+Boolean ssh_interceptor_send_to_ipm(unsigned char *data, size_t len,
+ Boolean reliable, void *machine_context);
+ssize_t ssh_interceptor_receive_from_ipm(unsigned char *data, size_t len);
+
+void interceptor_ipm_message_free(SshInterceptor interceptor,
+ SshInterceptorIpmMsg msg);
+
+/* Packet access and manipulation. */
+
+/* Header-only allocation.
+ This function will assert that the interface numbers will
+ fit into the data type SshInterceptorIfnum. */
+SshInterceptorInternalPacket
+ssh_interceptor_packet_alloc_header(SshInterceptor interceptor,
+ SshUInt32 flags,
+ SshInterceptorProtocol protocol,
+ SshUInt32 ifnum_in,
+ SshUInt32 ifnum_out,
+ struct sk_buff *skb,
+ Boolean force_copy_skbuff,
+ Boolean free_original_on_copy,
+ Boolean packet_from_system);
+
+
+
+/* Allocates new packet skb with copied data from original
+ + the extra free space reserved for extensions. */
+struct sk_buff *
+ssh_interceptor_packet_skb_dup(SshInterceptor interceptor,
+ struct sk_buff *skb,
+ size_t addbytes_active_ofs,
+ size_t addbytes_active);
+
+/* Align the interceptor packet at the data offset 'offset' to a word
+ boundary. On failure, 'pp' is freed and returns FALSE. */
+Boolean
+ssh_interceptor_packet_align(SshInterceptorPacket packet, size_t offset);
+
+/* Verify that `skbp' has enough headroom to be sent out through `skbp->dev'.
+ On failure this frees `skbp' and returns NULL. */
+struct sk_buff *
+ssh_interceptor_packet_verify_headroom(struct sk_buff *skbp,
+ size_t media_header_len);
+
+void
+ssh_interceptor_packet_return_dst_entry(SshInterceptor interceptor,
+ SshUInt32 dst_entry_id,
+ SshInterceptorPacket pp,
+ Boolean remove_only);
+SshUInt32
+ssh_interceptor_packet_cache_dst_entry(SshInterceptor interceptor,
+ SshInterceptorPacket pp);
+
+Boolean
+ssh_interceptor_dst_entry_cache_init(SshInterceptor interceptor);
+
+void
+ssh_interceptor_dst_entry_cache_flush(SshInterceptor interceptor);
+
+void
+ssh_interceptor_dst_entry_cache_uninit(SshInterceptor interceptor);
+
+/* Packet freelist init / uninit. */
+Boolean ssh_interceptor_packet_freelist_init(SshInterceptor interceptor);
+void ssh_interceptor_packet_freelist_uninit(SshInterceptor interceptor);
+
+int ssh_linux_module_inc_use_count(void);
+void ssh_linux_module_dec_use_count(void);
+
+
+Boolean ssh_interceptor_ip_glue_init(SshInterceptor interceptor);
+Boolean ssh_interceptor_ip_glue_uninit(SshInterceptor interceptor);
+
+int ssh_interceptor_hook_magic_init(void);
+
+struct net_device *
+ssh_interceptor_ifnum_to_netdev(SshInterceptor interceptor, SshUInt32 ifnum);
+struct net_device *
+ssh_interceptor_ifnum_to_netdev_ctx(SshInterceptor interceptor,
+ SshUInt32 ifnum, void **context_return);
+void ssh_interceptor_release_netdev(struct net_device *dev);
+void ssh_interceptor_receive_ifaces(SshInterceptor interceptor);
+void ssh_interceptor_clear_ifaces(SshInterceptor interceptor);
+Boolean ssh_interceptor_iface_init(SshInterceptor interceptor);
+void ssh_interceptor_iface_uninit(SshInterceptor interceptor);
+
+/* skb rerouting */
+Boolean ssh_interceptor_reroute_skb_ipv4(SshInterceptor interceptor,
+ struct sk_buff *skb,
+ SshUInt16 route_selector,
+ SshUInt32 ifnum_in);
+#ifdef SSH_LINUX_INTERCEPTOR_IPV6
+Boolean ssh_interceptor_reroute_skb_ipv6(SshInterceptor interceptor,
+ struct sk_buff *skb,
+ SshUInt16 route_selector,
+ SshUInt32 ifnum_in);
+#endif /* SSH_LINUX_INTERCEPTOR_IPV6 */
+
+#endif /* LINUX_INTERNAL_H */