/*[DOC]************************************************************************
*
* (c) Copyright 2004, 2005 Nortel Networks, Inc.
* All Rights Reserved Worldwide
*
**[ENDDOC]********************************************************************/

#ifndef _PLUGIN_CAPI_H_
#define _PLUGIN_CAPI_H_

typedef unsigned long  CAPI_UINT32;
typedef long           CAPI_INT32;
typedef unsigned short CAPI_UINT16;
typedef unsigned char  CAPI_UINT8;
typedef signed char    CAPI_INT8;
typedef CAPI_UINT32    CAPI_ERRORCODE;
typedef CAPI_UINT32    CAPI_HANDLE;
#if defined UNIX
typedef char	       CAPI_TCHAR;
#else
typedef wchar_t	       CAPI_TCHAR;
#endif /* UNIX */


#ifndef _CAPI_ISAKMP_PACKET_
#  define _CAPI_ISAKMP_PACKET_
    typedef void                      CAPI_ISAKMP_PACKET;
#endif /* _CAPI_ISAKMP_PACKET_ */
#ifndef _CAPI_ISAKMP_PAYLOAD_
#  define _CAPI_ISAKMP_PAYLOAD_
    typedef void                      CAPI_ISAKMP_PAYLOAD;
#endif /* _CAPI_ISAKMP_PAYLOAD_ */
#ifndef _CAPI_ESP_PACKET_
#  define _CAPI_ESP_PACKET_
    typedef void                      CAPI_ESP_PACKET;
#endif /* _CAPI_ESP_PACKET_ */

/* Error codes */
enum capi_result {
  CAPI_NOERROR = 0,             /* no error */
  CAPI_CALL_ERROR = 1,		/* invalid args without length errors */
  CAPI_PROTOCOL_ERROR = 2,	/* invalid calls sequence */
  CAPI_INTERNAL_ERROR = 3,	/* plugin UNKNOWN internal error */
  CAPI_LICENSE_ERROR = 5,	/* invalid license */
  CAPI_PSK_ERROR = 6,		/* psk error */
  CAPI_PLUGIN_AUTH_ERROR = 7,	/* auth error */
  CAPI_ARGLEN_ERROR = 8,	/* invalid argument length */
  CAPI_NOFREE_SID_ERROR = 9,	/* sid-table overflow */
  CAPI_NO_MORE_DATA_ERROR = 10,	/* no more data */
  CAPI_UNSUPPORTED_ERROR = 11,	/* unsupported feature */
  CAPI_LOGGER_ERROR = 12	/* unable to log event */
};

/* responder ? initiator */
enum capi_role {
  CAPI_INITIATOR = 1,
  CAPI_RESPONDER = 2
};

/* ESP direction */
enum capi_direction {
  CAPI_INBOUND = 1,
  CAPI_OUTBOUND = 2
};

/* log severity */
enum capi_log_severity {		/* when to use, destination */
  CAPI_EMERG = 0,	/* system is unusable, ram&disk */
  CAPI_ALERT = 1,       /* action must be taken immediately, ram&disk */
  CAPI_CRIT = 2,        /* critical conditions, ram&disk */
  CAPI_ERR = 3,         /* error conditions, ram&disk */
  CAPI_WARNING = 4,     /* warning conditions, ram&disk */
  CAPI_NOTICE = 5,      /* normal but significant conditions, ram */
  CAPI_INFO = 6,        /* informational messages, ram */
  CAPI_DEBUG = 7        /* debug-level messages */
};

typedef struct capi_blob {
  CAPI_UINT8  *ptr;
  CAPI_UINT32  len;
} _capi_blob_;

typedef struct capi_tm {
  CAPI_INT32 tm_sec;         /* seconds */
  CAPI_INT32 tm_min;         /* minutes */
  CAPI_INT32 tm_hour;        /* hours */
  CAPI_INT32 tm_mday;        /* day of the month */
  CAPI_INT32 tm_mon;         /* month */
  CAPI_INT32 tm_year;        /* year */
  CAPI_INT32 tm_wday;        /* day of the week */
  CAPI_INT32 tm_yday;        /* day in the year */
  CAPI_INT32 tm_isdst;       /* daylight saving time */
} _capi_tm_;

#define PAYLOAD_HEADER_LEN 4

