/*
- * linux/drivers/s390/misc/z90hardware.c
+ * linux/drivers/s390/crypto/z90hardware.c
*
- * z90crypt 1.3.1
+ * z90crypt 1.3.3
*
- * Copyright (C) 2001, 2004 IBM Corporation
+ * Copyright (C) 2001, 2005 IBM Corporation
* Author(s): Robert Burroughs (burrough@us.ibm.com)
- * Eric Rossman (edrossma@us.ibm.com)
+ * Eric Rossman (edrossma@us.ibm.com)
*
* Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
*
*
* 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
#include "z90crypt.h"
#include "z90common.h"
-#define VERSION_Z90HARDWARE_C "$Revision: 1.19 $"
-
-char z90chardware_version[] __initdata =
- "z90hardware.o (" VERSION_Z90HARDWARE_C "/"
- VERSION_Z90COMMON_H "/" VERSION_Z90CRYPT_H ")";
-
struct cca_token_hdr {
unsigned char token_identifier;
unsigned char version;
unsigned char right[4];
unsigned char reserved3[2];
unsigned char reserved4[2];
- unsigned char pfs[4];
+ unsigned char apfs[4];
unsigned int offset1;
unsigned int offset2;
unsigned int offset3;
unsigned char svr_name[8];
};
-struct CPRBX {
- unsigned short cprb_len;
- unsigned char cprb_ver_id;
- unsigned char pad_000[3];
- unsigned char func_id[2];
- unsigned char cprb_flags[4];
- unsigned int req_parml;
- unsigned int req_datal;
- unsigned int rpl_msgbl;
- unsigned int rpld_parml;
- unsigned int rpl_datal;
- unsigned int rpld_datal;
- unsigned int req_extbl;
- unsigned char pad_001[4];
- unsigned int rpld_extbl;
- unsigned char req_parmb[16];
- unsigned char req_datab[16];
- unsigned char rpl_parmb[16];
- unsigned char rpl_datab[16];
- unsigned char req_extb[16];
- unsigned char rpl_extb[16];
- unsigned short ccp_rtcode;
- unsigned short ccp_rscode;
- unsigned int mac_data_len;
- unsigned char logon_id[8];
- unsigned char mac_value[8];
- unsigned char mac_content_flgs;
- unsigned char pad_002;
- unsigned short domain;
- unsigned char pad_003[12];
- unsigned char pad_004[36];
-};
-
struct type6_msg {
struct type6_hdr header;
struct CPRB CPRB;
};
-union request_msg {
- union type4_msg t4msg;
- struct type6_msg t6msg;
-};
-
-struct request_msg_ext {
- int q_nr;
- unsigned char *psmid;
- union request_msg reqMsg;
-};
-
-struct type82_hdr {
- unsigned char reserved1;
- unsigned char type;
- unsigned char reserved2[2];
- unsigned char reply_code;
- unsigned char reserved3[3];
-};
-
-#define TYPE82_RSP_CODE 0x82
-
-#define REPLY_ERROR_MACHINE_FAILURE 0x10
-#define REPLY_ERROR_PREEMPT_FAILURE 0x12
-#define REPLY_ERROR_CHECKPT_FAILURE 0x14
-#define REPLY_ERROR_MESSAGE_TYPE 0x20
-#define REPLY_ERROR_INVALID_COMM_CD 0x21
-#define REPLY_ERROR_INVALID_MSG_LEN 0x23
-#define REPLY_ERROR_RESERVD_FIELD 0x24
-#define REPLY_ERROR_FORMAT_FIELD 0x29
-#define REPLY_ERROR_INVALID_COMMAND 0x30
-#define REPLY_ERROR_MALFORMED_MSG 0x40
-#define REPLY_ERROR_RESERVED_FIELD 0x50
-#define REPLY_ERROR_WORD_ALIGNMENT 0x60
-#define REPLY_ERROR_MESSAGE_LENGTH 0x80
-#define REPLY_ERROR_OPERAND_INVALID 0x82
-#define REPLY_ERROR_OPERAND_SIZE 0x84
-#define REPLY_ERROR_EVEN_MOD_IN_OPND 0x85
-#define REPLY_ERROR_TRANSPORT_FAIL 0x90
-#define REPLY_ERROR_PACKET_TRUNCATED 0xA0
-#define REPLY_ERROR_ZERO_BUFFER_LEN 0xB0
-
struct type86_hdr {
unsigned char reserved1;
unsigned char type;
#define TYPE86_FMT2 0x02
struct type86_fmt2_msg {
- struct type86_hdr hdr;
+ struct type86_hdr header;
unsigned char reserved[4];
unsigned char apfs[4];
unsigned int count1;
unsigned int offset2;
unsigned int count3;
unsigned int offset3;
- unsigned int ount4;
+ unsigned int count4;
unsigned int offset4;
};
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
};
-static struct function_and_rules_block static_pkd_function_and_rulesX = {
+static struct function_and_rules_block static_pkd_function_and_rulesX_MCL2 = {
{0x50,0x44},
{0x00,0x0A},
{'P','K','C','S','-','1','.','2'}
};
-static struct function_and_rules_block static_pke_function_and_rulesX = {
+static struct function_and_rules_block static_pke_function_and_rulesX_MCL2 = {
{0x50,0x4B},
{0x00,0x0A},
{'Z','E','R','O','-','P','A','D'}
};
+static struct function_and_rules_block static_pkd_function_and_rulesX = {
+ {0x50,0x44},
+ {0x00,0x0A},
+ {'Z','E','R','O','-','P','A','D'}
+};
+
+static struct function_and_rules_block static_pke_function_and_rulesX = {
+ {0x50,0x4B},
+ {0x00,0x0A},
+ {'M','R','P',' ',' ',' ',' ',' '}
+};
+
+static unsigned char static_PKE_function_code[2] = {0x50, 0x4B};
+
struct T6_keyBlock_hdrX {
unsigned short blen;
unsigned short ulen;
#define FIXED_TYPE6_CR_LENX 0x000001E3
-#ifndef MAX_RESPONSE_SIZE
#define MAX_RESPONSE_SIZE 0x00000710
#define MAX_RESPONSEX_SIZE 0x0000077C
-#endif
#define RESPONSE_CPRB_SIZE 0x000006B8
#define RESPONSE_CPRBX_SIZE 0x00000724
-#define CALLER_HEADER 12
+struct type50_hdr {
+ u8 reserved1;
+ u8 msg_type_code;
+ u16 msg_len;
+ u8 reserved2;
+ u8 ignored;
+ u16 reserved3;
+};
-static unsigned char static_PKE_function_code[2] = {0x50, 0x4B};
+#define TYPE50_TYPE_CODE 0x50
+
+#define TYPE50_MEB1_LEN (sizeof(struct type50_meb1_msg))
+#define TYPE50_MEB2_LEN (sizeof(struct type50_meb2_msg))
+#define TYPE50_CRB1_LEN (sizeof(struct type50_crb1_msg))
+#define TYPE50_CRB2_LEN (sizeof(struct type50_crb2_msg))
+
+#define TYPE50_MEB1_FMT 0x0001
+#define TYPE50_MEB2_FMT 0x0002
+#define TYPE50_CRB1_FMT 0x0011
+#define TYPE50_CRB2_FMT 0x0012
+
+struct type50_meb1_msg {
+ struct type50_hdr header;
+ u16 keyblock_type;
+ u8 reserved[6];
+ u8 exponent[128];
+ u8 modulus[128];
+ u8 message[128];
+};
+
+struct type50_meb2_msg {
+ struct type50_hdr header;
+ u16 keyblock_type;
+ u8 reserved[6];
+ u8 exponent[256];
+ u8 modulus[256];
+ u8 message[256];
+};
+
+struct type50_crb1_msg {
+ struct type50_hdr header;
+ u16 keyblock_type;
+ u8 reserved[6];
+ u8 p[64];
+ u8 q[64];
+ u8 dp[64];
+ u8 dq[64];
+ u8 u[64];
+ u8 message[128];
+};
+
+struct type50_crb2_msg {
+ struct type50_hdr header;
+ u16 keyblock_type;
+ u8 reserved[6];
+ u8 p[128];
+ u8 q[128];
+ u8 dp[128];
+ u8 dq[128];
+ u8 u[128];
+ u8 message[256];
+};
+
+union type50_msg {
+ struct type50_meb1_msg meb1;
+ struct type50_meb2_msg meb2;
+ struct type50_crb1_msg crb1;
+ struct type50_crb2_msg crb2;
+};
+
+struct type80_hdr {
+ u8 reserved1;
+ u8 type;
+ u16 len;
+ u8 code;
+ u8 reserved2[3];
+ u8 reserved3[8];
+};
+
+#define TYPE80_RSP_CODE 0x80
+
+struct error_hdr {
+ unsigned char reserved1;
+ unsigned char type;
+ unsigned char reserved2[2];
+ unsigned char reply_code;
+ unsigned char reserved3[3];
+};
+
+#define TYPE82_RSP_CODE 0x82
+#define TYPE88_RSP_CODE 0x88
+
+#define REP82_ERROR_MACHINE_FAILURE 0x10
+#define REP82_ERROR_PREEMPT_FAILURE 0x12
+#define REP82_ERROR_CHECKPT_FAILURE 0x14
+#define REP82_ERROR_MESSAGE_TYPE 0x20
+#define REP82_ERROR_INVALID_COMM_CD 0x21
+#define REP82_ERROR_INVALID_MSG_LEN 0x23
+#define REP82_ERROR_RESERVD_FIELD 0x24
+#define REP82_ERROR_FORMAT_FIELD 0x29
+#define REP82_ERROR_INVALID_COMMAND 0x30
+#define REP82_ERROR_MALFORMED_MSG 0x40
+#define REP82_ERROR_RESERVED_FIELDO 0x50
+#define REP82_ERROR_WORD_ALIGNMENT 0x60
+#define REP82_ERROR_MESSAGE_LENGTH 0x80
+#define REP82_ERROR_OPERAND_INVALID 0x82
+#define REP82_ERROR_OPERAND_SIZE 0x84
+#define REP82_ERROR_EVEN_MOD_IN_OPND 0x85
+#define REP82_ERROR_RESERVED_FIELD 0x88
+#define REP82_ERROR_TRANSPORT_FAIL 0x90
+#define REP82_ERROR_PACKET_TRUNCATED 0xA0
+#define REP82_ERROR_ZERO_BUFFER_LEN 0xB0
+
+#define REP88_ERROR_MODULE_FAILURE 0x10
+#define REP88_ERROR_MODULE_TIMEOUT 0x11
+#define REP88_ERROR_MODULE_NOTINIT 0x13
+#define REP88_ERROR_MODULE_NOTAVAIL 0x14
+#define REP88_ERROR_MODULE_DISABLED 0x15
+#define REP88_ERROR_MODULE_IN_DIAGN 0x17
+#define REP88_ERROR_FASTPATH_DISABLD 0x19
+#define REP88_ERROR_MESSAGE_TYPE 0x20
+#define REP88_ERROR_MESSAGE_MALFORMD 0x22
+#define REP88_ERROR_MESSAGE_LENGTH 0x23
+#define REP88_ERROR_RESERVED_FIELD 0x24
+#define REP88_ERROR_KEY_TYPE 0x34
+#define REP88_ERROR_INVALID_KEY 0x82
+#define REP88_ERROR_OPERAND 0x84
+#define REP88_ERROR_OPERAND_EVEN_MOD 0x85
+
+#define CALLER_HEADER 12
static inline int
testq(int q_nr, int *q_depth, int *dev_type, struct ap_status_word *stat)
int ccode;
asm volatile
-#ifdef __s390x__
+#ifdef CONFIG_64BIT
(" llgfr 0,%4 \n"
" slgr 1,1 \n"
" lgr 2,1 \n"
int ccode;
asm volatile
-#ifdef __s390x__
+#ifdef CONFIG_64BIT
(" llgfr 0,%2 \n"
" lghi 1,1 \n"
" sll 1,24 \n"
int ccode;
asm volatile
-#ifdef __s390x__
+#ifdef CONFIG_64BIT
(" lgr 6,%3 \n"
" llgfr 7,%2 \n"
" llgt 0,0(6) \n"
int ccode;
asm volatile
-#ifdef __s390x__
+#ifdef CONFIG_64BIT
(" llgfr 0,%2 \n"
" lgr 3,%4 \n"
" lgr 6,%3 \n"
stat = HD_ONLINE;
*q_depth = t_depth + 1;
switch (t_dev_type) {
- case OTHER_HW:
- case OTHER2_HW:
- stat = HD_NOT_THERE;
- *dev_type = NILDEV;
- break;
case PCICA_HW:
*dev_type = PCICA;
break;
*dev_type = PCICC;
break;
case PCIXCC_HW:
- *dev_type = PCIXCC;
+ *dev_type = PCIXCC_UNK;
+ break;
+ case CEX2C_HW:
+ *dev_type = CEX2C;
+ break;
+ case CEX2A_HW:
+ *dev_type = CEX2A;
break;
default:
*dev_type = NILDEV;
default:
stat = HD_NOT_THERE;
break_out = 1;
+ break;
}
if (break_out)
break;
switch (stat_word.response_code) {
case AP_RESPONSE_NORMAL:
stat = DEV_ONLINE;
- if (stat_word.q_stat_flags &
- AP_Q_STATUS_EMPTY)
+ if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY)
break_out = 1;
break;
case AP_RESPONSE_Q_NOT_AVAIL:
- stat = DEV_GONE;
- break_out = 1;
- break;
case AP_RESPONSE_DECONFIGURED:
- stat = DEV_GONE;
- break_out = 1;
- break;
case AP_RESPONSE_CHECKSTOPPED:
stat = DEV_GONE;
break_out = 1;
default:
stat = DEV_GONE;
break_out = 1;
+ break;
}
if (break_out == 1)
break;
struct ap_status_word stat_word;
enum devstat stat;
int ccode;
+ u32 *q_nr_p = (u32 *)msg_ext;
- ((struct request_msg_ext *) msg_ext)->q_nr =
- (dev_nr << SKIP_BITL) + cdx;
+ *q_nr_p = (dev_nr << SKIP_BITL) + cdx;
PDEBUG("msg_len passed to sen: %d\n", msg_len);
PDEBUG("q number passed to sen: %02x%02x%02x%02x\n",
msg_ext[0], msg_ext[1], msg_ext[2], msg_ext[3]);
msg_ext[0], msg_ext[1], msg_ext[2], msg_ext[3],
msg_ext[4], msg_ext[5], msg_ext[6], msg_ext[7],
msg_ext[8], msg_ext[9], msg_ext[10], msg_ext[11]);
- print_buffer(msg_ext+12, msg_len);
+ print_buffer(msg_ext+CALLER_HEADER, msg_len);
#endif
ccode = sen(msg_len, msg_ext, &stat_word);
break;
default:
stat = DEV_GONE;
+ break;
}
return stat;
}
enum devstat
-receive_from_AP(int dev_nr, int cdx, int resplen,
- unsigned char *resp, unsigned char *psmid)
+receive_from_AP(int dev_nr, int cdx, int resplen, unsigned char *resp,
+ unsigned char *psmid)
{
int ccode;
struct ap_status_word stat_word;
struct type6_hdr *tp6Hdr_p;
struct CPRB *cprb_p;
struct cca_private_ext_ME *key_p;
+ static int deprecated_msg_count = 0;
mod_len = icaMsg_p->inputdatalength;
tmp_size = FIXED_TYPE6_ME_LEN + mod_len;
return SEN_USER_ERROR;
if (is_common_public_key(temp, mod_len)) {
- PRINTK("Common public key used for modex decrypt\n");
+ if (deprecated_msg_count < 20) {
+ PRINTK("Common public key used for modex decrypt\n");
+ deprecated_msg_count++;
+ if (deprecated_msg_count == 20)
+ PRINTK("No longer issuing messages about common"
+ " public key for modex decrypt.\n");
+ }
return SEN_NOT_AVAIL;
}
temp = key_p->pvtMESec.modulus + sizeof(key_p->pvtMESec.modulus)
- mod_len;
- if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len) != 0)
+ if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len))
return SEN_RELEASED;
if (is_empty(temp, mod_len))
return SEN_USER_ERROR;
{
int mod_len, vud_len, exp_len, key_len;
int pad_len, tmp_size, total_CPRB_len, parmBlock_l, i;
- unsigned char temp_exp[256], *exp_p, *temp;
+ unsigned char *temp_exp, *exp_p, *temp;
struct type6_hdr *tp6Hdr_p;
struct CPRB *cprb_p;
struct cca_public_key *key_p;
struct T6_keyBlock_hdr *keyb_p;
+ temp_exp = kmalloc(256, GFP_KERNEL);
+ if (!temp_exp)
+ return EGETBUFF;
mod_len = icaMsg_p->inputdatalength;
- if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len))
+ if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len)) {
+ kfree(temp_exp);
return SEN_RELEASED;
- if (is_empty(temp_exp, mod_len))
+ }
+ if (is_empty(temp_exp, mod_len)) {
+ kfree(temp_exp);
return SEN_USER_ERROR;
+ }
exp_p = temp_exp;
for (i = 0; i < mod_len; i++)
if (exp_p[i])
break;
- if (i >= mod_len)
+ if (i >= mod_len) {
+ kfree(temp_exp);
return SEN_USER_ERROR;
+ }
exp_len = mod_len - i;
exp_p += i;
sizeof(struct function_and_rules_block));
temp += sizeof(struct function_and_rules_block);
temp += 2;
- if (copy_from_user(temp, icaMsg_p->inputdata, mod_len))
+ if (copy_from_user(temp, icaMsg_p->inputdata, mod_len)) {
+ kfree(temp_exp);
return SEN_RELEASED;
- if (is_empty(temp, mod_len))
+ }
+ if (is_empty(temp, mod_len)) {
+ kfree(temp_exp);
return SEN_USER_ERROR;
- if (temp[0] != 0x00 || temp[1] != 0x02)
+ }
+ if ((temp[0] != 0x00) || (temp[1] != 0x02)) {
+ kfree(temp_exp);
return SEN_NOT_AVAIL;
+ }
for (i = 2; i < mod_len; i++)
if (temp[i] == 0x00)
break;
- if ((i < 9) || (i > (mod_len - 2)))
+ if ((i < 9) || (i > (mod_len - 2))) {
+ kfree(temp_exp);
return SEN_NOT_AVAIL;
+ }
pad_len = i + 1;
vud_len = mod_len - pad_len;
memmove(temp, temp+pad_len, vud_len);
key_p = (struct cca_public_key *)temp;
temp = key_p->pubSec.exponent;
memcpy(temp, exp_p, exp_len);
+ kfree(temp_exp);
temp += exp_len;
if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len))
return SEN_RELEASED;
key_p->pubSec.modulus_bit_len = 8 * mod_len;
key_p->pubSec.modulus_byte_len = mod_len;
key_p->pubSec.exponent_len = exp_len;
- key_p->pubSec.section_length = 12 + mod_len + exp_len;
+ key_p->pubSec.section_length = CALLER_HEADER + mod_len + exp_len;
key_len = key_p->pubSec.section_length + sizeof(struct cca_token_hdr);
key_p->pubHdr.token_length = key_len;
key_len += 4;
static int
ICAMEX_msg_to_type6MEX_msgX(struct ica_rsa_modexpo *icaMsg_p, int cdx,
- int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
+ int *z90cMsg_l_p, struct type6_msg *z90cMsg_p,
+ int dev_type)
{
int mod_len, exp_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l;
int key_len, i;
- unsigned char temp_exp[256], *tgt_p, *temp, *exp_p;
+ unsigned char *temp_exp, *tgt_p, *temp, *exp_p;
struct type6_hdr *tp6Hdr_p;
struct CPRBX *cprbx_p;
struct cca_public_key *key_p;
struct T6_keyBlock_hdrX *keyb_p;
+ temp_exp = kmalloc(256, GFP_KERNEL);
+ if (!temp_exp)
+ return EGETBUFF;
mod_len = icaMsg_p->inputdatalength;
- if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len))
+ if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len)) {
+ kfree(temp_exp);
return SEN_RELEASED;
- if (is_empty(temp_exp, mod_len))
+ }
+ if (is_empty(temp_exp, mod_len)) {
+ kfree(temp_exp);
return SEN_USER_ERROR;
+ }
exp_p = temp_exp;
for (i = 0; i < mod_len; i++)
if (exp_p[i])
break;
- if (i >= mod_len)
+ if (i >= mod_len) {
+ kfree(temp_exp);
return SEN_USER_ERROR;
+ }
exp_len = mod_len - i;
exp_p += i;
PDEBUG("exp_len after computation: %08x\n", exp_len);
cprbx_p->domain = (unsigned short)cdx;
cprbx_p->rpl_msgbl = RESPONSE_CPRBX_SIZE;
tgt_p += sizeof(struct CPRBX);
- memcpy(tgt_p, &static_pke_function_and_rulesX,
- sizeof(struct function_and_rules_block));
+ if (dev_type == PCIXCC_MCL2)
+ memcpy(tgt_p, &static_pke_function_and_rulesX_MCL2,
+ sizeof(struct function_and_rules_block));
+ else
+ memcpy(tgt_p, &static_pke_function_and_rulesX,
+ sizeof(struct function_and_rules_block));
tgt_p += sizeof(struct function_and_rules_block);
tgt_p += 2;
- if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len))
- return SEN_RELEASED;
- if (is_empty(tgt_p, mod_len))
- return SEN_USER_ERROR;
+ if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len)) {
+ kfree(temp_exp);
+ return SEN_RELEASED;
+ }
+ if (is_empty(tgt_p, mod_len)) {
+ kfree(temp_exp);
+ return SEN_USER_ERROR;
+ }
tgt_p -= 2;
*((short *)tgt_p) = (short) vud_len;
tgt_p += vud_len;
key_p = (struct cca_public_key *)tgt_p;
temp = key_p->pubSec.exponent;
memcpy(temp, exp_p, exp_len);
+ kfree(temp_exp);
temp += exp_len;
if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len))
- return SEN_RELEASED;
+ return SEN_RELEASED;
if (is_empty(temp, mod_len))
- return SEN_USER_ERROR;
+ return SEN_USER_ERROR;
key_p->pubSec.modulus_bit_len = 8 * mod_len;
key_p->pubSec.modulus_byte_len = mod_len;
key_p->pubSec.exponent_len = exp_len;
- key_p->pubSec.section_length = 12 + mod_len + exp_len;
+ key_p->pubSec.section_length = CALLER_HEADER + mod_len + exp_len;
key_len = key_p->pubSec.section_length + sizeof(struct cca_token_hdr);
key_p->pubHdr.token_length = key_len;
key_len += 4;
static int
ICACRT_msg_to_type6CRT_msgX(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
- int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
+ int *z90cMsg_l_p, struct type6_msg *z90cMsg_p,
+ int dev_type)
{
int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l, short_len;
int long_len, pad_len, keyPartsLen, tmp_l;
cprbx_p->req_parml = parmBlock_l;
cprbx_p->rpl_msgbl = parmBlock_l;
tgt_p += sizeof(struct CPRBX);
- memcpy(tgt_p, &static_pkd_function_and_rulesX,
- sizeof(struct function_and_rules_block));
+ if (dev_type == PCIXCC_MCL2)
+ memcpy(tgt_p, &static_pkd_function_and_rulesX_MCL2,
+ sizeof(struct function_and_rules_block));
+ else
+ memcpy(tgt_p, &static_pkd_function_and_rulesX,
+ sizeof(struct function_and_rules_block));
tgt_p += sizeof(struct function_and_rules_block);
*((short *)tgt_p) = (short) vud_len;
tgt_p += 2;
return 0;
}
+static int
+ICAMEX_msg_to_type50MEX_msg(struct ica_rsa_modexpo *icaMex_p, int *z90cMsg_l_p,
+ union type50_msg *z90cMsg_p)
+{
+ int mod_len, msg_size, mod_tgt_len, exp_tgt_len, inp_tgt_len;
+ unsigned char *mod_tgt, *exp_tgt, *inp_tgt;
+ union type50_msg *tmp_type50_msg;
+
+ mod_len = icaMex_p->inputdatalength;
+
+ msg_size = ((mod_len <= 128) ? TYPE50_MEB1_LEN : TYPE50_MEB2_LEN) +
+ CALLER_HEADER;
+
+ memset(z90cMsg_p, 0, msg_size);
+
+ tmp_type50_msg = (union type50_msg *)
+ ((unsigned char *) z90cMsg_p + CALLER_HEADER);
+
+ tmp_type50_msg->meb1.header.msg_type_code = TYPE50_TYPE_CODE;
+
+ if (mod_len <= 128) {
+ tmp_type50_msg->meb1.header.msg_len = TYPE50_MEB1_LEN;
+ tmp_type50_msg->meb1.keyblock_type = TYPE50_MEB1_FMT;
+ mod_tgt = tmp_type50_msg->meb1.modulus;
+ mod_tgt_len = sizeof(tmp_type50_msg->meb1.modulus);
+ exp_tgt = tmp_type50_msg->meb1.exponent;
+ exp_tgt_len = sizeof(tmp_type50_msg->meb1.exponent);
+ inp_tgt = tmp_type50_msg->meb1.message;
+ inp_tgt_len = sizeof(tmp_type50_msg->meb1.message);
+ } else {
+ tmp_type50_msg->meb2.header.msg_len = TYPE50_MEB2_LEN;
+ tmp_type50_msg->meb2.keyblock_type = TYPE50_MEB2_FMT;
+ mod_tgt = tmp_type50_msg->meb2.modulus;
+ mod_tgt_len = sizeof(tmp_type50_msg->meb2.modulus);
+ exp_tgt = tmp_type50_msg->meb2.exponent;
+ exp_tgt_len = sizeof(tmp_type50_msg->meb2.exponent);
+ inp_tgt = tmp_type50_msg->meb2.message;
+ inp_tgt_len = sizeof(tmp_type50_msg->meb2.message);
+ }
+
+ mod_tgt += (mod_tgt_len - mod_len);
+ if (copy_from_user(mod_tgt, icaMex_p->n_modulus, mod_len))
+ return SEN_RELEASED;
+ if (is_empty(mod_tgt, mod_len))
+ return SEN_USER_ERROR;
+ exp_tgt += (exp_tgt_len - mod_len);
+ if (copy_from_user(exp_tgt, icaMex_p->b_key, mod_len))
+ return SEN_RELEASED;
+ if (is_empty(exp_tgt, mod_len))
+ return SEN_USER_ERROR;
+ inp_tgt += (inp_tgt_len - mod_len);
+ if (copy_from_user(inp_tgt, icaMex_p->inputdata, mod_len))
+ return SEN_RELEASED;
+ if (is_empty(inp_tgt, mod_len))
+ return SEN_USER_ERROR;
+
+ *z90cMsg_l_p = msg_size - CALLER_HEADER;
+
+ return 0;
+}
+
+static int
+ICACRT_msg_to_type50CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p,
+ int *z90cMsg_l_p, union type50_msg *z90cMsg_p)
+{
+ int mod_len, short_len, long_len, tmp_size, p_tgt_len, q_tgt_len,
+ dp_tgt_len, dq_tgt_len, u_tgt_len, inp_tgt_len, long_offset;
+ unsigned char *p_tgt, *q_tgt, *dp_tgt, *dq_tgt, *u_tgt, *inp_tgt,
+ temp[8];
+ union type50_msg *tmp_type50_msg;
+
+ mod_len = icaMsg_p->inputdatalength;
+ short_len = mod_len / 2;
+ long_len = mod_len / 2 + 8;
+ long_offset = 0;
+
+ if (long_len > 128) {
+ memset(temp, 0x00, sizeof(temp));
+ if (copy_from_user(temp, icaMsg_p->np_prime, long_len-128))
+ return SEN_RELEASED;
+ if (!is_empty(temp, 8))
+ return SEN_NOT_AVAIL;
+ if (copy_from_user(temp, icaMsg_p->bp_key, long_len-128))
+ return SEN_RELEASED;
+ if (!is_empty(temp, 8))
+ return SEN_NOT_AVAIL;
+ if (copy_from_user(temp, icaMsg_p->u_mult_inv, long_len-128))
+ return SEN_RELEASED;
+ if (!is_empty(temp, 8))
+ return SEN_NOT_AVAIL;
+ long_offset = long_len - 128;
+ long_len = 128;
+ }
+
+ tmp_size = ((mod_len <= 128) ? TYPE50_CRB1_LEN : TYPE50_CRB2_LEN) +
+ CALLER_HEADER;
+
+ memset(z90cMsg_p, 0, tmp_size);
+
+ tmp_type50_msg = (union type50_msg *)
+ ((unsigned char *) z90cMsg_p + CALLER_HEADER);
+
+ tmp_type50_msg->crb1.header.msg_type_code = TYPE50_TYPE_CODE;
+ if (long_len <= 64) {
+ tmp_type50_msg->crb1.header.msg_len = TYPE50_CRB1_LEN;
+ tmp_type50_msg->crb1.keyblock_type = TYPE50_CRB1_FMT;
+ p_tgt = tmp_type50_msg->crb1.p;
+ p_tgt_len = sizeof(tmp_type50_msg->crb1.p);
+ q_tgt = tmp_type50_msg->crb1.q;
+ q_tgt_len = sizeof(tmp_type50_msg->crb1.q);
+ dp_tgt = tmp_type50_msg->crb1.dp;
+ dp_tgt_len = sizeof(tmp_type50_msg->crb1.dp);
+ dq_tgt = tmp_type50_msg->crb1.dq;
+ dq_tgt_len = sizeof(tmp_type50_msg->crb1.dq);
+ u_tgt = tmp_type50_msg->crb1.u;
+ u_tgt_len = sizeof(tmp_type50_msg->crb1.u);
+ inp_tgt = tmp_type50_msg->crb1.message;
+ inp_tgt_len = sizeof(tmp_type50_msg->crb1.message);
+ } else {
+ tmp_type50_msg->crb2.header.msg_len = TYPE50_CRB2_LEN;
+ tmp_type50_msg->crb2.keyblock_type = TYPE50_CRB2_FMT;
+ p_tgt = tmp_type50_msg->crb2.p;
+ p_tgt_len = sizeof(tmp_type50_msg->crb2.p);
+ q_tgt = tmp_type50_msg->crb2.q;
+ q_tgt_len = sizeof(tmp_type50_msg->crb2.q);
+ dp_tgt = tmp_type50_msg->crb2.dp;
+ dp_tgt_len = sizeof(tmp_type50_msg->crb2.dp);
+ dq_tgt = tmp_type50_msg->crb2.dq;
+ dq_tgt_len = sizeof(tmp_type50_msg->crb2.dq);
+ u_tgt = tmp_type50_msg->crb2.u;
+ u_tgt_len = sizeof(tmp_type50_msg->crb2.u);
+ inp_tgt = tmp_type50_msg->crb2.message;
+ inp_tgt_len = sizeof(tmp_type50_msg->crb2.message);
+ }
+
+ p_tgt += (p_tgt_len - long_len);
+ if (copy_from_user(p_tgt, icaMsg_p->np_prime + long_offset, long_len))
+ return SEN_RELEASED;
+ if (is_empty(p_tgt, long_len))
+ return SEN_USER_ERROR;
+ q_tgt += (q_tgt_len - short_len);
+ if (copy_from_user(q_tgt, icaMsg_p->nq_prime, short_len))
+ return SEN_RELEASED;
+ if (is_empty(q_tgt, short_len))
+ return SEN_USER_ERROR;
+ dp_tgt += (dp_tgt_len - long_len);
+ if (copy_from_user(dp_tgt, icaMsg_p->bp_key + long_offset, long_len))
+ return SEN_RELEASED;
+ if (is_empty(dp_tgt, long_len))
+ return SEN_USER_ERROR;
+ dq_tgt += (dq_tgt_len - short_len);
+ if (copy_from_user(dq_tgt, icaMsg_p->bq_key, short_len))
+ return SEN_RELEASED;
+ if (is_empty(dq_tgt, short_len))
+ return SEN_USER_ERROR;
+ u_tgt += (u_tgt_len - long_len);
+ if (copy_from_user(u_tgt, icaMsg_p->u_mult_inv + long_offset, long_len))
+ return SEN_RELEASED;
+ if (is_empty(u_tgt, long_len))
+ return SEN_USER_ERROR;
+ inp_tgt += (inp_tgt_len - mod_len);
+ if (copy_from_user(inp_tgt, icaMsg_p->inputdata, mod_len))
+ return SEN_RELEASED;
+ if (is_empty(inp_tgt, mod_len))
+ return SEN_USER_ERROR;
+
+ *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+
+ return 0;
+}
+
int
convert_request(unsigned char *buffer, int func, unsigned short function,
int cdx, int dev_type, int *msg_l_p, unsigned char *msg_p)
(struct ica_rsa_modexpo *) buffer,
cdx, msg_l_p, (struct type6_msg *) msg_p);
}
- if (dev_type == PCIXCC) {
+ if ((dev_type == PCIXCC_MCL2) ||
+ (dev_type == PCIXCC_MCL3) ||
+ (dev_type == CEX2C)) {
if (func == ICARSACRT)
return ICACRT_msg_to_type6CRT_msgX(
(struct ica_rsa_modexpo_crt *) buffer,
- cdx, msg_l_p, (struct type6_msg *) msg_p);
+ cdx, msg_l_p, (struct type6_msg *) msg_p,
+ dev_type);
else
return ICAMEX_msg_to_type6MEX_msgX(
(struct ica_rsa_modexpo *) buffer,
- cdx, msg_l_p, (struct type6_msg *) msg_p);
+ cdx, msg_l_p, (struct type6_msg *) msg_p,
+ dev_type);
+ }
+ if (dev_type == CEX2A) {
+ if (func == ICARSACRT)
+ return ICACRT_msg_to_type50CRT_msg(
+ (struct ica_rsa_modexpo_crt *) buffer,
+ msg_l_p, (union type50_msg *) msg_p);
+ else
+ return ICAMEX_msg_to_type50MEX_msg(
+ (struct ica_rsa_modexpo *) buffer,
+ msg_l_p, (union type50_msg *) msg_p);
}
return 0;
}
+int ext_bitlens_msg_count = 0;
+static inline void
+unset_ext_bitlens(void)
+{
+ if (!ext_bitlens_msg_count) {
+ PRINTK("Unable to use coprocessors for extended bitlengths. "
+ "Using PCICAs/CEX2As (if present) for extended "
+ "bitlengths. This is not an error.\n");
+ ext_bitlens_msg_count++;
+ }
+ ext_bitlens = 0;
+}
+
int
convert_response(unsigned char *response, unsigned char *buffer,
int *respbufflen_p, unsigned char *resp_buff)
{
struct ica_rsa_modexpo *icaMsg_p = (struct ica_rsa_modexpo *) buffer;
- struct type82_hdr *t82h_p = (struct type82_hdr *) response;
+ struct error_hdr *errh_p = (struct error_hdr *) response;
+ struct type80_hdr *t80h_p = (struct type80_hdr *) response;
struct type84_hdr *t84h_p = (struct type84_hdr *) response;
- struct type86_hdr *t86h_p = (struct type86_hdr *) response;
- int rv, reply_code, service_rc, service_rs, src_l;
+ struct type86_fmt2_msg *t86m_p = (struct type86_fmt2_msg *) response;
+ int reply_code, service_rc, service_rs, src_l;
unsigned char *src_p, *tgt_p;
struct CPRB *cprb_p;
struct CPRBX *cprbx_p;
service_rc = 0;
service_rs = 0;
src_l = 0;
- rv = 0;
- switch (t82h_p->type) {
+ switch (errh_p->type) {
case TYPE82_RSP_CODE:
- reply_code = t82h_p->reply_code;
- rv = 4;
- src_p = (unsigned char *)t82h_p;
- PRINTK("Hardware error: Type 82 Message Header: "
+ case TYPE88_RSP_CODE:
+ reply_code = errh_p->reply_code;
+ src_p = (unsigned char *)errh_p;
+ PRINTK("Hardware error: Type %02X Message Header: "
"%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ errh_p->type,
src_p[0], src_p[1], src_p[2], src_p[3],
src_p[4], src_p[5], src_p[6], src_p[7]);
break;
+ case TYPE80_RSP_CODE:
+ src_l = icaMsg_p->outputdatalength;
+ src_p = response + (int)t80h_p->len - src_l;
+ break;
case TYPE84_RSP_CODE:
src_l = icaMsg_p->outputdatalength;
src_p = response + (int)t84h_p->len - src_l;
break;
case TYPE86_RSP_CODE:
- reply_code = t86h_p->reply_code;
- if (t86h_p->format != TYPE86_FMT2) {
- rv = 4;
- break;
- }
- if (reply_code != 0) {
- rv = 4;
+ reply_code = t86m_p->header.reply_code;
+ if (reply_code != 0)
break;
- }
cprb_p = (struct CPRB *)
(response + sizeof(struct type86_fmt2_msg));
cprbx_p = (struct CPRBX *) cprb_p;
if (service_rc != 0) {
le2toI(cprb_p->ccp_rscode, &service_rs);
if ((service_rc == 8) && (service_rs == 66))
- PDEBUG("8/66 on PCICC\n");
+ PDEBUG("Bad block format on PCICC\n");
+ else if ((service_rc == 8) && (service_rs == 65))
+ PDEBUG("Probably an even modulus on "
+ "PCICC\n");
+ else if ((service_rc == 8) && (service_rs == 770)) {
+ PDEBUG("Invalid key length on PCICC\n");
+ unset_ext_bitlens();
+ return REC_USE_PCICA;
+ }
+ else if ((service_rc == 8) && (service_rs == 783)) {
+ PDEBUG("Extended bitlengths not enabled"
+ "on PCICC\n");
+ unset_ext_bitlens();
+ return REC_USE_PCICA;
+ }
else
- PRINTK("service rc/rs: %d/%d\n",
+ PRINTK("service rc/rs (PCICC): %d/%d\n",
service_rc, service_rs);
- rv = 8;
+ return REC_OPERAND_INV;
}
src_p = (unsigned char *)cprb_p + sizeof(struct CPRB);
src_p += 4;
if (service_rc != 0) {
service_rs = (int) cprbx_p->ccp_rscode;
if ((service_rc == 8) && (service_rs == 66))
- PDEBUG("8/66 on PCIXCC\n");
+ PDEBUG("Bad block format on PCIXCC\n");
+ else if ((service_rc == 8) && (service_rs == 65))
+ PDEBUG("Probably an even modulus on "
+ "PCIXCC\n");
+ else if ((service_rc == 8) && (service_rs == 770)) {
+ PDEBUG("Invalid key length on PCIXCC\n");
+ unset_ext_bitlens();
+ return REC_USE_PCICA;
+ }
+ else if ((service_rc == 8) && (service_rs == 783)) {
+ PDEBUG("Extended bitlengths not enabled"
+ "on PCIXCC\n");
+ unset_ext_bitlens();
+ return REC_USE_PCICA;
+ }
else
- PRINTK("service rc/rs: %d/%d\n",
+ PRINTK("service rc/rs (PCIXCC): %d/%d\n",
service_rc, service_rs);
- rv = 8;
+ return REC_OPERAND_INV;
}
src_p = (unsigned char *)
cprbx_p + sizeof(struct CPRBX);
}
break;
default:
- break;
+ src_p = (unsigned char *)errh_p;
+ PRINTK("Unrecognized Message Header: "
+ "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ src_p[0], src_p[1], src_p[2], src_p[3],
+ src_p[4], src_p[5], src_p[6], src_p[7]);
+ return REC_BAD_MESSAGE;
}
- if (rv == 8)
- return 8;
- if (rv == 4)
+ if (reply_code)
switch (reply_code) {
- case REPLY_ERROR_OPERAND_INVALID:
+ case REP82_ERROR_OPERAND_INVALID:
+ case REP88_ERROR_MESSAGE_MALFORMD:
return REC_OPERAND_INV;
- case REPLY_ERROR_OPERAND_SIZE:
+ case REP82_ERROR_OPERAND_SIZE:
return REC_OPERAND_SIZE;
- case REPLY_ERROR_EVEN_MOD_IN_OPND:
+ case REP82_ERROR_EVEN_MOD_IN_OPND:
return REC_EVEN_MOD;
- case REPLY_ERROR_MESSAGE_TYPE:
+ case REP82_ERROR_MESSAGE_TYPE:
return WRONG_DEVICE_TYPE;
+ case REP82_ERROR_TRANSPORT_FAIL:
+ PRINTKW("Transport failed (APFS = %02X%02X%02X%02X)\n",
+ t86m_p->apfs[0], t86m_p->apfs[1],
+ t86m_p->apfs[2], t86m_p->apfs[3]);
+ return REC_HARDWAR_ERR;
default:
- return 12;
+ PRINTKW("reply code = %d\n", reply_code);
+ return REC_HARDWAR_ERR;
}
if (service_rc != 0)
PDEBUG("Length returned = %d\n", src_l);
tgt_p = resp_buff + icaMsg_p->outputdatalength - src_l;
memcpy(tgt_p, src_p, src_l);
- if ((t82h_p->type == TYPE86_RSP_CODE) && (resp_buff < tgt_p)) {
+ if ((errh_p->type == TYPE86_RSP_CODE) && (resp_buff < tgt_p)) {
memset(resp_buff, 0, icaMsg_p->outputdatalength - src_l);
- rv = pad_msg(resp_buff, icaMsg_p->outputdatalength, src_l);
- if (rv != 0)
- return rv;
+ if (pad_msg(resp_buff, icaMsg_p->outputdatalength, src_l))
+ return REC_INVALID_PAD;
}
*respbufflen_p = icaMsg_p->outputdatalength;
if (*respbufflen_p == 0)
PRINTK("Zero *respbufflen_p\n");
- return rv;
+ return 0;
}