| /* |
| * linux/drivers/s390/crypto/z90hardware.c |
| * |
| * z90crypt 1.3.2 |
| * |
| * Copyright (C) 2001, 2004 IBM Corporation |
| * Author(s): Robert Burroughs (burrough@us.ibm.com) |
| * Eric Rossman (edrossma@us.ibm.com) |
| * |
| * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) |
| * |
| * 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, or (at your option) |
| * any later version. |
| * |
| * 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. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| */ |
| |
| #include <asm/uaccess.h> |
| #include <linux/compiler.h> |
| #include <linux/delay.h> |
| #include <linux/init.h> |
| #include <linux/module.h> |
| #include "z90crypt.h" |
| #include "z90common.h" |
| |
| #define VERSION_Z90HARDWARE_C "$Revision: 1.34 $" |
| |
| char z90hardware_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 short token_length; |
| unsigned char reserved[4]; |
| }; |
| |
| #define CCA_TKN_HDR_ID_EXT 0x1E |
| |
| struct cca_private_ext_ME_sec { |
| unsigned char section_identifier; |
| unsigned char version; |
| unsigned short section_length; |
| unsigned char private_key_hash[20]; |
| unsigned char reserved1[4]; |
| unsigned char key_format; |
| unsigned char reserved2; |
| unsigned char key_name_hash[20]; |
| unsigned char key_use_flags[4]; |
| unsigned char reserved3[6]; |
| unsigned char reserved4[24]; |
| unsigned char confounder[24]; |
| unsigned char exponent[128]; |
| unsigned char modulus[128]; |
| }; |
| |
| #define CCA_PVT_USAGE_ALL 0x80 |
| |
| struct cca_public_sec { |
| unsigned char section_identifier; |
| unsigned char version; |
| unsigned short section_length; |
| unsigned char reserved[2]; |
| unsigned short exponent_len; |
| unsigned short modulus_bit_len; |
| unsigned short modulus_byte_len; |
| unsigned char exponent[3]; |
| }; |
| |
| struct cca_private_ext_ME { |
| struct cca_token_hdr pvtMEHdr; |
| struct cca_private_ext_ME_sec pvtMESec; |
| struct cca_public_sec pubMESec; |
| }; |
| |
| struct cca_public_key { |
| struct cca_token_hdr pubHdr; |
| struct cca_public_sec pubSec; |
| }; |
| |
| struct cca_pvt_ext_CRT_sec { |
| unsigned char section_identifier; |
| unsigned char version; |
| unsigned short section_length; |
| unsigned char private_key_hash[20]; |
| unsigned char reserved1[4]; |
| unsigned char key_format; |
| unsigned char reserved2; |
| unsigned char key_name_hash[20]; |
| unsigned char key_use_flags[4]; |
| unsigned short p_len; |
| unsigned short q_len; |
| unsigned short dp_len; |
| unsigned short dq_len; |
| unsigned short u_len; |
| unsigned short mod_len; |
| unsigned char reserved3[4]; |
| unsigned short pad_len; |
| unsigned char reserved4[52]; |
| unsigned char confounder[8]; |
| }; |
| |
| #define CCA_PVT_EXT_CRT_SEC_ID_PVT 0x08 |
| #define CCA_PVT_EXT_CRT_SEC_FMT_CL 0x40 |
| |
| struct cca_private_ext_CRT { |
| struct cca_token_hdr pvtCrtHdr; |
| struct cca_pvt_ext_CRT_sec pvtCrtSec; |
| struct cca_public_sec pubCrtSec; |
| }; |
| |
| struct ap_status_word { |
| unsigned char q_stat_flags; |
| unsigned char response_code; |
| unsigned char reserved[2]; |
| }; |
| |
| #define AP_Q_STATUS_EMPTY 0x80 |
| #define AP_Q_STATUS_REPLIES_WAITING 0x40 |
| #define AP_Q_STATUS_ARRAY_FULL 0x20 |
| |
| #define AP_RESPONSE_NORMAL 0x00 |
| #define AP_RESPONSE_Q_NOT_AVAIL 0x01 |
| #define AP_RESPONSE_RESET_IN_PROGRESS 0x02 |
| #define AP_RESPONSE_DECONFIGURED 0x03 |
| #define AP_RESPONSE_CHECKSTOPPED 0x04 |
| #define AP_RESPONSE_BUSY 0x05 |
| #define AP_RESPONSE_Q_FULL 0x10 |
| #define AP_RESPONSE_NO_PENDING_REPLY 0x10 |
| #define AP_RESPONSE_INDEX_TOO_BIG 0x11 |
| #define AP_RESPONSE_NO_FIRST_PART 0x13 |
| #define AP_RESPONSE_MESSAGE_TOO_BIG 0x15 |
| |
| #define AP_MAX_CDX_BITL 4 |
| #define AP_RQID_RESERVED_BITL 4 |
| #define SKIP_BITL (AP_MAX_CDX_BITL + AP_RQID_RESERVED_BITL) |
| |
| struct type4_hdr { |
| unsigned char reserved1; |
| unsigned char msg_type_code; |
| unsigned short msg_len; |
| unsigned char request_code; |
| unsigned char msg_fmt; |
| unsigned short reserved2; |
| }; |
| |
| #define TYPE4_TYPE_CODE 0x04 |
| #define TYPE4_REQU_CODE 0x40 |
| |
| #define TYPE4_SME_LEN 0x0188 |
| #define TYPE4_LME_LEN 0x0308 |
| #define TYPE4_SCR_LEN 0x01E0 |
| #define TYPE4_LCR_LEN 0x03A0 |
| |
| #define TYPE4_SME_FMT 0x00 |
| #define TYPE4_LME_FMT 0x10 |
| #define TYPE4_SCR_FMT 0x40 |
| #define TYPE4_LCR_FMT 0x50 |
| |
| struct type4_sme { |
| struct type4_hdr header; |
| unsigned char message[128]; |
| unsigned char exponent[128]; |
| unsigned char modulus[128]; |
| }; |
| |
| struct type4_lme { |
| struct type4_hdr header; |
| unsigned char message[256]; |
| unsigned char exponent[256]; |
| unsigned char modulus[256]; |
| }; |
| |
| struct type4_scr { |
| struct type4_hdr header; |
| unsigned char message[128]; |
| unsigned char dp[72]; |
| unsigned char dq[64]; |
| unsigned char p[72]; |
| unsigned char q[64]; |
| unsigned char u[72]; |
| }; |
| |
| struct type4_lcr { |
| struct type4_hdr header; |
| unsigned char message[256]; |
| unsigned char dp[136]; |
| unsigned char dq[128]; |
| unsigned char p[136]; |
| unsigned char q[128]; |
| unsigned char u[136]; |
| }; |
| |
| union type4_msg { |
| struct type4_sme sme; |
| struct type4_lme lme; |
| struct type4_scr scr; |
| struct type4_lcr lcr; |
| }; |
| |
| struct type84_hdr { |
| unsigned char reserved1; |
| unsigned char code; |
| unsigned short len; |
| unsigned char reserved2[4]; |
| }; |
| |
| #define TYPE84_RSP_CODE 0x84 |
| |
| struct type6_hdr { |
| unsigned char reserved1; |
| unsigned char type; |
| unsigned char reserved2[2]; |
| unsigned char right[4]; |
| unsigned char reserved3[2]; |
| unsigned char reserved4[2]; |
| unsigned char apfs[4]; |
| unsigned int offset1; |
| unsigned int offset2; |
| unsigned int offset3; |
| unsigned int offset4; |
| unsigned char agent_id[16]; |
| unsigned char rqid[2]; |
| unsigned char reserved5[2]; |
| unsigned char function_code[2]; |
| unsigned char reserved6[2]; |
| unsigned int ToCardLen1; |
| unsigned int ToCardLen2; |
| unsigned int ToCardLen3; |
| unsigned int ToCardLen4; |
| unsigned int FromCardLen1; |
| unsigned int FromCardLen2; |
| unsigned int FromCardLen3; |
| unsigned int FromCardLen4; |
| }; |
| |
| struct CPRB { |
| unsigned char cprb_len[2]; |
| unsigned char cprb_ver_id; |
| unsigned char pad_000; |
| unsigned char srpi_rtcode[4]; |
| unsigned char srpi_verb; |
| unsigned char flags; |
| unsigned char func_id[2]; |
| unsigned char checkpoint_flag; |
| unsigned char resv2; |
| unsigned char req_parml[2]; |
| unsigned char req_parmp[4]; |
| unsigned char req_datal[4]; |
| unsigned char req_datap[4]; |
| unsigned char rpl_parml[2]; |
| unsigned char pad_001[2]; |
| unsigned char rpl_parmp[4]; |
| unsigned char rpl_datal[4]; |
| unsigned char rpl_datap[4]; |
| unsigned char ccp_rscode[2]; |
| unsigned char ccp_rtcode[2]; |
| unsigned char repd_parml[2]; |
| unsigned char mac_data_len[2]; |
| unsigned char repd_datal[4]; |
| unsigned char req_pc[2]; |
| unsigned char res_origin[8]; |
| unsigned char mac_value[8]; |
| unsigned char logon_id[8]; |
| unsigned char usage_domain[2]; |
| unsigned char resv3[18]; |
| unsigned char svr_namel[2]; |
| unsigned char svr_name[8]; |
| }; |
| |
| struct type6_msg { |
| struct type6_hdr header; |
| struct CPRB CPRB; |
| }; |
| |
| struct type86_hdr { |
| unsigned char reserved1; |
| unsigned char type; |
| unsigned char format; |
| unsigned char reserved2; |
| unsigned char reply_code; |
| unsigned char reserved3[3]; |
| }; |
| |
| #define TYPE86_RSP_CODE 0x86 |
| #define TYPE86_FMT2 0x02 |
| |
| struct type86_fmt2_msg { |
| struct type86_hdr header; |
| unsigned char reserved[4]; |
| unsigned char apfs[4]; |
| unsigned int count1; |
| unsigned int offset1; |
| unsigned int count2; |
| unsigned int offset2; |
| unsigned int count3; |
| unsigned int offset3; |
| unsigned int count4; |
| unsigned int offset4; |
| }; |
| |
| static struct type6_hdr static_type6_hdr = { |
| 0x00, |
| 0x06, |
| {0x00,0x00}, |
| {0x00,0x00,0x00,0x00}, |
| {0x00,0x00}, |
| {0x00,0x00}, |
| {0x00,0x00,0x00,0x00}, |
| 0x00000058, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000, |
| {0x01,0x00,0x43,0x43,0x41,0x2D,0x41,0x50, |
| 0x50,0x4C,0x20,0x20,0x20,0x01,0x01,0x01}, |
| {0x00,0x00}, |
| {0x00,0x00}, |
| {0x50,0x44}, |
| {0x00,0x00}, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000 |
| }; |
| |
| static struct type6_hdr static_type6_hdrX = { |
| 0x00, |
| 0x06, |
| {0x00,0x00}, |
| {0x00,0x00,0x00,0x00}, |
| {0x00,0x00}, |
| {0x00,0x00}, |
| {0x00,0x00,0x00,0x00}, |
| 0x00000058, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000, |
| {0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, |
| {0x00,0x00}, |
| {0x00,0x00}, |
| {0x50,0x44}, |
| {0x00,0x00}, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000 |
| }; |
| |
| static struct CPRB static_cprb = { |
| {0x70,0x00}, |
| 0x41, |
| 0x00, |
| {0x00,0x00,0x00,0x00}, |
| 0x00, |
| 0x00, |
| {0x54,0x32}, |
| 0x01, |
| 0x00, |
| {0x00,0x00}, |
| {0x00,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00}, |
| {0x00,0x00}, |
| {0x00,0x00}, |
| {0x00,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00}, |
| {0x00,0x00}, |
| {0x00,0x00}, |
| {0x00,0x00}, |
| {0x00,0x00}, |
| {0x00,0x00,0x00,0x00}, |
| {0x00,0x00}, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, |
| {0x00,0x00}, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00}, |
| {0x08,0x00}, |
| {0x49,0x43,0x53,0x46,0x20,0x20,0x20,0x20} |
| }; |
| |
| struct function_and_rules_block { |
| unsigned char function_code[2]; |
| unsigned char ulen[2]; |
| unsigned char only_rule[8]; |
| }; |
| |
| static struct function_and_rules_block static_pkd_function_and_rules = { |
| {0x50,0x44}, |
| {0x0A,0x00}, |
| {'P','K','C','S','-','1','.','2'} |
| }; |
| |
| static struct function_and_rules_block static_pke_function_and_rules = { |
| {0x50,0x4B}, |
| {0x0A,0x00}, |
| {'P','K','C','S','-','1','.','2'} |
| }; |
| |
| struct T6_keyBlock_hdr { |
| unsigned char blen[2]; |
| unsigned char ulen[2]; |
| unsigned char flags[2]; |
| }; |
| |
| static struct T6_keyBlock_hdr static_T6_keyBlock_hdr = { |
| {0x89,0x01}, |
| {0x87,0x01}, |
| {0x00} |
| }; |
| |
| static struct CPRBX static_cprbx = { |
| 0x00DC, |
| 0x02, |
| {0x00,0x00,0x00}, |
| {0x54,0x32}, |
| {0x00,0x00,0x00,0x00}, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000, |
| 0x00000000, |
| {0x00,0x00,0x00,0x00}, |
| 0x00000000, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, |
| 0x0000, |
| 0x0000, |
| 0x00000000, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, |
| 0x00, |
| 0x00, |
| 0x0000, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} |
| }; |
| |
| 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_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; |
| unsigned char flags[2]; |
| }; |
| |
| static unsigned char static_pad[256] = { |
| 0x1B,0x7B,0x5D,0xB5,0x75,0x01,0x3D,0xFD,0x8D,0xD1,0xC7,0x03,0x2D,0x09,0x23,0x57, |
| 0x89,0x49,0xB9,0x3F,0xBB,0x99,0x41,0x5B,0x75,0x21,0x7B,0x9D,0x3B,0x6B,0x51,0x39, |
| 0xBB,0x0D,0x35,0xB9,0x89,0x0F,0x93,0xA5,0x0B,0x47,0xF1,0xD3,0xBB,0xCB,0xF1,0x9D, |
| 0x23,0x73,0x71,0xFF,0xF3,0xF5,0x45,0xFB,0x61,0x29,0x23,0xFD,0xF1,0x29,0x3F,0x7F, |
| 0x17,0xB7,0x1B,0xA9,0x19,0xBD,0x57,0xA9,0xD7,0x95,0xA3,0xCB,0xED,0x1D,0xDB,0x45, |
| 0x7D,0x11,0xD1,0x51,0x1B,0xED,0x71,0xE9,0xB1,0xD1,0xAB,0xAB,0x21,0x2B,0x1B,0x9F, |
| 0x3B,0x9F,0xF7,0xF7,0xBD,0x63,0xEB,0xAD,0xDF,0xB3,0x6F,0x5B,0xDB,0x8D,0xA9,0x5D, |
| 0xE3,0x7D,0x77,0x49,0x47,0xF5,0xA7,0xFD,0xAB,0x2F,0x27,0x35,0x77,0xD3,0x49,0xC9, |
| 0x09,0xEB,0xB1,0xF9,0xBF,0x4B,0xCB,0x2B,0xEB,0xEB,0x05,0xFF,0x7D,0xC7,0x91,0x8B, |
| 0x09,0x83,0xB9,0xB9,0x69,0x33,0x39,0x6B,0x79,0x75,0x19,0xBF,0xBB,0x07,0x1D,0xBD, |
| 0x29,0xBF,0x39,0x95,0x93,0x1D,0x35,0xC7,0xC9,0x4D,0xE5,0x97,0x0B,0x43,0x9B,0xF1, |
| 0x16,0x93,0x03,0x1F,0xA5,0xFB,0xDB,0xF3,0x27,0x4F,0x27,0x61,0x05,0x1F,0xB9,0x23, |
| 0x2F,0xC3,0x81,0xA9,0x23,0x71,0x55,0x55,0xEB,0xED,0x41,0xE5,0xF3,0x11,0xF1,0x43, |
| 0x69,0x03,0xBD,0x0B,0x37,0x0F,0x51,0x8F,0x0B,0xB5,0x89,0x5B,0x67,0xA9,0xD9,0x4F, |
| 0x01,0xF9,0x21,0x77,0x37,0x73,0x79,0xC5,0x7F,0x51,0xC1,0xCF,0x97,0xA1,0x75,0xAD, |
| 0x35,0x9D,0xD3,0xD3,0xA7,0x9D,0x5D,0x41,0x6F,0x65,0x1B,0xCF,0xA9,0x87,0x91,0x09 |
| }; |
| |
| static struct cca_private_ext_ME static_pvt_me_key = { |
| { |
| 0x1E, |
| 0x00, |
| 0x0183, |
| {0x00,0x00,0x00,0x00} |
| }, |
| |
| { |
| 0x02, |
| 0x00, |
| 0x016C, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00}, |
| 0x00, |
| 0x00, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00}, |
| {0x80,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, |
| {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
| 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} |
| }, |
| |
| { |
| 0x04, |
| 0x00, |
| 0x000F, |
| {0x00,0x00}, |
| 0x0003, |
| 0x0000, |
| 0x0000, |
| {0x01,0x00,0x01} |
| } |
| }; |
| |
| static struct cca_public_key static_public_key = { |
| { |
| 0x1E, |
| 0x00, |
| 0x0000, |
| {0x00,0x00,0x00,0x00} |
| }, |
| |
| { |
| 0x04, |
| 0x00, |
| 0x0000, |
| {0x00,0x00}, |
| 0x0000, |
| 0x0000, |
| 0x0000, |
| {0x01,0x00,0x01} |
| } |
| }; |
| |
| #define FIXED_TYPE6_ME_LEN 0x0000025F |
| |
| #define FIXED_TYPE6_ME_EN_LEN 0x000000F0 |
| |
| #define FIXED_TYPE6_ME_LENX 0x000002CB |
| |
| #define FIXED_TYPE6_ME_EN_LENX 0x0000015C |
| |
| static struct cca_public_sec static_cca_pub_sec = { |
| 0x04, |
| 0x00, |
| 0x000f, |
| {0x00,0x00}, |
| 0x0003, |
| 0x0000, |
| 0x0000, |
| {0x01,0x00,0x01} |
| }; |
| |
| #define FIXED_TYPE6_CR_LEN 0x00000177 |
| |
| #define FIXED_TYPE6_CR_LENX 0x000001E3 |
| |
| #define MAX_RESPONSE_SIZE 0x00000710 |
| |
| #define MAX_RESPONSEX_SIZE 0x0000077C |
| |
| #define RESPONSE_CPRB_SIZE 0x000006B8 |
| #define RESPONSE_CPRBX_SIZE 0x00000724 |
| |
| 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 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 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__ |
| (" llgfr 0,%4 \n" |
| " slgr 1,1 \n" |
| " lgr 2,1 \n" |
| "0: .long 0xb2af0000 \n" |
| "1: ipm %0 \n" |
| " srl %0,28 \n" |
| " iihh %0,0 \n" |
| " iihl %0,0 \n" |
| " lgr %1,1 \n" |
| " lgr %3,2 \n" |
| " srl %3,24 \n" |
| " sll 2,24 \n" |
| " srl 2,24 \n" |
| " lgr %2,2 \n" |
| "2: \n" |
| ".section .fixup,\"ax\" \n" |
| "3: \n" |
| " lhi %0,%h5 \n" |
| " jg 2b \n" |
| ".previous \n" |
| ".section __ex_table,\"a\" \n" |
| " .align 8 \n" |
| " .quad 0b,3b \n" |
| " .quad 1b,3b \n" |
| ".previous" |
| :"=d" (ccode),"=d" (*stat),"=d" (*q_depth), "=d" (*dev_type) |
| :"d" (q_nr), "K" (DEV_TSQ_EXCEPTION) |
| :"cc","0","1","2","memory"); |
| #else |
| (" lr 0,%4 \n" |
| " slr 1,1 \n" |
| " lr 2,1 \n" |
| "0: .long 0xb2af0000 \n" |
| "1: ipm %0 \n" |
| " srl %0,28 \n" |
| " lr %1,1 \n" |
| " lr %3,2 \n" |
| " srl %3,24 \n" |
| " sll 2,24 \n" |
| " srl 2,24 \n" |
| " lr %2,2 \n" |
| "2: \n" |
| ".section .fixup,\"ax\" \n" |
| "3: \n" |
| " lhi %0,%h5 \n" |
| " bras 1,4f \n" |
| " .long 2b \n" |
| "4: \n" |
| " l 1,0(1) \n" |
| " br 1 \n" |
| ".previous \n" |
| ".section __ex_table,\"a\" \n" |
| " .align 4 \n" |
| " .long 0b,3b \n" |
| " .long 1b,3b \n" |
| ".previous" |
| :"=d" (ccode),"=d" (*stat),"=d" (*q_depth), "=d" (*dev_type) |
| :"d" (q_nr), "K" (DEV_TSQ_EXCEPTION) |
| :"cc","0","1","2","memory"); |
| #endif |
| return ccode; |
| } |
| |
| static inline int |
| resetq(int q_nr, struct ap_status_word *stat_p) |
| { |
| int ccode; |
| |
| asm volatile |
| #ifdef __s390x__ |
| (" llgfr 0,%2 \n" |
| " lghi 1,1 \n" |
| " sll 1,24 \n" |
| " or 0,1 \n" |
| " slgr 1,1 \n" |
| " lgr 2,1 \n" |
| "0: .long 0xb2af0000 \n" |
| "1: ipm %0 \n" |
| " srl %0,28 \n" |
| " iihh %0,0 \n" |
| " iihl %0,0 \n" |
| " lgr %1,1 \n" |
| "2: \n" |
| ".section .fixup,\"ax\" \n" |
| "3: \n" |
| " lhi %0,%h3 \n" |
| " jg 2b \n" |
| ".previous \n" |
| ".section __ex_table,\"a\" \n" |
| " .align 8 \n" |
| " .quad 0b,3b \n" |
| " .quad 1b,3b \n" |
| ".previous" |
| :"=d" (ccode),"=d" (*stat_p) |
| :"d" (q_nr), "K" (DEV_RSQ_EXCEPTION) |
| :"cc","0","1","2","memory"); |
| #else |
| (" lr 0,%2 \n" |
| " lhi 1,1 \n" |
| " sll 1,24 \n" |
| " or 0,1 \n" |
| " slr 1,1 \n" |
| " lr 2,1 \n" |
| "0: .long 0xb2af0000 \n" |
| "1: ipm %0 \n" |
| " srl %0,28 \n" |
| " lr %1,1 \n" |
| "2: \n" |
| ".section .fixup,\"ax\" \n" |
| "3: \n" |
| " lhi %0,%h3 \n" |
| " bras 1,4f \n" |
| " .long 2b \n" |
| "4: \n" |
| " l 1,0(1) \n" |
| " br 1 \n" |
| ".previous \n" |
| ".section __ex_table,\"a\" \n" |
| " .align 4 \n" |
| " .long 0b,3b \n" |
| " .long 1b,3b \n" |
| ".previous" |
| :"=d" (ccode),"=d" (*stat_p) |
| :"d" (q_nr), "K" (DEV_RSQ_EXCEPTION) |
| :"cc","0","1","2","memory"); |
| #endif |
| return ccode; |
| } |
| |
| static inline int |
| sen(int msg_len, unsigned char *msg_ext, struct ap_status_word *stat) |
| { |
| int ccode; |
| |
| asm volatile |
| #ifdef __s390x__ |
| (" lgr 6,%3 \n" |
| " llgfr 7,%2 \n" |
| " llgt 0,0(6) \n" |
| " lghi 1,64 \n" |
| " sll 1,24 \n" |
| " or 0,1 \n" |
| " la 6,4(6) \n" |
| " llgt 2,0(6) \n" |
| " llgt 3,4(6) \n" |
| " la 6,8(6) \n" |
| " slr 1,1 \n" |
| "0: .long 0xb2ad0026 \n" |
| "1: brc 2,0b \n" |
| " ipm %0 \n" |
| " srl %0,28 \n" |
| " iihh %0,0 \n" |
| " iihl %0,0 \n" |
| " lgr %1,1 \n" |
| "2: \n" |
| ".section .fixup,\"ax\" \n" |
| "3: \n" |
| " lhi %0,%h4 \n" |
| " jg 2b \n" |
| ".previous \n" |
| ".section __ex_table,\"a\" \n" |
| " .align 8 \n" |
| " .quad 0b,3b \n" |
| " .quad 1b,3b \n" |
| ".previous" |
| :"=d" (ccode),"=d" (*stat) |
| :"d" (msg_len),"a" (msg_ext), "K" (DEV_SEN_EXCEPTION) |
| :"cc","0","1","2","3","6","7","memory"); |
| #else |
| (" lr 6,%3 \n" |
| " lr 7,%2 \n" |
| " l 0,0(6) \n" |
| " lhi 1,64 \n" |
| " sll 1,24 \n" |
| " or 0,1 \n" |
| " la 6,4(6) \n" |
| " l 2,0(6) \n" |
| " l 3,4(6) \n" |
| " la 6,8(6) \n" |
| " slr 1,1 \n" |
| "0: .long 0xb2ad0026 \n" |
| "1: brc 2,0b \n" |
| " ipm %0 \n" |
| " srl %0,28 \n" |
| " lr %1,1 \n" |
| "2: \n" |
| ".section .fixup,\"ax\" \n" |
| "3: \n" |
| " lhi %0,%h4 \n" |
| " bras 1,4f \n" |
| " .long 2b \n" |
| "4: \n" |
| " l 1,0(1) \n" |
| " br 1 \n" |
| ".previous \n" |
| ".section __ex_table,\"a\" \n" |
| " .align 4 \n" |
| " .long 0b,3b \n" |
| " .long 1b,3b \n" |
| ".previous" |
| :"=d" (ccode),"=d" (*stat) |
| :"d" (msg_len),"a" (msg_ext), "K" (DEV_SEN_EXCEPTION) |
| :"cc","0","1","2","3","6","7","memory"); |
| #endif |
| return ccode; |
| } |
| |
| static inline int |
| rec(int q_nr, int buff_l, unsigned char *rsp, unsigned char *id, |
| struct ap_status_word *st) |
| { |
| int ccode; |
| |
| asm volatile |
| #ifdef __s390x__ |
| (" llgfr 0,%2 \n" |
| " lgr 3,%4 \n" |
| " lgr 6,%3 \n" |
| " llgfr 7,%5 \n" |
| " lghi 1,128 \n" |
| " sll 1,24 \n" |
| " or 0,1 \n" |
| " slgr 1,1 \n" |
| " lgr 2,1 \n" |
| " lgr 4,1 \n" |
| " lgr 5,1 \n" |
| "0: .long 0xb2ae0046 \n" |
| "1: brc 2,0b \n" |
| " brc 4,0b \n" |
| " ipm %0 \n" |
| " srl %0,28 \n" |
| " iihh %0,0 \n" |
| " iihl %0,0 \n" |
| " lgr %1,1 \n" |
| " st 4,0(3) \n" |
| " st 5,4(3) \n" |
| "2: \n" |
| ".section .fixup,\"ax\" \n" |
| "3: \n" |
| " lhi %0,%h6 \n" |
| " jg 2b \n" |
| ".previous \n" |
| ".section __ex_table,\"a\" \n" |
| " .align 8 \n" |
| " .quad 0b,3b \n" |
| " .quad 1b,3b \n" |
| ".previous" |
| :"=d"(ccode),"=d"(*st) |
| :"d" (q_nr), "d" (rsp), "d" (id), "d" (buff_l), "K" (DEV_REC_EXCEPTION) |
| :"cc","0","1","2","3","4","5","6","7","memory"); |
| #else |
| (" lr 0,%2 \n" |
| " lr 3,%4 \n" |
| " lr 6,%3 \n" |
| " lr 7,%5 \n" |
| " lhi 1,128 \n" |
| " sll 1,24 \n" |
| " or 0,1 \n" |
| " slr 1,1 \n" |
| " lr 2,1 \n" |
| " lr 4,1 \n" |
| " lr 5,1 \n" |
| "0: .long 0xb2ae0046 \n" |
| "1: brc 2,0b \n" |
| " brc 4,0b \n" |
| " ipm %0 \n" |
| " srl %0,28 \n" |
| " lr %1,1 \n" |
| " st 4,0(3) \n" |
| " st 5,4(3) \n" |
| "2: \n" |
| ".section .fixup,\"ax\" \n" |
| "3: \n" |
| " lhi %0,%h6 \n" |
| " bras 1,4f \n" |
| " .long 2b \n" |
| "4: \n" |
| " l 1,0(1) \n" |
| " br 1 \n" |
| ".previous \n" |
| ".section __ex_table,\"a\" \n" |
| " .align 4 \n" |
| " .long 0b,3b \n" |
| " .long 1b,3b \n" |
| ".previous" |
| :"=d"(ccode),"=d"(*st) |
| :"d" (q_nr), "d" (rsp), "d" (id), "d" (buff_l), "K" (DEV_REC_EXCEPTION) |
| :"cc","0","1","2","3","4","5","6","7","memory"); |
| #endif |
| return ccode; |
| } |
| |
| static inline void |
| itoLe2(int *i_p, unsigned char *lechars) |
| { |
| *lechars = *((unsigned char *) i_p + sizeof(int) - 1); |
| *(lechars + 1) = *((unsigned char *) i_p + sizeof(int) - 2); |
| } |
| |
| static inline void |
| le2toI(unsigned char *lechars, int *i_p) |
| { |
| unsigned char *ic_p; |
| *i_p = 0; |
| ic_p = (unsigned char *) i_p; |
| *(ic_p + 2) = *(lechars + 1); |
| *(ic_p + 3) = *(lechars); |
| } |
| |
| static inline int |
| is_empty(unsigned char *ptr, int len) |
| { |
| return !memcmp(ptr, (unsigned char *) &static_pvt_me_key+60, len); |
| } |
| |
| enum hdstat |
| query_online(int deviceNr, int cdx, int resetNr, int *q_depth, int *dev_type) |
| { |
| int q_nr, i, t_depth, t_dev_type; |
| enum devstat ccode; |
| struct ap_status_word stat_word; |
| enum hdstat stat; |
| int break_out; |
| |
| q_nr = (deviceNr << SKIP_BITL) + cdx; |
| stat = HD_BUSY; |
| ccode = testq(q_nr, &t_depth, &t_dev_type, &stat_word); |
| PDEBUG("ccode %d response_code %02X\n", ccode, stat_word.response_code); |
| break_out = 0; |
| for (i = 0; i < resetNr; i++) { |
| if (ccode > 3) { |
| PRINTKC("Exception testing device %d\n", i); |
| return HD_TSQ_EXCEPTION; |
| } |
| switch (ccode) { |
| case 0: |
| PDEBUG("t_dev_type %d\n", t_dev_type); |
| break_out = 1; |
| stat = HD_ONLINE; |
| *q_depth = t_depth + 1; |
| switch (t_dev_type) { |
| case OTHER_HW: |
| stat = HD_NOT_THERE; |
| *dev_type = NILDEV; |
| break; |
| case PCICA_HW: |
| *dev_type = PCICA; |
| break; |
| case PCICC_HW: |
| *dev_type = PCICC; |
| break; |
| case PCIXCC_HW: |
| *dev_type = PCIXCC_UNK; |
| break; |
| case CEX2C_HW: |
| *dev_type = CEX2C; |
| break; |
| default: |
| *dev_type = NILDEV; |
| break; |
| } |
| PDEBUG("available device %d: Q depth = %d, dev " |
| "type = %d, stat = %02X%02X%02X%02X\n", |
| deviceNr, *q_depth, *dev_type, |
| stat_word.q_stat_flags, |
| stat_word.response_code, |
| stat_word.reserved[0], |
| stat_word.reserved[1]); |
| break; |
| case 3: |
| switch (stat_word.response_code) { |
| case AP_RESPONSE_NORMAL: |
| stat = HD_ONLINE; |
| break_out = 1; |
| *q_depth = t_depth + 1; |
| *dev_type = t_dev_type; |
| PDEBUG("cc3, available device " |
| "%d: Q depth = %d, dev " |
| "type = %d, stat = " |
| "%02X%02X%02X%02X\n", |
| deviceNr, *q_depth, |
| *dev_type, |
| stat_word.q_stat_flags, |
| stat_word.response_code, |
| stat_word.reserved[0], |
| stat_word.reserved[1]); |
| break; |
| case AP_RESPONSE_Q_NOT_AVAIL: |
| stat = HD_NOT_THERE; |
| break_out = 1; |
| break; |
| case AP_RESPONSE_RESET_IN_PROGRESS: |
| PDEBUG("device %d in reset\n", |
| deviceNr); |
| break; |
| case AP_RESPONSE_DECONFIGURED: |
| stat = HD_DECONFIGURED; |
| break_out = 1; |
| break; |
| case AP_RESPONSE_CHECKSTOPPED: |
| stat = HD_CHECKSTOPPED; |
| break_out = 1; |
| break; |
| case AP_RESPONSE_BUSY: |
| PDEBUG("device %d busy\n", |
| deviceNr); |
| break; |
| default: |
| break; |
| } |
| break; |
| default: |
| stat = HD_NOT_THERE; |
| break_out = 1; |
| break; |
| } |
| if (break_out) |
| break; |
| |
| udelay(5); |
| |
| ccode = testq(q_nr, &t_depth, &t_dev_type, &stat_word); |
| } |
| return stat; |
| } |
| |
| enum devstat |
| reset_device(int deviceNr, int cdx, int resetNr) |
| { |
| int q_nr, ccode = 0, dummy_qdepth, dummy_devType, i; |
| struct ap_status_word stat_word; |
| enum devstat stat; |
| int break_out; |
| |
| q_nr = (deviceNr << SKIP_BITL) + cdx; |
| stat = DEV_GONE; |
| ccode = resetq(q_nr, &stat_word); |
| if (ccode > 3) |
| return DEV_RSQ_EXCEPTION; |
| |
| break_out = 0; |
| for (i = 0; i < resetNr; i++) { |
| switch (ccode) { |
| case 0: |
| stat = DEV_ONLINE; |
| if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY) |
| break_out = 1; |
| break; |
| case 3: |
| switch (stat_word.response_code) { |
| case AP_RESPONSE_NORMAL: |
| stat = DEV_ONLINE; |
| if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY) |
| break_out = 1; |
| break; |
| case AP_RESPONSE_Q_NOT_AVAIL: |
| case AP_RESPONSE_DECONFIGURED: |
| case AP_RESPONSE_CHECKSTOPPED: |
| stat = DEV_GONE; |
| break_out = 1; |
| break; |
| case AP_RESPONSE_RESET_IN_PROGRESS: |
| case AP_RESPONSE_BUSY: |
| default: |
| break; |
| } |
| break; |
| default: |
| stat = DEV_GONE; |
| break_out = 1; |
| break; |
| } |
| if (break_out == 1) |
| break; |
| udelay(5); |
| |
| ccode = testq(q_nr, &dummy_qdepth, &dummy_devType, &stat_word); |
| if (ccode > 3) { |
| stat = DEV_TSQ_EXCEPTION; |
| break; |
| } |
| } |
| PDEBUG("Number of testq's needed for reset: %d\n", i); |
| |
| if (i >= resetNr) { |
| stat = DEV_GONE; |
| } |
| |
| return stat; |
| } |
| |
| #ifdef DEBUG_HYDRA_MSGS |
| static inline void |
| print_buffer(unsigned char *buffer, int bufflen) |
| { |
| int i; |
| for (i = 0; i < bufflen; i += 16) { |
| PRINTK("%04X: %02X%02X%02X%02X %02X%02X%02X%02X " |
| "%02X%02X%02X%02X %02X%02X%02X%02X\n", i, |
| buffer[i+0], buffer[i+1], buffer[i+2], buffer[i+3], |
| buffer[i+4], buffer[i+5], buffer[i+6], buffer[i+7], |
| buffer[i+8], buffer[i+9], buffer[i+10], buffer[i+11], |
| buffer[i+12], buffer[i+13], buffer[i+14], buffer[i+15]); |
| } |
| } |
| #endif |
| |
| enum devstat |
| send_to_AP(int dev_nr, int cdx, int msg_len, unsigned char *msg_ext) |
| { |
| struct ap_status_word stat_word; |
| enum devstat stat; |
| int ccode; |
| u32 *q_nr_p = (u32 *)msg_ext; |
| |
| *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]); |
| stat = DEV_GONE; |
| |
| #ifdef DEBUG_HYDRA_MSGS |
| PRINTK("Request header: %02X%02X%02X%02X %02X%02X%02X%02X " |
| "%02X%02X%02X%02X\n", |
| 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+CALLER_HEADER, msg_len); |
| #endif |
| |
| ccode = sen(msg_len, msg_ext, &stat_word); |
| if (ccode > 3) |
| return DEV_SEN_EXCEPTION; |
| |
| PDEBUG("nq cc: %u, st: %02x%02x%02x%02x\n", |
| ccode, stat_word.q_stat_flags, stat_word.response_code, |
| stat_word.reserved[0], stat_word.reserved[1]); |
| switch (ccode) { |
| case 0: |
| stat = DEV_ONLINE; |
| break; |
| case 1: |
| stat = DEV_GONE; |
| break; |
| case 3: |
| switch (stat_word.response_code) { |
| case AP_RESPONSE_NORMAL: |
| stat = DEV_ONLINE; |
| break; |
| case AP_RESPONSE_Q_FULL: |
| stat = DEV_QUEUE_FULL; |
| break; |
| default: |
| stat = DEV_GONE; |
| break; |
| } |
| 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) |
| { |
| int ccode; |
| struct ap_status_word stat_word; |
| enum devstat stat; |
| |
| memset(resp, 0x00, 8); |
| |
| ccode = rec((dev_nr << SKIP_BITL) + cdx, resplen, resp, psmid, |
| &stat_word); |
| if (ccode > 3) |
| return DEV_REC_EXCEPTION; |
| |
| PDEBUG("dq cc: %u, st: %02x%02x%02x%02x\n", |
| ccode, stat_word.q_stat_flags, stat_word.response_code, |
| stat_word.reserved[0], stat_word.reserved[1]); |
| |
| stat = DEV_GONE; |
| switch (ccode) { |
| case 0: |
| stat = DEV_ONLINE; |
| #ifdef DEBUG_HYDRA_MSGS |
| print_buffer(resp, resplen); |
| #endif |
| break; |
| case 3: |
| switch (stat_word.response_code) { |
| case AP_RESPONSE_NORMAL: |
| stat = DEV_ONLINE; |
| break; |
| case AP_RESPONSE_NO_PENDING_REPLY: |
| if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY) |
| stat = DEV_EMPTY; |
| else |
| stat = DEV_NO_WORK; |
| break; |
| case AP_RESPONSE_INDEX_TOO_BIG: |
| case AP_RESPONSE_NO_FIRST_PART: |
| case AP_RESPONSE_MESSAGE_TOO_BIG: |
| stat = DEV_BAD_MESSAGE; |
| break; |
| default: |
| break; |
| } |
| break; |
| default: |
| break; |
| } |
| |
| return stat; |
| } |
| |
| static inline int |
| pad_msg(unsigned char *buffer, int totalLength, int msgLength) |
| { |
| int pad_len; |
| |
| for (pad_len = 0; pad_len < (totalLength - msgLength); pad_len++) |
| if (buffer[pad_len] != 0x00) |
| break; |
| pad_len -= 3; |
| if (pad_len < 8) |
| return SEN_PAD_ERROR; |
| |
| buffer[0] = 0x00; |
| buffer[1] = 0x02; |
| |
| memcpy(buffer+2, static_pad, pad_len); |
| |
| buffer[pad_len + 2] = 0x00; |
| |
| return 0; |
| } |
| |
| static inline int |
| is_common_public_key(unsigned char *key, int len) |
| { |
| int i; |
| |
| for (i = 0; i < len; i++) |
| if (key[i]) |
| break; |
| key += i; |
| len -= i; |
| if (((len == 1) && (key[0] == 3)) || |
| ((len == 3) && (key[0] == 1) && (key[1] == 0) && (key[2] == 1))) |
| return 1; |
| |
| return 0; |
| } |
| |
| static int |
| ICAMEX_msg_to_type4MEX_msg(struct ica_rsa_modexpo *icaMex_p, int *z90cMsg_l_p, |
| union type4_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 type4_msg *tmp_type4_msg; |
| |
| mod_len = icaMex_p->inputdatalength; |
| |
| msg_size = ((mod_len <= 128) ? TYPE4_SME_LEN : TYPE4_LME_LEN) + |
| CALLER_HEADER; |
| |
| memset(z90cMsg_p, 0, msg_size); |
| |
| tmp_type4_msg = (union type4_msg *) |
| ((unsigned char *) z90cMsg_p + CALLER_HEADER); |
| |
| tmp_type4_msg->sme.header.msg_type_code = TYPE4_TYPE_CODE; |
| tmp_type4_msg->sme.header.request_code = TYPE4_REQU_CODE; |
| |
| if (mod_len <= 128) { |
| tmp_type4_msg->sme.header.msg_fmt = TYPE4_SME_FMT; |
| tmp_type4_msg->sme.header.msg_len = TYPE4_SME_LEN; |
| mod_tgt = tmp_type4_msg->sme.modulus; |
| mod_tgt_len = sizeof(tmp_type4_msg->sme.modulus); |
| exp_tgt = tmp_type4_msg->sme.exponent; |
| exp_tgt_len = sizeof(tmp_type4_msg->sme.exponent); |
| inp_tgt = tmp_type4_msg->sme.message; |
| inp_tgt_len = sizeof(tmp_type4_msg->sme.message); |
| } else { |
| tmp_type4_msg->lme.header.msg_fmt = TYPE4_LME_FMT; |
| tmp_type4_msg->lme.header.msg_len = TYPE4_LME_LEN; |
| mod_tgt = tmp_type4_msg->lme.modulus; |
| mod_tgt_len = sizeof(tmp_type4_msg->lme.modulus); |
| exp_tgt = tmp_type4_msg->lme.exponent; |
| exp_tgt_len = sizeof(tmp_type4_msg->lme.exponent); |
| inp_tgt = tmp_type4_msg->lme.message; |
| inp_tgt_len = sizeof(tmp_type4_msg->lme.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_type4CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p, |
| int *z90cMsg_l_p, union type4_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; |
| unsigned char *p_tgt, *q_tgt, *dp_tgt, *dq_tgt, *u_tgt, *inp_tgt; |
| union type4_msg *tmp_type4_msg; |
| |
| mod_len = icaMsg_p->inputdatalength; |
| short_len = mod_len / 2; |
| long_len = mod_len / 2 + 8; |
| |
| tmp_size = ((mod_len <= 128) ? TYPE4_SCR_LEN : TYPE4_LCR_LEN) + |
| CALLER_HEADER; |
| |
| memset(z90cMsg_p, 0, tmp_size); |
| |
| tmp_type4_msg = (union type4_msg *) |
| ((unsigned char *) z90cMsg_p + CALLER_HEADER); |
| |
| tmp_type4_msg->scr.header.msg_type_code = TYPE4_TYPE_CODE; |
| tmp_type4_msg->scr.header.request_code = TYPE4_REQU_CODE; |
| if (mod_len <= 128) { |
| tmp_type4_msg->scr.header.msg_fmt = TYPE4_SCR_FMT; |
| tmp_type4_msg->scr.header.msg_len = TYPE4_SCR_LEN; |
| p_tgt = tmp_type4_msg->scr.p; |
| p_tgt_len = sizeof(tmp_type4_msg->scr.p); |
| q_tgt = tmp_type4_msg->scr.q; |
| q_tgt_len = sizeof(tmp_type4_msg->scr.q); |
| dp_tgt = tmp_type4_msg->scr.dp; |
| dp_tgt_len = sizeof(tmp_type4_msg->scr.dp); |
| dq_tgt = tmp_type4_msg->scr.dq; |
| dq_tgt_len = sizeof(tmp_type4_msg->scr.dq); |
| u_tgt = tmp_type4_msg->scr.u; |
| u_tgt_len = sizeof(tmp_type4_msg->scr.u); |
| inp_tgt = tmp_type4_msg->scr.message; |
| inp_tgt_len = sizeof(tmp_type4_msg->scr.message); |
| } else { |
| tmp_type4_msg->lcr.header.msg_fmt = TYPE4_LCR_FMT; |
| tmp_type4_msg->lcr.header.msg_len = TYPE4_LCR_LEN; |
| p_tgt = tmp_type4_msg->lcr.p; |
| p_tgt_len = sizeof(tmp_type4_msg->lcr.p); |
| q_tgt = tmp_type4_msg->lcr.q; |
| q_tgt_len = sizeof(tmp_type4_msg->lcr.q); |
| dp_tgt = tmp_type4_msg->lcr.dp; |
| dp_tgt_len = sizeof(tmp_type4_msg->lcr.dp); |
| dq_tgt = tmp_type4_msg->lcr.dq; |
| dq_tgt_len = sizeof(tmp_type4_msg->lcr.dq); |
| u_tgt = tmp_type4_msg->lcr.u; |
| u_tgt_len = sizeof(tmp_type4_msg->lcr.u); |
| inp_tgt = tmp_type4_msg->lcr.message; |
| inp_tgt_len = sizeof(tmp_type4_msg->lcr.message); |
| } |
| |
| p_tgt += (p_tgt_len - long_len); |
| if (copy_from_user(p_tgt, icaMsg_p->np_prime, 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_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_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; |
| } |
| |
| static int |
| ICAMEX_msg_to_type6MEX_de_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx, |
| int *z90cMsg_l_p, struct type6_msg *z90cMsg_p) |
| { |
| int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l; |
| unsigned char *temp; |
| 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; |
| total_CPRB_len = tmp_size - sizeof(struct type6_hdr); |
| parmBlock_l = total_CPRB_len - sizeof(struct CPRB); |
| tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER; |
| |
| memset(z90cMsg_p, 0, tmp_size); |
| |
| temp = (unsigned char *)z90cMsg_p + CALLER_HEADER; |
| memcpy(temp, &static_type6_hdr, sizeof(struct type6_hdr)); |
| tp6Hdr_p = (struct type6_hdr *)temp; |
| tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4); |
| tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE; |
| |
| temp += sizeof(struct type6_hdr); |
| memcpy(temp, &static_cprb, sizeof(struct CPRB)); |
| cprb_p = (struct CPRB *) temp; |
| cprb_p->usage_domain[0]= (unsigned char)cdx; |
| itoLe2(&parmBlock_l, cprb_p->req_parml); |
| itoLe2((int *)&(tp6Hdr_p->FromCardLen1), cprb_p->rpl_parml); |
| |
| temp += sizeof(struct CPRB); |
| memcpy(temp, &static_pkd_function_and_rules, |
| sizeof(struct function_and_rules_block)); |
| |
| temp += sizeof(struct function_and_rules_block); |
| vud_len = 2 + icaMsg_p->inputdatalength; |
| itoLe2(&vud_len, temp); |
| |
| temp += 2; |
| if (copy_from_user(temp, icaMsg_p->inputdata, mod_len)) |
| return SEN_RELEASED; |
| if (is_empty(temp, mod_len)) |
| return SEN_USER_ERROR; |
| |
| temp += mod_len; |
| memcpy(temp, &static_T6_keyBlock_hdr, sizeof(struct T6_keyBlock_hdr)); |
| |
| temp += sizeof(struct T6_keyBlock_hdr); |
| memcpy(temp, &static_pvt_me_key, sizeof(struct cca_private_ext_ME)); |
| key_p = (struct cca_private_ext_ME *)temp; |
| temp = key_p->pvtMESec.exponent + sizeof(key_p->pvtMESec.exponent) |
| - mod_len; |
| if (copy_from_user(temp, icaMsg_p->b_key, mod_len)) |
| return SEN_RELEASED; |
| if (is_empty(temp, mod_len)) |
| return SEN_USER_ERROR; |
| |
| if (is_common_public_key(temp, mod_len)) { |
| 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)) |
| return SEN_RELEASED; |
| if (is_empty(temp, mod_len)) |
| return SEN_USER_ERROR; |
| |
| key_p->pubMESec.modulus_bit_len = 8 * mod_len; |
| |
| *z90cMsg_l_p = tmp_size - CALLER_HEADER; |
| |
| return 0; |
| } |
| |
| static int |
| ICAMEX_msg_to_type6MEX_en_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx, |
| int *z90cMsg_l_p, struct type6_msg *z90cMsg_p) |
| { |
| int mod_len, vud_len, exp_len, key_len; |
| int pad_len, tmp_size, total_CPRB_len, parmBlock_l, i; |
| 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)) { |
| kfree(temp_exp); |
| return SEN_RELEASED; |
| } |
| 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) { |
| kfree(temp_exp); |
| return SEN_USER_ERROR; |
| } |
| |
| exp_len = mod_len - i; |
| exp_p += i; |
| |
| PDEBUG("exp_len after computation: %08x\n", exp_len); |
| tmp_size = FIXED_TYPE6_ME_EN_LEN + 2 * mod_len + exp_len; |
| total_CPRB_len = tmp_size - sizeof(struct type6_hdr); |
| parmBlock_l = total_CPRB_len - sizeof(struct CPRB); |
| tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER; |
| |
| vud_len = 2 + mod_len; |
| memset(z90cMsg_p, 0, tmp_size); |
| |
| temp = (unsigned char *)z90cMsg_p + CALLER_HEADER; |
| memcpy(temp, &static_type6_hdr, sizeof(struct type6_hdr)); |
| tp6Hdr_p = (struct type6_hdr *)temp; |
| tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4); |
| tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE; |
| memcpy(tp6Hdr_p->function_code, static_PKE_function_code, |
| sizeof(static_PKE_function_code)); |
| temp += sizeof(struct type6_hdr); |
| memcpy(temp, &static_cprb, sizeof(struct CPRB)); |
| cprb_p = (struct CPRB *) temp; |
| cprb_p->usage_domain[0]= (unsigned char)cdx; |
| itoLe2((int *)&(tp6Hdr_p->FromCardLen1), cprb_p->rpl_parml); |
| temp += sizeof(struct CPRB); |
| memcpy(temp, &static_pke_function_and_rules, |
| 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)) { |
| kfree(temp_exp); |
| return SEN_RELEASED; |
| } |
| if (is_empty(temp, mod_len)) { |
| kfree(temp_exp); |
| return SEN_USER_ERROR; |
| } |
| 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))) { |
| kfree(temp_exp); |
| return SEN_NOT_AVAIL; |
| } |
| pad_len = i + 1; |
| vud_len = mod_len - pad_len; |
| memmove(temp, temp+pad_len, vud_len); |
| temp -= 2; |
| vud_len += 2; |
| itoLe2(&vud_len, temp); |
| temp += (vud_len); |
| keyb_p = (struct T6_keyBlock_hdr *)temp; |
| temp += sizeof(struct T6_keyBlock_hdr); |
| memcpy(temp, &static_public_key, sizeof(static_public_key)); |
| 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; |
| if (is_empty(temp, mod_len)) |
| 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 = 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; |
| itoLe2(&key_len, keyb_p->ulen); |
| key_len += 2; |
| itoLe2(&key_len, keyb_p->blen); |
| parmBlock_l -= pad_len; |
| itoLe2(&parmBlock_l, cprb_p->req_parml); |
| *z90cMsg_l_p = tmp_size - CALLER_HEADER; |
| |
| return 0; |
| } |
| |
| static int |
| ICACRT_msg_to_type6CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx, |
| int *z90cMsg_l_p, struct type6_msg *z90cMsg_p) |
| { |
| int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l, short_len; |
| int long_len, pad_len, keyPartsLen, tmp_l; |
| unsigned char *tgt_p, *temp; |
| struct type6_hdr *tp6Hdr_p; |
| struct CPRB *cprb_p; |
| struct cca_token_hdr *keyHdr_p; |
| struct cca_pvt_ext_CRT_sec *pvtSec_p; |
| struct cca_public_sec *pubSec_p; |
| |
| mod_len = icaMsg_p->inputdatalength; |
| short_len = mod_len / 2; |
| long_len = 8 + short_len; |
| keyPartsLen = 3 * long_len + 2 * short_len; |
| pad_len = (8 - (keyPartsLen % 8)) % 8; |
| keyPartsLen += pad_len + mod_len; |
| tmp_size = FIXED_TYPE6_CR_LEN + keyPartsLen + mod_len; |
| total_CPRB_len = tmp_size - sizeof(struct type6_hdr); |
| parmBlock_l = total_CPRB_len - sizeof(struct CPRB); |
| vud_len = 2 + mod_len; |
| tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER; |
| |
| memset(z90cMsg_p, 0, tmp_size); |
| tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER; |
| memcpy(tgt_p, &static_type6_hdr, sizeof(struct type6_hdr)); |
| tp6Hdr_p = (struct type6_hdr *)tgt_p; |
| tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4); |
| tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE; |
| tgt_p += sizeof(struct type6_hdr); |
| cprb_p = (struct CPRB *) tgt_p; |
| memcpy(tgt_p, &static_cprb, sizeof(struct CPRB)); |
| cprb_p->usage_domain[0]= *((unsigned char *)(&(cdx))+3); |
| itoLe2(&parmBlock_l, cprb_p->req_parml); |
| memcpy(cprb_p->rpl_parml, cprb_p->req_parml, |
| sizeof(cprb_p->req_parml)); |
| tgt_p += sizeof(struct CPRB); |
| memcpy(tgt_p, &static_pkd_function_and_rules, |
| sizeof(struct function_and_rules_block)); |
| tgt_p += sizeof(struct function_and_rules_block); |
| itoLe2(&vud_len, tgt_p); |
| 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; |
| tgt_p += mod_len; |
| tmp_l = sizeof(struct T6_keyBlock_hdr) + sizeof(struct cca_token_hdr) + |
| sizeof(struct cca_pvt_ext_CRT_sec) + 0x0F + keyPartsLen; |
| itoLe2(&tmp_l, tgt_p); |
| temp = tgt_p + 2; |
| tmp_l -= 2; |
| itoLe2(&tmp_l, temp); |
| tgt_p += sizeof(struct T6_keyBlock_hdr); |
| keyHdr_p = (struct cca_token_hdr *)tgt_p; |
| keyHdr_p->token_identifier = CCA_TKN_HDR_ID_EXT; |
| tmp_l -= 4; |
| keyHdr_p->token_length = tmp_l; |
| tgt_p += sizeof(struct cca_token_hdr); |
| pvtSec_p = (struct cca_pvt_ext_CRT_sec *)tgt_p; |
| pvtSec_p->section_identifier = CCA_PVT_EXT_CRT_SEC_ID_PVT; |
| pvtSec_p->section_length = |
| sizeof(struct cca_pvt_ext_CRT_sec) + keyPartsLen; |
| pvtSec_p->key_format = CCA_PVT_EXT_CRT_SEC_FMT_CL; |
| pvtSec_p->key_use_flags[0] = CCA_PVT_USAGE_ALL; |
| pvtSec_p->p_len = long_len; |
| pvtSec_p->q_len = short_len; |
| pvtSec_p->dp_len = long_len; |
| pvtSec_p->dq_len = short_len; |
| pvtSec_p->u_len = long_len; |
| pvtSec_p->mod_len = mod_len; |
| pvtSec_p->pad_len = pad_len; |
| tgt_p += sizeof(struct cca_pvt_ext_CRT_sec); |
| if (copy_from_user(tgt_p, icaMsg_p->np_prime, long_len)) |
| return SEN_RELEASED; |
| if (is_empty(tgt_p, long_len)) |
| return SEN_USER_ERROR; |
| tgt_p += long_len; |
| if (copy_from_user(tgt_p, icaMsg_p->nq_prime, short_len)) |
| return SEN_RELEASED; |
| if (is_empty(tgt_p, short_len)) |
| return SEN_USER_ERROR; |
| tgt_p += short_len; |
| if (copy_from_user(tgt_p, icaMsg_p->bp_key, long_len)) |
| return SEN_RELEASED; |
| if (is_empty(tgt_p, long_len)) |
| return SEN_USER_ERROR; |
| tgt_p += long_len; |
| if (copy_from_user(tgt_p, icaMsg_p->bq_key, short_len)) |
| return SEN_RELEASED; |
| if (is_empty(tgt_p, short_len)) |
| return SEN_USER_ERROR; |
| tgt_p += short_len; |
| if (copy_from_user(tgt_p, icaMsg_p->u_mult_inv, long_len)) |
| return SEN_RELEASED; |
| if (is_empty(tgt_p, long_len)) |
| return SEN_USER_ERROR; |
| tgt_p += long_len; |
| tgt_p += pad_len; |
| memset(tgt_p, 0xFF, mod_len); |
| tgt_p += mod_len; |
| memcpy(tgt_p, &static_cca_pub_sec, sizeof(struct cca_public_sec)); |
| pubSec_p = (struct cca_public_sec *) tgt_p; |
| pubSec_p->modulus_bit_len = 8 * mod_len; |
| *z90cMsg_l_p = tmp_size - CALLER_HEADER; |
| |
| return 0; |
| } |
| |
| 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 dev_type) |
| { |
| int mod_len, exp_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l; |
| int key_len, i; |
| 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)) { |
| kfree(temp_exp); |
| return SEN_RELEASED; |
| } |
| 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) { |
| kfree(temp_exp); |
| return SEN_USER_ERROR; |
| } |
| exp_len = mod_len - i; |
| exp_p += i; |
| PDEBUG("exp_len after computation: %08x\n", exp_len); |
| tmp_size = FIXED_TYPE6_ME_EN_LENX + 2 * mod_len + exp_len; |
| total_CPRB_len = tmp_size - sizeof(struct type6_hdr); |
| parmBlock_l = total_CPRB_len - sizeof(struct CPRBX); |
| tmp_size = tmp_size + CALLER_HEADER; |
| vud_len = 2 + mod_len; |
| memset(z90cMsg_p, 0, tmp_size); |
| tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER; |
| memcpy(tgt_p, &static_type6_hdrX, sizeof(struct type6_hdr)); |
| tp6Hdr_p = (struct type6_hdr *)tgt_p; |
| tp6Hdr_p->ToCardLen1 = total_CPRB_len; |
| tp6Hdr_p->FromCardLen1 = RESPONSE_CPRBX_SIZE; |
| memcpy(tp6Hdr_p->function_code, static_PKE_function_code, |
| sizeof(static_PKE_function_code)); |
| tgt_p += sizeof(struct type6_hdr); |
| memcpy(tgt_p, &static_cprbx, sizeof(struct CPRBX)); |
| cprbx_p = (struct CPRBX *) tgt_p; |
| cprbx_p->domain = (unsigned short)cdx; |
| cprbx_p->rpl_msgbl = RESPONSE_CPRBX_SIZE; |
| tgt_p += sizeof(struct CPRBX); |
| 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)) { |
| 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; |
| keyb_p = (struct T6_keyBlock_hdrX *)tgt_p; |
| tgt_p += sizeof(struct T6_keyBlock_hdrX); |
| memcpy(tgt_p, &static_public_key, sizeof(static_public_key)); |
| 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; |
| if (is_empty(temp, mod_len)) |
| 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 = 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; |
| keyb_p->ulen = (unsigned short)key_len; |
| key_len += 2; |
| keyb_p->blen = (unsigned short)key_len; |
| cprbx_p->req_parml = parmBlock_l; |
| *z90cMsg_l_p = tmp_size - CALLER_HEADER; |
| |
| return 0; |
| } |
| |
| 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 dev_type) |
| { |
| int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l, short_len; |
| int long_len, pad_len, keyPartsLen, tmp_l; |
| unsigned char *tgt_p, *temp; |
| struct type6_hdr *tp6Hdr_p; |
| struct CPRBX *cprbx_p; |
| struct cca_token_hdr *keyHdr_p; |
| struct cca_pvt_ext_CRT_sec *pvtSec_p; |
| struct cca_public_sec *pubSec_p; |
| |
| mod_len = icaMsg_p->inputdatalength; |
| short_len = mod_len / 2; |
| long_len = 8 + short_len; |
| keyPartsLen = 3 * long_len + 2 * short_len; |
| pad_len = (8 - (keyPartsLen % 8)) % 8; |
| keyPartsLen += pad_len + mod_len; |
| tmp_size = FIXED_TYPE6_CR_LENX + keyPartsLen + mod_len; |
| total_CPRB_len = tmp_size - sizeof(struct type6_hdr); |
| parmBlock_l = total_CPRB_len - sizeof(struct CPRBX); |
| vud_len = 2 + mod_len; |
| tmp_size = tmp_size + CALLER_HEADER; |
| memset(z90cMsg_p, 0, tmp_size); |
| tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER; |
| memcpy(tgt_p, &static_type6_hdrX, sizeof(struct type6_hdr)); |
| tp6Hdr_p = (struct type6_hdr *)tgt_p; |
| tp6Hdr_p->ToCardLen1 = total_CPRB_len; |
| tp6Hdr_p->FromCardLen1 = RESPONSE_CPRBX_SIZE; |
| tgt_p += sizeof(struct type6_hdr); |
| cprbx_p = (struct CPRBX *) tgt_p; |
| memcpy(tgt_p, &static_cprbx, sizeof(struct CPRBX)); |
| cprbx_p->domain = (unsigned short)cdx; |
| cprbx_p->req_parml = parmBlock_l; |
| cprbx_p->rpl_msgbl = parmBlock_l; |
| tgt_p += sizeof(struct CPRBX); |
| 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; |
| 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; |
| tgt_p += mod_len; |
| tmp_l = sizeof(struct T6_keyBlock_hdr) + sizeof(struct cca_token_hdr) + |
| sizeof(struct cca_pvt_ext_CRT_sec) + 0x0F + keyPartsLen; |
| *((short *)tgt_p) = (short) tmp_l; |
| temp = tgt_p + 2; |
| tmp_l -= 2; |
| *((short *)temp) = (short) tmp_l; |
| tgt_p += sizeof(struct T6_keyBlock_hdr); |
| keyHdr_p = (struct cca_token_hdr *)tgt_p; |
| keyHdr_p->token_identifier = CCA_TKN_HDR_ID_EXT; |
| tmp_l -= 4; |
| keyHdr_p->token_length = tmp_l; |
| tgt_p += sizeof(struct cca_token_hdr); |
| pvtSec_p = (struct cca_pvt_ext_CRT_sec *)tgt_p; |
| pvtSec_p->section_identifier = CCA_PVT_EXT_CRT_SEC_ID_PVT; |
| pvtSec_p->section_length = |
| sizeof(struct cca_pvt_ext_CRT_sec) + keyPartsLen; |
| pvtSec_p->key_format = CCA_PVT_EXT_CRT_SEC_FMT_CL; |
| pvtSec_p->key_use_flags[0] = CCA_PVT_USAGE_ALL; |
| pvtSec_p->p_len = long_len; |
| pvtSec_p->q_len = short_len; |
| pvtSec_p->dp_len = long_len; |
| pvtSec_p->dq_len = short_len; |
| pvtSec_p->u_len = long_len; |
| pvtSec_p->mod_len = mod_len; |
| pvtSec_p->pad_len = pad_len; |
| tgt_p += sizeof(struct cca_pvt_ext_CRT_sec); |
| if (copy_from_user(tgt_p, icaMsg_p->np_prime, long_len)) |
| return SEN_RELEASED; |
| if (is_empty(tgt_p, long_len)) |
| return SEN_USER_ERROR; |
| tgt_p += long_len; |
| if (copy_from_user(tgt_p, icaMsg_p->nq_prime, short_len)) |
| return SEN_RELEASED; |
| if (is_empty(tgt_p, short_len)) |
| return SEN_USER_ERROR; |
| tgt_p += short_len; |
| if (copy_from_user(tgt_p, icaMsg_p->bp_key, long_len)) |
| return SEN_RELEASED; |
| if (is_empty(tgt_p, long_len)) |
| return SEN_USER_ERROR; |
| tgt_p += long_len; |
| if (copy_from_user(tgt_p, icaMsg_p->bq_key, short_len)) |
| return SEN_RELEASED; |
| if (is_empty(tgt_p, short_len)) |
| return SEN_USER_ERROR; |
| tgt_p += short_len; |
| if (copy_from_user(tgt_p, icaMsg_p->u_mult_inv, long_len)) |
| return SEN_RELEASED; |
| if (is_empty(tgt_p, long_len)) |
| return SEN_USER_ERROR; |
| tgt_p += long_len; |
| tgt_p += pad_len; |
| memset(tgt_p, 0xFF, mod_len); |
| tgt_p += mod_len; |
| memcpy(tgt_p, &static_cca_pub_sec, sizeof(struct cca_public_sec)); |
| pubSec_p = (struct cca_public_sec *) tgt_p; |
| pubSec_p->modulus_bit_len = 8 * mod_len; |
| *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) |
| { |
| if (dev_type == PCICA) { |
| if (func == ICARSACRT) |
| return ICACRT_msg_to_type4CRT_msg( |
| (struct ica_rsa_modexpo_crt *) buffer, |
| msg_l_p, (union type4_msg *) msg_p); |
| else |
| return ICAMEX_msg_to_type4MEX_msg( |
| (struct ica_rsa_modexpo *) buffer, |
| msg_l_p, (union type4_msg *) msg_p); |
| } |
| if (dev_type == PCICC) { |
| if (func == ICARSACRT) |
| return ICACRT_msg_to_type6CRT_msg( |
| (struct ica_rsa_modexpo_crt *) buffer, |
| cdx, msg_l_p, (struct type6_msg *)msg_p); |
| if (function == PCI_FUNC_KEY_ENCRYPT) |
| return ICAMEX_msg_to_type6MEX_en_msg( |
| (struct ica_rsa_modexpo *) buffer, |
| cdx, msg_l_p, (struct type6_msg *) msg_p); |
| else |
| return ICAMEX_msg_to_type6MEX_de_msg( |
| (struct ica_rsa_modexpo *) buffer, |
| cdx, msg_l_p, (struct type6_msg *) msg_p); |
| } |
| 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, |
| dev_type); |
| else |
| return ICAMEX_msg_to_type6MEX_msgX( |
| (struct ica_rsa_modexpo *) buffer, |
| cdx, msg_l_p, (struct type6_msg *) msg_p, |
| dev_type); |
| } |
| |
| 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 (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 error_hdr *errh_p = (struct error_hdr *) response; |
| struct type84_hdr *t84h_p = (struct type84_hdr *) response; |
| 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; |
| |
| src_p = 0; |
| reply_code = 0; |
| service_rc = 0; |
| service_rs = 0; |
| src_l = 0; |
| switch (errh_p->type) { |
| case TYPE82_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 TYPE84_RSP_CODE: |
| src_l = icaMsg_p->outputdatalength; |
| src_p = response + (int)t84h_p->len - src_l; |
| break; |
| case TYPE86_RSP_CODE: |
| 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 (cprb_p->cprb_ver_id != 0x02) { |
| le2toI(cprb_p->ccp_rtcode, &service_rc); |
| if (service_rc != 0) { |
| le2toI(cprb_p->ccp_rscode, &service_rs); |
| if ((service_rc == 8) && (service_rs == 66)) |
| 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 (PCICC): %d/%d\n", |
| service_rc, service_rs); |
| return REC_OPERAND_INV; |
| } |
| src_p = (unsigned char *)cprb_p + sizeof(struct CPRB); |
| src_p += 4; |
| le2toI(src_p, &src_l); |
| src_l -= 2; |
| src_p += 2; |
| } else { |
| service_rc = (int)cprbx_p->ccp_rtcode; |
| if (service_rc != 0) { |
| service_rs = (int) cprbx_p->ccp_rscode; |
| if ((service_rc == 8) && (service_rs == 66)) |
| 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 (PCIXCC): %d/%d\n", |
| service_rc, service_rs); |
| return REC_OPERAND_INV; |
| } |
| src_p = (unsigned char *) |
| cprbx_p + sizeof(struct CPRBX); |
| src_p += 4; |
| src_l = (int)(*((short *) src_p)); |
| src_l -= 2; |
| src_p += 2; |
| } |
| break; |
| default: |
| 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 (reply_code) |
| switch (reply_code) { |
| case REP82_ERROR_OPERAND_INVALID: |
| return REC_OPERAND_INV; |
| case REP82_ERROR_OPERAND_SIZE: |
| return REC_OPERAND_SIZE; |
| case REP82_ERROR_EVEN_MOD_IN_OPND: |
| return REC_EVEN_MOD; |
| 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: |
| PRINTKW("reply code = %d\n", reply_code); |
| return REC_HARDWAR_ERR; |
| } |
| |
| if (service_rc != 0) |
| return REC_OPERAND_INV; |
| |
| if ((src_l > icaMsg_p->outputdatalength) || |
| (src_l > RESPBUFFSIZE) || |
| (src_l <= 0)) |
| return REC_OPERAND_SIZE; |
| |
| PDEBUG("Length returned = %d\n", src_l); |
| tgt_p = resp_buff + icaMsg_p->outputdatalength - src_l; |
| memcpy(tgt_p, src_p, src_l); |
| if ((errh_p->type == TYPE86_RSP_CODE) && (resp_buff < tgt_p)) { |
| memset(resp_buff, 0, icaMsg_p->outputdatalength - src_l); |
| 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 0; |
| } |
| |