/* declarations of routines that interface with the kernel's IPsec mechanism
 * Copyright (C) 1998-2001,2013 D. Hugh Redelmeier <hugh@mimosa.com>
 * Copyright (C) 2011 Michael Richardson <mcr@sandelman.ca>
 * Copyright (C) 2012 Avesh Agarwal <avagarwa@redhat.com>
 * Copyright (C) 2013 Kim Heino <b@bbbs.net>
 * Copyright (C) 2013 Tuomo Soini <tis@foobar.fi>
 * Copyright (C) 2012-2013 Paul Wouters <paul@libreswan.org>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
 *
 * 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.
 *
 */

#ifndef _KERNEL_H_

#include <net/if.h>

extern bool can_do_IPcomp;  /* can system actually perform IPCOMP? */

/*
 * Declare eroute things early enough for uses.
 * Some of these things, while they seem like they are KLIPS-only, the
 * definitions are in fact needed by all kernel interfaces at this time.
 *
 * Flags are encoded above the low-order byte of verbs.
 * "real" eroutes are only outbound.  Inbound eroutes don't exist,
 * but an addflow with an INBOUND flag allows IPIP tunnels to be
 * limited to appropriate source and destination addresses.
 */

#define IPSEC_PROTO_ANY 255

enum pluto_sadb_operations {
	ERO_ADD=1,
	ERO_REPLACE=2,
	ERO_DELETE=3,
	ERO_ADD_INBOUND=4,
	ERO_REPLACE_INBOUND=5,
	ERO_DEL_INBOUND=6
};

#define IPSEC_PROTO_ANY         255

/* KLIPS has:
   #define ERO_DELETE	SADB_X_DELFLOW
   #define ERO_ADD	SADB_X_ADDFLOW
   #define ERO_REPLACE	(SADB_X_ADDFLOW | (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT))
   #define ERO_ADD_INBOUND	(SADB_X_ADDFLOW | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT))
   #define ERO_DEL_INBOUND	(SADB_X_DELFLOW | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT))
 */

struct pfkey_proto_info {
	int proto;
	int encapsulation;
	unsigned reqid;
};

extern const struct pfkey_proto_info null_proto_info[2];

struct sadb_msg;

/* replaces SADB_X_SATYPE_* for non-KLIPS code. Assumes normal SADB_SATYPE values */
enum eroute_type {
	ET_UNSPEC = 0,
	ET_AH    = SA_AH,       /* (51)  authentication */
	ET_ESP   = SA_ESP,      /* (50)  encryption/auth */
	ET_IPCOMP= SA_COMP,     /* (108) compression */
	ET_INT   = SA_INT,      /* (61)  internal type */
	ET_IPIP  = SA_IPIP,     /* (4)   turn on tunnel type */
};
#define esatype2proto(X) (int)X
#define proto2esatype(X) (enum eroute_type)X

struct kernel_sa {
	const ip_address *src;
	const ip_address *dst;

	const ip_subnet *src_client;
	const ip_subnet *dst_client;

	bool inbound;
	bool add_selector;
	ipsec_spi_t spi;
	unsigned proto;
	unsigned int transport_proto;
	enum eroute_type esatype;
	unsigned replay_window;
	unsigned reqid;

	unsigned authalg;
	unsigned authkeylen;
	unsigned char *authkey;

	unsigned encalg;
	unsigned enckeylen;
	unsigned char *enckey;

	int outif;
	IPsecSAref_t ref;
	IPsecSAref_t refhim;

	int encapsulation;
	u_int16_t natt_sport, natt_dport;
	u_int8_t transid, natt_type;
	ip_address *natt_oa;
	const char *text_said;
#ifdef HAVE_LABELED_IPSEC
	struct xfrm_user_sec_ctx_ike *sec_ctx;
#endif

	unsigned long sa_lifetime; /* number of seconds until SA expires */
	unsigned long sa_priority;
};

struct raw_iface {
	ip_address addr;
	char name[IFNAMSIZ + 20]; /* what would be a safe size? */
	struct raw_iface *next;
};

LIST_HEAD(iface_list, iface_dev);
extern struct iface_list interface_dev;

extern char *pluto_listen;	/* from --listen flag */


/* KAME has a different name for AES */
#if !defined(SADB_X_EALG_AESCBC) && defined(SADB_X_EALG_AES)
#define SADB_X_EALG_AESCBC SADB_X_EALG_AES
#endif

struct kernel_ops {
	enum kernel_interface type;
	const char *kern_name;
	bool inbound_eroute;
	bool policy_lifetime;
	bool overlap_supported;
	bool sha2_truncbug_support;
	int replay_window;
	int *async_fdp;