typedef struct tISAKMP_PAYLOAD {
  CAPI_UINT8  nextPayload;
  CAPI_UINT8  RESERVED;
  CAPI_UINT16 PayloadLength;
} ISAKMP_PAYLOAD;

typedef struct tikeHdrFlags {
  unsigned NextPayl : 8;
  unsigned MjVer    : 4;
  unsigned MnVer    : 4;
  unsigned ExchType : 8;
  unsigned Flags    : 8;
} ikeHdrFlags;

typedef struct tIKEpktHeader {
  CAPI_UINT32 Initiator_Cookie[2];
  CAPI_UINT32 Responder_Cookie[2];
  union {
    CAPI_UINT32 _bit_flds;	/* XXXX dim unneeded for us ? */
    ikeHdrFlags flgs;
  } bf;
  CAPI_UINT32 MessageID;
  CAPI_UINT32 Length;
} ikeHDR;

typedef struct tESPpktHeader {
  CAPI_UINT32 SPI;
  CAPI_UINT32 SeqNum;
} espHDR;

typedef struct plugin_hdl _plugin_hdl_;

/* function prototypes */
typedef CAPI_ERRORCODE p1_CreateDecl(struct plugin_hdl *plugin, 
				       CAPI_UINT32 role,
				       CAPI_HANDLE *sid);

typedef CAPI_ERRORCODE p1_EncapDecl(struct plugin_hdl *plugin, CAPI_HANDLE sid,
				    CAPI_ISAKMP_PACKET *data, CAPI_UINT32 inputdata_len,
				    CAPI_UINT32 *outputdata_len);

typedef CAPI_ERRORCODE p1_DecapDecl(struct plugin_hdl *plugin, CAPI_HANDLE sid,
				    CAPI_ISAKMP_PACKET *data, CAPI_UINT32 *len );

typedef CAPI_ERRORCODE p1_SetupDecl(struct plugin_hdl *plugin, CAPI_HANDLE sid,
				    CAPI_UINT8 *KEx_b, CAPI_UINT32 *KEx_b_len,
				    CAPI_UINT8 *Nx_b, CAPI_UINT32 *Nx_b_len );

typedef CAPI_ERRORCODE p1_AgreeDecl(struct plugin_hdl *plugin, CAPI_HANDLE sid,
				    const CAPI_UINT8 *SAi_b, CAPI_UINT32 SAi_b_len,
				    const CAPI_UINT8 *KEx_b, CAPI_UINT32 KEx_b_len,
				    const CAPI_UINT8 *Nx_b, CAPI_UINT32 Nx_b_len);

typedef CAPI_ERRORCODE p1_SetPSKDecl(struct plugin_hdl *plugin, CAPI_HANDLE sid,
				     const CAPI_UINT8 *psk, CAPI_UINT32 psk_len,
				     const CAPI_UINT8 *CKY_I, CAPI_UINT32 CKY_I_len,
				     const CAPI_UINT8 *CKY_R, CAPI_UINT32 CKY_R_len);

typedef CAPI_ERRORCODE p1_Hash_irDecl(struct plugin_hdl *plugin, CAPI_HANDLE sid,
				      const CAPI_UINT8 *IDix_b, CAPI_UINT32 IDix_b_len,
				      CAPI_UINT8 *HASH_X_b, CAPI_UINT32 *HASH_X_b_len);

typedef CAPI_ERRORCODE p1_Verify_irDecl(struct plugin_hdl *plugin, CAPI_HANDLE sid,
					const CAPI_UINT8 *IDix_b, CAPI_UINT32 IDix_b_len,
					const CAPI_UINT8 *HASH_X_b, CAPI_UINT32 HASH_X_b_len);

typedef CAPI_ERRORCODE p2_CreateDecl(struct plugin_hdl *plugin, CAPI_HANDLE p1sid,
				     CAPI_UINT32 role,
				     CAPI_UINT8 *KEx_b, CAPI_UINT32 *KEx_b_len, /* if NULL/NULL --> no PFS */
				     CAPI_UINT8 *Nx_b, CAPI_UINT32 *Nx_b_len,
				     CAPI_HANDLE *p2sid );

typedef CAPI_ERRORCODE p2_AgreeDecl(struct plugin_hdl *plugin, CAPI_HANDLE sid, 
				    const CAPI_ISAKMP_PAYLOAD *KEx, CAPI_UINT32 KEx_len,
				    const CAPI_ISAKMP_PAYLOAD *Nx, CAPI_UINT32 Nx_len);

