#ifndef _SYS_CRYPTO_DCA_H
#define _SYS_CRYPTO_DCA_H
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/types.h>
#include <sys/varargs.h>
#include <sys/crypto/spi.h>
#define DRIVER "dca"
#define DCA_MANUFACTURER_ID "SUNWdca"
#ifdef _KERNEL
#define MCR1LOWATER 16
#define MCR1HIWATER 24
#define MCR1MAXREQS 8
#define MCR2LOWATER 16
#define MCR2HIWATER 24
#define MCR2MAXREQS 4
#define MAXMCR 2
#define MAXREQSPERMCR 16
#define MAXFRAGS 6
#define MAXWORK 6
#if defined(i386) || defined(__i386) || defined(__amd64)
#define MAXPACKET 0xefff
#else
#define MAXPACKET 0xffff
#endif
#define DESBLOCK 8
#define DSAPARTLEN 20
#define DSASIGLEN 40
#define SHA1LEN 20
#define SECOND 1000000
#define MSEC 1000
#define DES_KEYSIZE 8
#define DES_IV_LEN 8
#define DES3_KEYSIZE (3 * DES_KEYSIZE)
#define MD5_HMAC_BLOCK_SIZE 64
#define MD5_HMAC_MIN_KEY_LEN 1
#define MD5_HMAC_MAX_KEY_LEN 64
#define SHA1_HMAC_BLOCK_SIZE 64
#define SHA1_HMAC_MIN_KEY_LEN 1
#define SHA1_HMAC_MAX_KEY_LEN 64
#define DES_KEY_LEN 8
#define DES3_MIN_KEY_LEN 16
#define DES3_MAX_KEY_LEN 24
#define DSA_MIN_KEY_LEN 64
#define DSA_MAX_KEY_LEN 128
#define RSA_MIN_KEY_LEN 32
#define RSA_MAX_KEY_LEN 256
#define DCA_RSA_ENC 0
#define DCA_RSA_DEC 1
#define DCA_RSA_SIGN 2
#define DCA_RSA_VRFY 3
#define DCA_RSA_SIGNR 4
#define DCA_RSA_VRFYR 5
#define DCA_DSA_SIGN 0
#define DCA_DSA_VRFY 1
typedef enum dca_fma_eclass {
DCA_FM_ECLASS_HW_DEVICE = 0,
DCA_FM_ECLASS_HW_TIMEOUT,
DCA_FM_ECLASS_NONE
} dca_fma_eclass_t;
typedef struct dca dca_t;
typedef struct dca_chain dca_chain_t;
typedef struct dca_listnode dca_listnode_t;
typedef struct dca_worklist dca_worklist_t;
typedef struct dca_work dca_work_t;
typedef struct dca_request dca_request_t;
typedef struct dca_stat dca_stat_t;
typedef struct dca_cookie dca_cookie_t;
typedef struct dca_device dca_device_t;
struct dca_device {
ushort_t dd_vendor_id;
ushort_t dd_device_id;
char *dd_model;
};
struct dca_chain {
caddr_t dc_desc_kaddr;
size_t dc_buffer_length;
ddi_dma_handle_t dc_buffer_dmah;
caddr_t dc_buffer_kaddr;
uint32_t dc_desc_paddr;
uint32_t dc_buffer_paddr;
uint32_t dc_next_paddr;
};
struct dca_listnode {
dca_listnode_t *dl_next;
dca_listnode_t *dl_prev;
dca_listnode_t *dl_next2;
dca_listnode_t *dl_prev2;
};
typedef enum dca_mech_type {
DES_CBC_MECH_INFO_TYPE,
DES3_CBC_MECH_INFO_TYPE,
DSA_MECH_INFO_TYPE,
RSA_X_509_MECH_INFO_TYPE,
RSA_PKCS_MECH_INFO_TYPE
} dca_mech_type_t;
#define SUN_CKM_DSA "CKM_DSA"
struct dca_rng {
uint32_t dr_chunklen;
};
union dca_parameters {
struct dca_rng dp_rng;
};
typedef struct dca_ctx {
crypto_mech_type_t ctx_cm_type;
int mode;
int atomic;
uchar_t *mod;
unsigned modlen;
unsigned pqfix;
uint32_t iv[2];
uint32_t key[6];
int residlen;
uchar_t resid[DESBLOCK];
int activeresidlen;
uchar_t activeresid[DESBLOCK];
crypto_data_t in_dup;
} dca_ctx_t;
struct dca_request {
dca_listnode_t dr_linkage;
uint16_t dr_pkt_length;
crypto_req_handle_t dr_kcf_req;
dca_t *dr_dca;
dca_worklist_t *dr_wlp;
crypto_data_t *dr_in;
crypto_data_t *dr_out;
dca_ctx_t dr_ctx;
size_t dr_dma_size;
uint32_t dr_ctx_paddr;
caddr_t dr_ctx_kaddr;
ddi_acc_handle_t dr_ctx_acch;
ddi_dma_handle_t dr_ctx_dmah;
ddi_acc_handle_t dr_ibuf_acch;
ddi_dma_handle_t dr_ibuf_dmah;
caddr_t dr_ibuf_kaddr;
uint32_t dr_ibuf_paddr;
ddi_acc_handle_t dr_obuf_acch;
ddi_dma_handle_t dr_obuf_dmah;
caddr_t dr_obuf_kaddr;
uint32_t dr_obuf_paddr;
uint32_t dr_in_paddr;
uint32_t dr_out_paddr;
uint32_t dr_in_next;
uint32_t dr_out_next;
uint16_t dr_in_len;
uint16_t dr_out_len;
void (*dr_callback)(dca_request_t *, int);
uint32_t dr_flags;
void *dr_context;
union dca_parameters dr_param;
int dr_job_stat;
int dr_byte_stat;
dca_chain_t dr_ibuf_head;
dca_chain_t dr_obuf_head;
dca_chain_t dr_chain_in_head;
ddi_dma_handle_t dr_chain_in_dmah;
dca_chain_t dr_chain_out_head;
ddi_dma_handle_t dr_chain_out_dmah;
int dr_offset;
int destroy;
};
#define DR_INPLACE 0x002
#define DR_SCATTER 0x004
#define DR_GATHER 0x008
#define DR_NOCACHE 0x020
#define DR_ENCRYPT 0x040
#define DR_DECRYPT 0x080
#define DR_TRIPLE 0x100
#define DR_ATOMIC 0x200
struct dca_work {
dca_listnode_t dw_linkage;
dca_worklist_t *dw_wlp;
ddi_acc_handle_t dw_mcr_acch;
ddi_dma_handle_t dw_mcr_dmah;
caddr_t dw_mcr_kaddr;
uint32_t dw_mcr_paddr;
dca_request_t *dw_reqs[MAXREQSPERMCR];
clock_t dw_lbolt;
};
#define MCR1 0x1
#define MCR2 0x2
struct dca_worklist {
dca_t *dwl_dca;
crypto_kcf_provider_handle_t dwl_prov;
char dwl_name[16];
int dwl_mcr;
kmutex_t dwl_lock;
kmutex_t dwl_freelock;
kmutex_t dwl_freereqslock;
kcondvar_t dwl_cv;
dca_listnode_t dwl_freereqs;
dca_listnode_t dwl_waitq;
dca_listnode_t dwl_freework;
dca_listnode_t dwl_runq;
timeout_id_t dwl_schedtid;
clock_t dwl_lastsubmit;
int dwl_count;
int dwl_busy;
int dwl_lowater;
int dwl_hiwater;
int dwl_reqspermcr;
int dwl_drain;
u_longlong_t dwl_submit;
u_longlong_t dwl_flowctl;
};
#define CMD_IPSEC 0x0
#define CMD_SSLMAC 0x1
#define CMD_TLSMAC 0x2
#define CMD_3DES 0x3
#define CMD_RC4 0x4
#define CMD_PUREHASH 0x5
#define CMD_DHPUBLIC 0x1
#define CMD_DHSHARED 0x2
#define CMD_RSAPUBLIC 0x3
#define CMD_RSAPRIVATE 0x4
#define CMD_DSASIGN 0x5
#define CMD_DSAVERIFY 0x6
#define CMD_RNGDIRECT 0x41
#define CMD_RNGSHA1 0x42
#define CMD_MODADD 0x43
#define CMD_MODSUB 0x44
#define CMD_MODMUL 0x45
#define CMD_MODREM 0x46
#define CMD_MODEXP 0x47
#define CMD_MODINV 0x48
#define DS_3DESJOBS 0
#define DS_3DESBYTES 1
#define DS_RSAPUBLIC 2
#define DS_RSAPRIVATE 3
#define DS_DSASIGN 4
#define DS_DSAVERIFY 5
#define DS_RNGJOBS 6
#define DS_RNGBYTES 7
#define DS_RNGSHA1JOBS 8
#define DS_RNGSHA1BYTES 9
#define DS_MAX 10
#if 0
#define DS_RC4JOBS 11
#define DS_RC4BYTES 12
#define DS_DHPUBLIC 13
#define DS_DHSECRET 14
#endif
struct dca_stat {
kstat_named_t ds_status;
kstat_named_t ds_algs[DS_MAX];
struct {
kstat_named_t ds_submit;
kstat_named_t ds_flowctl;
kstat_named_t ds_lowater;
kstat_named_t ds_hiwater;
kstat_named_t ds_maxreqs;
} ds_mcr[MAXMCR];
};
struct dca_cookie {
kmutex_t dc_mx;
kcondvar_t dc_cv;
int dc_outstanding;
int dc_status;
};
struct dca {
dev_info_t *dca_dip;
kmutex_t dca_intrlock;
caddr_t dca_regs;
ddi_acc_handle_t dca_regs_handle;
ddi_iblock_cookie_t dca_icookie;
timeout_id_t dca_jobtid;
ulong_t dca_pagesize;
unsigned dca_flags;
dca_worklist_t dca_worklist[MAXMCR];
char *dca_model;
ushort_t dca_devid;
kstat_t *dca_ksp;
kstat_t *dca_intrstats;
u_longlong_t dca_stats[DS_MAX];
char *dca_buf1;
char *dca_buf2;
char *dca_buf_ptr;
int dca_index;
uint32_t dca_random_filling;
kmutex_t dca_random_lock;
int fm_capabilities;
kmutex_t dca_ctx_list_lock;
dca_listnode_t dca_ctx_list;
};
#define DCA_FAILED 0x1
#define DCA_POWERMGMT 0x4
#define DCA_RNGSHA1 0x8
#define KIOIP(dca) KSTAT_INTR_PTR((dca)->dca_intrstats)
typedef enum dca_sg_param {
DCA_SG_CONTIG = 1,
DCA_SG_WALIGN,
DCA_SG_PALIGN
} dca_sg_param_t;
#define FALSE 0
#define TRUE 1
#define PCI_VENID 0x00
#define PCI_DEVID 0x02
#define PCI_COMM 0x04
#define PCI_STATUS 0x06
#define PCI_REVID 0x08
#define PCI_PROGCLASS 0x09
#define PCI_SUBCLASS 0x0A
#define PCI_CACHELINESZ 0x0C
#define PCI_LATTMR 0x0D
#define PCI_BIST 0x0F
#define PCI_SUBVENID 0x2C
#define PCI_SUBSYSID 0x2E
#define PCI_MINGNT 0x3E
#define PCI_MAXLAT 0x3F
#define PCI_TRDYTO 0x40
#define PCI_RETRIES 0x41
#define PCICOMM_FBBE 0x0200
#define PCICOMM_SEE 0x0100
#define PCICOMM_PEE 0x0040
#define PCICOMM_MWIE 0x0010
#define PCICOMM_BME 0x0004
#define PCICOMM_MAE 0x0002
#define PCISTAT_PERR 0x8000
#define PCISTAT_SERR 0x4000
#define PCISTAT_MABRT 0x2000
#define PCISTAT_TABRT 0x1000
#define PCISTAT_TABRTS 0x0800
#define PCISTAT_PARITY 0x0100
#define PCIREVID_DOMESTIC 0x01
#define PCIREVID_EXPORT 0xE1
#define PCIBIST_CAP 0x80
#define PCIBIST_START 0x40
#define PCIBIST_ERRMASK 0x0F
#define CSR_MCR1 0x00
#define CSR_DMACTL 0x04
#define CSR_DMASTAT 0x08
#define CSR_DMAEA 0x0C
#define CSR_MCR2 0x10
#define DMACTL_RESET 0x80000000U
#define DMACTL_MCR2IE 0x40000000U
#define DMACTL_MCR1IE 0x20000000U
#define DMACTL_OFM 0x10000000U
#define DMACTL_BE32 0x08000000U
#define DMACTL_BE64 0x04000000U
#define DMACTL_EIE 0x02000000U
#define DMACTL_RNGMASK 0x01800000U
#define DMACTL_RNG1 0x00000000U
#define DMACTL_RNG4 0x00800000U
#define DMACTL_RNG8 0x01000000U
#define DMACTL_RNG16 0x01800000U
#define DMACTL_MODNORM 0x00400000U
#define DMACTL_RD256 0x00020000U
#define DMACTL_FRAGMASK 0x0000FFFFU
#define DMASTAT_MAIP 0x80000000U
#define DMASTAT_MCR1FULL 0x40000000U
#define DMASTAT_MCR1INT 0x20000000U
#define DMASTAT_ERRINT 0x10000000U
#define DMASTAT_MCR2FULL 0x08000000U
#define DMASTAT_MCR2INT 0x04000000U
#define DMASTAT_INTERRUPTS 0x34000000U
#define MCR_COUNT 0
#define MCR_FLAGS 2
#define MCR_CTXADDR 4
#define MCR_SIZE (4 + MAXREQSPERMCR * ((2 * DESC_SIZE) + 8))
#define MCRFLAG_FINISHED 0x0001
#define MCRFLAG_ERROR 0x0002
#define MCRFLAG_ERRORMASK 0xff00
#define DESC_BUFADDR 0
#define DESC_NEXT 4
#define DESC_LENGTH 8
#define DESC_RSVD 10
#define DESC_SIZE 16
#define CTX_LENGTH 0
#define CTX_CMD 2
#define CTX_MAXLENGTH 768
#define CTX_3DESDIRECTION 4
#define CTX_3DESKEY1HI 8
#define CTX_3DESKEY1LO 12
#define CTX_3DESKEY2HI 16
#define CTX_3DESKEY2LO 20
#define CTX_3DESKEY3HI 24
#define CTX_3DESKEY3LO 28
#define CTX_3DESIVHI 32
#define CTX_3DESIVLO 36
#define CTX_IPSECFLAGS 4
#define CTX_IPSECOFFSET 6
#define CTX_IPSECKEY1HI 8
#define CTX_IPSECKEY1LO 12
#define CTX_IPSECKEY2HI 16
#define CTX_IPSECKEY2LO 20
#define CTX_IPSECKEY3HI 24
#define CTX_IPSECKEY3LO 28
#define CTX_IPSECIVHI 32
#define CTX_IPSECIVLO 36
#define CTX_IPSECHMACINNER1 40
#define CTX_IPSECHMACINNER2 44
#define CTX_IPSECHMACINNER3 48
#define CTX_IPSECHMACINNER4 52
#define CTX_IPSECHMACINNER5 56
#define CTX_IPSECHMACOUTER1 60
#define CTX_IPSECHMACOUTER2 64
#define CTX_IPSECHMACOUTER3 68
#define CTX_IPSECHMACOUTER4 72
#define CTX_IPSECHMACOUTER5 76
#define CTX_RSAEXPLEN 4
#define CTX_RSAMODLEN 6
#define CTX_RSABIGNUMS 8
#define CTX_RSAQLEN 4
#define CTX_RSAPLEN 6
#define CTX_DSAMSGTYPE 4
#define CTX_DSARSVD 6
#define CTX_DSARNG 8
#define CTX_DSAPLEN 10
#define CTX_DSABIGNUMS 12
#define CTX_RNG_LENGTH 64
#define CTX_3DES_LENGTH 64
#define CTX_3DES_DECRYPT 0x4000
#define CTX_3DES_ENCRYPT 0x0000
#define CTX_IPSEC_LENGTH 80
#define CTX_IPSEC_ENCRYPT 0x8000
#define CTX_IPSEC_DECRYPT 0xc000
#define CTX_IPSEC_HMAC_MD5 0x1000
#define CTX_IPSEC_HMAC_SHA1 0x2000
#define CTX_DSAMSGTYPE_SHA1 0
#define CTX_DSAMSGTYPE_TEXT 1
#define CTX_DSARNG_GEN 1
#define CTX_DSARNG_SUPPLY 0
#define PUTMCR32(work, reg, val) \
ddi_put32(work->dw_mcr_acch, \
(uint32_t *)(work->dw_mcr_kaddr + reg), val)
#define PUTMCR16(work, reg, val) \
ddi_put16(work->dw_mcr_acch, \
(uint16_t *)(work->dw_mcr_kaddr + reg), val)
#define GETMCR32(work, reg) \
ddi_get32(work->dw_mcr_acch, (uint32_t *)(work->dw_mcr_kaddr + reg))
#define GETMCR16(work, reg) \
ddi_get16(work->dw_mcr_acch, (uint16_t *)(work->dw_mcr_kaddr + reg))
#define PUTDESC32(req, dc_desc_kaddr, reg, val) \
ddi_put32(req->dr_ctx_acch, \
(uint32_t *)(dc_desc_kaddr + reg), val)
#define PUTDESC16(req, dc_desc_kaddr, reg, val) \
ddi_put16(req->dr_ctx_acch, \
(uint16_t *)(dc_desc_kaddr + reg), val)
#define PUTCTX32(req, reg, val) \
ddi_put32(req->dr_ctx_acch, \
(uint32_t *)(req->dr_ctx_kaddr + reg), val)
#define PUTCTX16(req, reg, val) \
ddi_put16(req->dr_ctx_acch, \
(uint16_t *)(req->dr_ctx_kaddr + reg), val)
#define CTXBCOPY(req, src, dst, count) \
ddi_rep_put8(req->dr_ctx_acch, (uchar_t *)src, (uchar_t *)dst, count, \
DDI_DEV_AUTOINCR)
#define GETCSR(dca, reg) \
ddi_get32(dca->dca_regs_handle, (uint_t *)(dca->dca_regs + reg))
#define PUTCSR(dca, reg, val) \
ddi_put32(dca->dca_regs_handle, (uint_t *)(dca->dca_regs + reg), val)
#define SETBIT(dca, reg, val) \
PUTCSR(dca, reg, GETCSR(dca, reg) | val)
#define CLRBIT(dca, reg, val) \
PUTCSR(dca, reg, GETCSR(dca, reg) & ~val)
#define ROUNDUP(a, n) (((a) + ((n) - 1)) & ~((n) - 1))
#define ROUNDDOWN(a, n) (((a) & ~((n) - 1)))
#define HIDBLWORD(x) (((x) & 0xffffffff00000000ULL) >> 32)
#define LODBLWORD(x) ((x) & 0xffffffffULL)
#define CHECK_REGS(dca) ddi_check_acc_handle(dca->dca_regs_handle)
#define QEMPTY(q) ((q)->dl_next == (q))
#define BITS2BYTES(b) ((b) >> 3)
#define WORKLIST(dca, mcr) (&((dca)->dca_worklist[mcr - 1]))
#ifdef DEBUG
#define DWARN 0x0001
#define DPCI 0x0002
#define DINTR 0x0004
#define DSTART 0x0008
#define DRECLAIM 0x0010
#define DCHATTY 0x0020
#define DMOD 0x0040
#define DENTRY 0x0080
void dca_dprintf(dca_t *, int, const char *, ...);
#define DBG dca_dprintf
#else
#define DBG(dca, lvl, ...)
#endif
#define CKO_PUBLIC_KEY 0x00000002UL
#define CKO_PRIVATE_KEY 0x00000003UL
#define CKA_CLASS 0x00000000UL
#define CKA_VALUE 0x00000011UL
#define CKA_KEY_TYPE 0x00000100UL
#define CKA_MODULUS 0x00000120UL
#define CKA_PUBLIC_EXPONENT 0x00000122UL
#define CKA_PRIVATE_EXPONENT 0x00000123UL
#define CKA_PRIME_1 0x00000124UL
#define CKA_PRIME_2 0x00000125UL
#define CKA_EXPONENT_1 0x00000126UL
#define CKA_EXPONENT_2 0x00000127UL
#define CKA_COEFFICIENT 0x00000128UL
#define CKA_PRIME 0x00000130UL
#define CKA_SUBPRIME 0x00000131UL
#define CKA_BASE 0x00000132UL
extern int dca_mindma;
extern int dca_hardening;
void dca_error(dca_t *, const char *, ...);
void dca_diperror(dev_info_t *, const char *, ...);
void dca_dipverror(dev_info_t *, const char *, va_list);
int dca_3desctxinit(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *,
int, int);
int dca_3des(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
crypto_req_handle_t, int);
int dca_3desupdate(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
crypto_req_handle_t, int);
int dca_3desfinal(crypto_ctx_t *, crypto_data_t *, int);
int dca_3desatomic(crypto_provider_handle_t, crypto_session_id_t,
crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
int, crypto_req_handle_t, int);
void dca_3desctxfree(void *);
int dca_rsastart(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
crypto_req_handle_t, int);
int dca_rsainit(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *, int);
void dca_rsactxfree(void *);
int dca_rsaatomic(crypto_provider_handle_t, crypto_session_id_t,
crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
int, crypto_req_handle_t, int);
int dca_dsa_sign(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
crypto_req_handle_t);
int dca_dsa_verify(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
crypto_req_handle_t);
int dca_dsainit(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *, int,
int);
void dca_dsactxfree(void *);
int dca_dsaatomic(crypto_provider_handle_t, crypto_session_id_t,
crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
int, crypto_req_handle_t, int);
int dca_rng(dca_t *, uchar_t *, size_t len, crypto_req_handle_t);
int dca_random_buffer(dca_t *dca, caddr_t buf, int len);
int dca_random_init();
void dca_random_fini();
void dca_ksinit(dca_t *);
void dca_rmqueue(dca_listnode_t *);
dca_request_t *dca_getreq(dca_t *, int, int);
void dca_freereq(dca_request_t *);
int dca_bindchains(dca_request_t *, size_t, size_t);
int dca_unbindchains(dca_request_t *);
int dca_start(dca_t *, dca_request_t *, int, int);
void dca_done(dca_request_t *, int);
void dca_destroyreq(dca_request_t *);
int dca_length(crypto_data_t *);
int dca_gather(crypto_data_t *, char *, int, int);
int dca_resid_gather(crypto_data_t *, char *, int *, char *, int);
int dca_scatter(const char *, crypto_data_t *, int, int);
int dca_bcmp_reverse(const void *s1, const void *s2, size_t n);
int dca_dupcrypto(crypto_data_t *, crypto_data_t *);
int dca_verifyio(crypto_data_t *, crypto_data_t *);
int dca_getbufbytes(crypto_data_t *, size_t, int, uchar_t *);
int dca_sgcheck(dca_t *, crypto_data_t *, dca_sg_param_t);
crypto_object_attribute_t *
dca_get_key_attr(crypto_key_t *);
int dca_attr_lookup_uint32(crypto_object_attribute_t *, uint_t, uint64_t,
uint32_t *);
int dca_attr_lookup_uint8_array(crypto_object_attribute_t *, uint_t,
uint64_t, void **, unsigned int *);
crypto_object_attribute_t *
dca_find_attribute(crypto_object_attribute_t *, uint_t, uint64_t);
caddr_t dca_bufdaddr(crypto_data_t *);
void dca_rcoalesce(dca_request_t *, int);
void dca_runcoalesce(dca_request_t *);
int dca_bitlen(unsigned char *, int);
uint16_t dca_padhalf(int);
uint16_t dca_padfull(int);
void dca_reverse(void *, void *, int, int);
int dca_numcmp(caddr_t, int, caddr_t, int);
int dca_check_dma_handle(dca_t *dca, ddi_dma_handle_t handle,
dca_fma_eclass_t eclass_index);
int dca_free_context(crypto_ctx_t *ctx);
#endif
#ifdef __cplusplus
}
#endif
#endif