	void (*init)(void);
	void (*pfkey_register)(void);
	void (*pfkey_register_response)(const struct sadb_msg *msg);
	void (*process_queue)(void);
	void (*process_msg)(void);
	void (*set_debug)(int,
			  libreswan_keying_debug_func_t debug_func,
			  libreswan_keying_debug_func_t error_func);
	bool (*raw_eroute)(const ip_address *this_host,
			   const ip_subnet *this_client,
			   const ip_address *that_host,
			   const ip_subnet *that_client,
			   ipsec_spi_t spi,
			   unsigned int proto,
			   unsigned int transport_proto,
			   enum eroute_type satype,
			   const struct pfkey_proto_info *proto_info,
			   time_t use_lifetime,
			   unsigned long sa_priority,
			   enum pluto_sadb_operations op,
			   const char *text_said
#ifdef HAVE_LABELED_IPSEC
			   , char *policy_label
#endif
			   );
	bool (*shunt_eroute)(struct connection *c,
			     struct spd_route *sr,
			     enum routing_t rt_kind,
			     enum pluto_sadb_operations op,
			     const char *opname);
	bool (*sag_eroute)(struct state *st, struct spd_route *sr,
			   enum pluto_sadb_operations op, const char *opname);
	bool (*eroute_idle)(struct state *st, time_t idle_max);
	void (*remove_orphaned_holds)(int transportproto,
				      const ip_subnet *ours,
				      const ip_subnet *his);
	bool (*add_sa)(struct kernel_sa *sa, bool replace);
	bool (*grp_sa)(const struct kernel_sa *sa_outer,
		       const struct kernel_sa *sa_inner);
	bool (*del_sa)(const struct kernel_sa *sa);
	bool (*get_sa)(const struct kernel_sa *sa, u_int *bytes);
	ipsec_spi_t (*get_spi)(const ip_address *src,
			       const ip_address *dst,
			       int proto,
			       bool tunnel_mode,
			       unsigned reqid,
			       ipsec_spi_t min,
			       ipsec_spi_t max,
			       const char *text_said);
	bool (*docommand)(struct connection *c,
			  struct spd_route *sr,
			  const char *verb,
			  struct state *st);
	void (*process_ifaces)(struct raw_iface *rifaces);
	bool (*exceptsocket)(int socketfd, int family);

};

extern int create_socket(struct raw_iface *ifp, const char *v_name, int port);

#ifndef IPSECDEVPREFIX
# define IPSECDEVPREFIX "ipsec"
#endif

extern int useful_mastno;
#ifndef MASTDEVPREFIX
# define MASTDEVPREFIX  "mast"
#endif

extern const struct kernel_ops *kernel_ops;
extern struct raw_iface *find_raw_ifaces4(void);
extern struct raw_iface *find_raw_ifaces6(void);

/* helper for invoking call outs */
extern int fmt_common_shell_out(char *buf, int blen, struct connection *c,
				struct spd_route *sr, struct state *st);

#ifdef KLIPS_MAST
/* KLIPS/mast/pfkey things */
extern bool pfkey_plumb_mast_device(int mast_dev);
#endif

/* many bits reach in to use this, but maybe shouldn't */
extern bool do_command(struct connection *c, struct spd_route *sr,
		       const char *verb, struct state *st);

#if defined(linux)
extern bool do_command_linux(struct connection *c, struct spd_route *sr,
			     const char *verb, struct state *st);
extern bool invoke_command(const char *verb, const char *verb_suffix,
			   char *cmd);
#endif

#if defined(__FreeBSD__)
extern bool do_command_freebsd(struct connection *c, struct spd_route *sr,
			       const char *verb, struct state *st);
extern bool invoke_command(const char *verb, const char *verb_suffix,
			   char *cmd);
#endif

#if defined(macintosh) || (defined(__MACH__) && defined(__APPLE__))
extern bool do_command_darwin(struct connection *c, struct spd_route *sr,
			      const char *verb, struct state *st);
extern bool invoke_command(const char *verb, const char *verb_suffix,
			   char *cmd);
#endif

#if defined(__CYGWIN32__)
extern bool do_command_cygwin(struct connection *c, struct spd_route *sr,
			      const char *verb, struct state *st);
#endif

/* information from /proc/net/ipsec_eroute */

struct eroute_info {
	unsigned long count;
	ip_subnet ours;
	ip_subnet his;
	ip_address dst;
	ip_said said;
	int transport_proto;
	struct eroute_info *next;
};

/* bare (connectionless) shunt (eroute) table
 *
 * Bare shunts are those that don't "belong" to a connection.
 * This happens because some %trapped traffic hasn't yet or cannot be
 * assigned to a connection.  The usual reason is that we cannot discover
 * the peer SG.  Another is that even when the peer has been discovered,
 * it may be that no connection matches all the particulars.
 * We record them so that, with scanning, we can discover
 * which %holds are news and which others should expire.
 */