typedef CAPI_ERRORCODE p1_Hash_a_CreateDecl(struct plugin_hdl *plugin, CAPI_HANDLE sid );

typedef CAPI_ERRORCODE p1_Hash_a_UpdateDecl(struct plugin_hdl *plugin, CAPI_HANDLE sid,
					    const CAPI_UINT8 *data, CAPI_UINT32 len );

typedef CAPI_ERRORCODE p1_Hash_a_GetDecl(struct plugin_hdl *plugin, CAPI_HANDLE sid, 
					 CAPI_UINT8 *mac, CAPI_UINT32 *len );

typedef CAPI_ERRORCODE p2_Verify2Decl(struct plugin_hdl *plugin, CAPI_HANDLE sid, 
				      const CAPI_UINT8 *HASH2_b, CAPI_UINT32 HASH2_b_len, 
				      const CAPI_UINT8 *M_ID, CAPI_UINT32 M_ID_len, 
				      const CAPI_UINT8 *allpays, CAPI_UINT32 allpays_len);

typedef CAPI_ERRORCODE p2_Verify3Decl(struct plugin_hdl *plugin, CAPI_HANDLE sid,
				      const CAPI_UINT8 *HASH3_b, CAPI_UINT32 HASH3_b_len,
				      const CAPI_UINT8 *M_ID, CAPI_UINT32 M_ID_len);

typedef CAPI_ERRORCODE espCreateDecl(struct plugin_hdl *plugin, CAPI_HANDLE p2sid, CAPI_UINT32 direction,
				     CAPI_UINT8 proto, CAPI_UINT32 spi, CAPI_HANDLE *espsid);

typedef CAPI_ERRORCODE espEncapDecl(struct plugin_hdl *plugin, CAPI_HANDLE sid,
				    CAPI_ESP_PACKET *data, CAPI_UINT32 inputdata_len, CAPI_UINT32 *outputdata_len );

typedef CAPI_ERRORCODE espDecapDecl(struct plugin_hdl *plugin, CAPI_HANDLE sid,
				    CAPI_ESP_PACKET *data, CAPI_UINT32 *len );

typedef CAPI_ERRORCODE GetRandomDecl(struct plugin_hdl *plugin, CAPI_HANDLE sid,
				     CAPI_UINT8 *data, CAPI_UINT32 len );

typedef CAPI_ERRORCODE destroyDecl(struct plugin_hdl *plugin, CAPI_HANDLE sid);

typedef CAPI_ERRORCODE shutdownDecl(struct plugin_hdl *plugin);

typedef CAPI_ERRORCODE selfTestDecl(struct plugin_hdl *plugin);

/*
 * GCC (and some other compilers) define '__attribute__'; we're using this
 * macro to alert the compiler to flag inconsistencies in printf/scanf-like
 * function calls.  Just in case '__attribute__' isn't defined, make a dummy.
 * G++ doesn't accept it anyway.
 */
#if !defined GCC_PRINTFLIKE
#   if defined(__GNUC__) && !defined(printf) && !defined __cplusplus
#       define GCC_PRINTFLIKE(fmt,var) __attribute__((format (printf,fmt,var)))
#   else
#       define GCC_PRINTFLIKE(fmt,var)
#   endif
#endif
typedef CAPI_ERRORCODE LoggerDecl(const struct plugin_hdl *plugin,
				  CAPI_UINT32 severity,
				  const CAPI_TCHAR *fmt, ...) GCC_PRINTFLIKE(3,4);

/* Plugin handle structure */
/* This structure is located at the beginning of plugin memory and is filled
   by the plugin.
   A pointer to this structure is passed with every function call to any
   plugin function.
*/

struct plugin_hdl {
  p1_CreateDecl *p1_CreateFn;
  p1_EncapDecl *p1_EncapFn;
  p1_DecapDecl *p1_DecapFn;
  p1_SetupDecl *p1_SetupFn;
  p1_AgreeDecl *p1_AgreeFn;
  p1_SetPSKDecl *p1_SetPSKFn;
  p1_Hash_irDecl *p1_Hash_irFn;
  p1_Verify_irDecl *p1_Verify_irFn;
  p2_CreateDecl *p2_CreateFn;
  p2_AgreeDecl *p2_AgreeFn;
  p1_Hash_a_CreateDecl *p1_Hash_a_CreateFn;
  p1_Hash_a_UpdateDecl *p1_Hash_a_UpdateFn;
  p1_Hash_a_GetDecl *p1_Hash_a_GetFn;
  p2_Verify2Decl *p2_Verify2Fn;
  p2_Verify3Decl *p2_Verify3Fn;