#define SHUNT_SCAN_INTERVAL     (60 * 2)   /* time between scans of eroutes */

/* SHUNT_PATIENCE only has resolution down to a multiple of the sample rate,
 * SHUNT_SCAN_INTERVAL.
 * By making SHUNT_PATIENCE an odd multiple of half of SHUNT_SCAN_INTERVAL,
 * we minimize the effects of jitter.
 */
#define SHUNT_PATIENCE  (SHUNT_SCAN_INTERVAL * 15 / 2)  /* inactivity timeout */

struct bare_shunt {
	policy_prio_t policy_prio;
	ip_subnet ours;
	ip_subnet his;
	ip_said said;
	int transport_proto;
	unsigned long count;
	time_t last_activity;
	char *why;
	struct bare_shunt *next;
};
extern void show_shunt_status(void);

struct bare_shunt **bare_shunt_ptr(const ip_subnet *ours,
				   const ip_subnet *his,
				   int transport_proto);

/* A netlink header defines EM_MAXRELSPIS, the max number of SAs in a group.
 * Is there a PF_KEY equivalent?
 */
#ifndef EM_MAXRELSPIS
# define EM_MAXRELSPIS 4        /* AH ESP IPCOMP IPIP */
#endif

#ifdef HAVE_LABELED_IPSEC
struct xfrm_user_sec_ctx_ike; /* forward declaration of tag */
#endif
extern void record_and_initiate_opportunistic(const ip_subnet *,
					      const ip_subnet *,
					      int transport_proto
#ifdef HAVE_LABELED_IPSEC
					      , struct xfrm_user_sec_ctx_ike *
#endif
					      , const char *why);
extern void init_kernel(void);

extern void scan_proc_shunts(void);

struct connection;      /* forward declaration of tag */
extern bool trap_connection(struct connection *c);
extern void unroute_connection(struct connection *c);

extern bool has_bare_hold(const ip_address *src, const ip_address *dst,
			  int transport_proto);

extern bool replace_bare_shunt(const ip_address *src, const ip_address *dst,
			       policy_prio_t policy_prio,
			       ipsec_spi_t shunt_spi,   /* in host order! */
			       bool repl,
			       int transport_proto,
			       const char *why);

extern bool assign_hold(struct connection *c,
			struct spd_route *sr,
			int transport_proto,
			const ip_address *src, const ip_address *dst);

extern ipsec_spi_t shunt_policy_spi(struct connection *c, bool prospective);

struct state;   /* forward declaration of tag */
extern ipsec_spi_t get_ipsec_spi(ipsec_spi_t avoid,
				 int proto,
				 struct spd_route *sr,
				 bool tunnel_mode);
extern ipsec_spi_t get_my_cpi(struct spd_route *sr, bool tunnel_mode);

extern bool install_inbound_ipsec_sa(struct state *st);
extern bool install_ipsec_sa(struct state *st, bool inbound_also);
extern void delete_ipsec_sa(struct state *st, bool inbound_only);
extern bool route_and_eroute(struct connection *c,
			     struct spd_route *sr,
			     struct state *st);

extern bool was_eroute_idle(struct state *st, time_t idle_max);
extern bool get_sa_info(struct state *st, bool inbound, time_t *ago);

extern bool update_ipsec_sa(struct state *st);

extern bool eroute_connection(struct spd_route *sr,
			      ipsec_spi_t spi, unsigned int proto,
			      enum eroute_type esatype,
			      const struct pfkey_proto_info *proto_info,
			      unsigned int op, const char *opname
#ifdef HAVE_LABELED_IPSEC
			      , char *policy_label
#endif
			      );

static inline bool compatible_overlapping_connections(struct connection *a,
						      struct connection *b)
{
	return kernel_ops->overlap_supported &&
	       a && b &&
	       a != b &&
	       LIN(POLICY_OVERLAPIP, a->policy) &&
	       LIN(POLICY_OVERLAPIP, a->policy);
}

#ifdef KLIPS
extern const struct kernel_ops klips_kernel_ops;
#endif
#ifdef KLIPS_MAST
extern const struct kernel_ops mast_kernel_ops;
#endif

extern bool kernel_overlap_supported(void);
extern const char *kernel_if_name(void);
extern void show_kernel_interface(void);

/*
 * Used to pass default priority from kernel_ops-> functions.
 * Our priority is based on an unsigned long int, with the
 * lower number being the highest priority, but this
 * might need to be translated depending on the IPsec stack.
 */
#define DEFAULT_IPSEC_SA_PRIORITY 0

#define _KERNEL_H_
#endif /* _KERNEL_H_ */