  GetRandomDecl *GetRandomFn;
  espCreateDecl *espCreateFn;
  espEncapDecl *espEncapFn;
  espDecapDecl *espDecapFn;

  LoggerDecl *LoggerFn;
  destroyDecl *destroyFn;
  shutdownDecl *shutdownFn;
  selfTestDecl *selfTestFn;
  CAPI_ERRORCODE *__funcPad[64-23]; /* Allow up to 64 functions */

  /* IDs to be used in negotiating */
  /* IKE */
  CAPI_UINT8*   ikeGrpXfrmLongName; /* Zero terminated ascii */
  CAPI_UINT8*   ikeGrpXfrmShortName; /* Zero terminated ascii */
  CAPI_UINT16   ikeGroup; /* IDs 32768-65535 are reserved for private use */
  CAPI_UINT16   ikeGroupType;	/* IDs 65001-65535 are reserved for private use */
  CAPI_UINT16   ikeCrypt; /* IDs 65001-65535 are reserved for private use */
  CAPI_UINT16   ikeHash; /* IDs 65001-65535 are reserved for private use */
  CAPI_UINT16   ikeAuthMethod; /* NOTE: only pre-shared key - 1 - is currently supported */
  CAPI_UINT16   ikePrf;  /* IDs 65001-65535 are reserved for private use */
  CAPI_UINT16   ikeKeyLength; /* must be set to 0 if unused */

  CAPI_UINT8    __ikePad[128-22]; /* Allow up to 128 bytes */
  
  /* ESP */
  CAPI_UINT8*   espXfrmLongName; /* Zero terminated ascii */
  CAPI_UINT8*   espXfrmShortName; /* Zero terminated ascii */
  CAPI_UINT16   espAuth; /* IDs 32001-32676 are reserved for private use */
  CAPI_UINT16   espGroup; /* IDs 32001-32676 are reserved for private use */
  CAPI_UINT16   espKeyLength; /* must be set to 0 if unused */
  CAPI_UINT16   espKeyRounds; /* must be set to 0 if unused */
  CAPI_UINT8    espTransform; /* IDs 249-255 are reserved for private use */

  CAPI_UINT8    __espPad[128-17]; /* Allow up to 128 bytes */

  /* ID TYPE */
  CAPI_UINT8*   pluginShortName; /* Zero terminated ascii */
  CAPI_UINT8*   pluginLongName;  /* Zero terminated ascii */
  CAPI_UINT8    idType; /* NOTE: only ID_KEY_ID - 11 - is currently supported */

  CAPI_UINT8    __miscPad[128-9]; /* Allow up to 128 bytes */
};

typedef struct plugin_init_in {
  CAPI_UINT32 maxSessions;
  CAPI_UINT32 model;
  CAPI_UINT32 serial;
  CAPI_UINT32 apiVersionMajor;
  CAPI_UINT32 apiVersionMinor;
  CAPI_UINT32 time;
  struct capi_blob obj;
  struct capi_blob lic;
  struct capi_blob cfg;
  struct capi_tm gmtime;
  CAPI_TCHAR* modelName;
  LoggerDecl *LoggerFn;
  CAPI_UINT8  __pad[128-102]; /* keep total struct size at 128 */
} _plugin_init_in_;

typedef struct plugin_init_out {
  CAPI_UINT32 requiredMem;
  CAPI_UINT8* vendorid;
  struct capi_blob  cfg;
  CAPI_UINT8  __pad[128-16]; /* keep total struct size at 128 */
} _plugin_init_out_;

#if defined __cplusplus
extern "C" {
#endif

typedef CAPI_ERRORCODE plugin_initDecl(struct plugin_hdl *,
				       const struct plugin_init_in *,
				       struct plugin_init_out *);
#if defined __cplusplus
}
#endif

#define NONCELEN 16
#define CKYLEN 8
#define PSKLEN 34

static const CAPI_UINT32 szCESpskHalf = 14;
static const CAPI_UINT32 szPLUGINpskHalf = PSKLEN/2;
static const unsigned int L_N = 2;

#endif /* _PLUGIN_CAPI_H_ */
