blob: dc542e0a3055a6abb63314ee6dd20ecc451c7d2d [file] [log] [blame]
Holger Dengler5e55a482012-08-28 16:45:36 +02001/*
2 * zcrypt 2.1.0
3 *
4 * Copyright IBM Corp. 2001, 2012
5 * Author(s): Robert Burroughs
6 * Eric Rossman (edrossma@us.ibm.com)
7 *
8 * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
9 * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
10 * Ralph Wuerthner <rwuerthn@de.ibm.com>
11 * MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2, or (at your option)
16 * any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 */
27
Ingo Tuchscherer91f3e3e2013-11-20 10:47:13 +010028#define KMSG_COMPONENT "zcrypt"
29#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
30
Holger Dengler5e55a482012-08-28 16:45:36 +020031#include <linux/module.h>
32#include <linux/init.h>
33#include <linux/err.h>
34#include <linux/delay.h>
35#include <linux/slab.h>
36#include <linux/atomic.h>
37#include <linux/uaccess.h>
38
39#include "ap_bus.h"
40#include "zcrypt_api.h"
41#include "zcrypt_error.h"
42#include "zcrypt_msgtype6.h"
43#include "zcrypt_cca_key.h"
44
45#define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */
46#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
47
48#define CEIL4(x) ((((x)+3)/4)*4)
49
50struct response_type {
51 struct completion work;
52 int type;
53};
54#define PCIXCC_RESPONSE_TYPE_ICA 0
55#define PCIXCC_RESPONSE_TYPE_XCRB 1
Ingo Tuchscherer91f3e3e2013-11-20 10:47:13 +010056#define PCIXCC_RESPONSE_TYPE_EP11 2
Holger Dengler5e55a482012-08-28 16:45:36 +020057
58MODULE_AUTHOR("IBM Corporation");
59MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \
60 "Copyright IBM Corp. 2001, 2012");
61MODULE_LICENSE("GPL");
62
63static void zcrypt_msgtype6_receive(struct ap_device *, struct ap_message *,
64 struct ap_message *);
65
66/**
67 * CPRB
68 * Note that all shorts, ints and longs are little-endian.
69 * All pointer fields are 32-bits long, and mean nothing
70 *
71 * A request CPRB is followed by a request_parameter_block.
72 *
73 * The request (or reply) parameter block is organized thus:
74 * function code
75 * VUD block
76 * key block
77 */
78struct CPRB {
79 unsigned short cprb_len; /* CPRB length */
80 unsigned char cprb_ver_id; /* CPRB version id. */
81 unsigned char pad_000; /* Alignment pad byte. */
82 unsigned char srpi_rtcode[4]; /* SRPI return code LELONG */
83 unsigned char srpi_verb; /* SRPI verb type */
84 unsigned char flags; /* flags */
85 unsigned char func_id[2]; /* function id */
86 unsigned char checkpoint_flag; /* */
87 unsigned char resv2; /* reserved */
88 unsigned short req_parml; /* request parameter buffer */
89 /* length 16-bit little endian */
90 unsigned char req_parmp[4]; /* request parameter buffer *
91 * pointer (means nothing: the *
92 * parameter buffer follows *
93 * the CPRB). */
94 unsigned char req_datal[4]; /* request data buffer */
95 /* length ULELONG */
96 unsigned char req_datap[4]; /* request data buffer */
97 /* pointer */
98 unsigned short rpl_parml; /* reply parameter buffer */
99 /* length 16-bit little endian */
100 unsigned char pad_001[2]; /* Alignment pad bytes. ULESHORT */
101 unsigned char rpl_parmp[4]; /* reply parameter buffer *
102 * pointer (means nothing: the *
103 * parameter buffer follows *
104 * the CPRB). */
105 unsigned char rpl_datal[4]; /* reply data buffer len ULELONG */
106 unsigned char rpl_datap[4]; /* reply data buffer */
107 /* pointer */
108 unsigned short ccp_rscode; /* server reason code ULESHORT */
109 unsigned short ccp_rtcode; /* server return code ULESHORT */
110 unsigned char repd_parml[2]; /* replied parameter len ULESHORT*/
111 unsigned char mac_data_len[2]; /* Mac Data Length ULESHORT */
112 unsigned char repd_datal[4]; /* replied data length ULELONG */
113 unsigned char req_pc[2]; /* PC identifier */
114 unsigned char res_origin[8]; /* resource origin */
115 unsigned char mac_value[8]; /* Mac Value */
116 unsigned char logon_id[8]; /* Logon Identifier */
117 unsigned char usage_domain[2]; /* cdx */
118 unsigned char resv3[18]; /* reserved for requestor */
119 unsigned short svr_namel; /* server name length ULESHORT */
120 unsigned char svr_name[8]; /* server name */
121} __packed;
122
123struct function_and_rules_block {
124 unsigned char function_code[2];
125 unsigned short ulen;
126 unsigned char only_rule[8];
127} __packed;
128
129/**
130 * The following is used to initialize the CPRBX passed to the PCIXCC/CEX2C
131 * card in a type6 message. The 3 fields that must be filled in at execution
132 * time are req_parml, rpl_parml and usage_domain.
133 * Everything about this interface is ascii/big-endian, since the
134 * device does *not* have 'Intel inside'.
135 *
136 * The CPRBX is followed immediately by the parm block.
137 * The parm block contains:
138 * - function code ('PD' 0x5044 or 'PK' 0x504B)
139 * - rule block (one of:)
140 * + 0x000A 'PKCS-1.2' (MCL2 'PD')
141 * + 0x000A 'ZERO-PAD' (MCL2 'PK')
142 * + 0x000A 'ZERO-PAD' (MCL3 'PD' or CEX2C 'PD')
143 * + 0x000A 'MRP ' (MCL3 'PK' or CEX2C 'PK')
144 * - VUD block
145 */
146static struct CPRBX static_cprbx = {
147 .cprb_len = 0x00DC,
148 .cprb_ver_id = 0x02,
149 .func_id = {0x54, 0x32},
150};
151
152/**
153 * Convert a ICAMEX message to a type6 MEX message.
154 *
155 * @zdev: crypto device pointer
156 * @ap_msg: pointer to AP message
157 * @mex: pointer to user input data
158 *
159 * Returns 0 on success or -EFAULT.
160 */
161static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev,
162 struct ap_message *ap_msg,
163 struct ica_rsa_modexpo *mex)
164{
165 static struct type6_hdr static_type6_hdrX = {
166 .type = 0x06,
167 .offset1 = 0x00000058,
168 .agent_id = {'C', 'A',},
169 .function_code = {'P', 'K'},
170 };
171 static struct function_and_rules_block static_pke_fnr = {
172 .function_code = {'P', 'K'},
173 .ulen = 10,
174 .only_rule = {'M', 'R', 'P', ' ', ' ', ' ', ' ', ' '}
175 };
176 static struct function_and_rules_block static_pke_fnr_MCL2 = {
177 .function_code = {'P', 'K'},
178 .ulen = 10,
179 .only_rule = {'Z', 'E', 'R', 'O', '-', 'P', 'A', 'D'}
180 };
181 struct {
182 struct type6_hdr hdr;
183 struct CPRBX cprbx;
184 struct function_and_rules_block fr;
185 unsigned short length;
186 char text[0];
187 } __packed * msg = ap_msg->message;
188 int size;
189
190 /* VUD.ciphertext */
191 msg->length = mex->inputdatalength + 2;
192 if (copy_from_user(msg->text, mex->inputdata, mex->inputdatalength))
193 return -EFAULT;
194
195 /* Set up key which is located after the variable length text. */
196 size = zcrypt_type6_mex_key_en(mex, msg->text+mex->inputdatalength, 1);
197 if (size < 0)
198 return size;
199 size += sizeof(*msg) + mex->inputdatalength;
200
201 /* message header, cprbx and f&r */
202 msg->hdr = static_type6_hdrX;
203 msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
204 msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
205
206 msg->cprbx = static_cprbx;
207 msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
208 msg->cprbx.rpl_msgbl = msg->hdr.FromCardLen1;
209
210 msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
211 static_pke_fnr_MCL2 : static_pke_fnr;
212
213 msg->cprbx.req_parml = size - sizeof(msg->hdr) - sizeof(msg->cprbx);
214
215 ap_msg->length = size;
216 return 0;
217}
218
219/**
220 * Convert a ICACRT message to a type6 CRT message.
221 *
222 * @zdev: crypto device pointer
223 * @ap_msg: pointer to AP message
224 * @crt: pointer to user input data
225 *
226 * Returns 0 on success or -EFAULT.
227 */
228static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
229 struct ap_message *ap_msg,
230 struct ica_rsa_modexpo_crt *crt)
231{
232 static struct type6_hdr static_type6_hdrX = {
233 .type = 0x06,
234 .offset1 = 0x00000058,
235 .agent_id = {'C', 'A',},
236 .function_code = {'P', 'D'},
237 };
238 static struct function_and_rules_block static_pkd_fnr = {
239 .function_code = {'P', 'D'},
240 .ulen = 10,
241 .only_rule = {'Z', 'E', 'R', 'O', '-', 'P', 'A', 'D'}
242 };
243
244 static struct function_and_rules_block static_pkd_fnr_MCL2 = {
245 .function_code = {'P', 'D'},
246 .ulen = 10,
247 .only_rule = {'P', 'K', 'C', 'S', '-', '1', '.', '2'}
248 };
249 struct {
250 struct type6_hdr hdr;
251 struct CPRBX cprbx;
252 struct function_and_rules_block fr;
253 unsigned short length;
254 char text[0];
255 } __packed * msg = ap_msg->message;
256 int size;
257
258 /* VUD.ciphertext */
259 msg->length = crt->inputdatalength + 2;
260 if (copy_from_user(msg->text, crt->inputdata, crt->inputdatalength))
261 return -EFAULT;
262
263 /* Set up key which is located after the variable length text. */
264 size = zcrypt_type6_crt_key(crt, msg->text + crt->inputdatalength, 1);
265 if (size < 0)
266 return size;
267 size += sizeof(*msg) + crt->inputdatalength; /* total size of msg */
268
269 /* message header, cprbx and f&r */
270 msg->hdr = static_type6_hdrX;
271 msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
272 msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
273
274 msg->cprbx = static_cprbx;
275 msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
276 msg->cprbx.req_parml = msg->cprbx.rpl_msgbl =
277 size - sizeof(msg->hdr) - sizeof(msg->cprbx);
278
279 msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
280 static_pkd_fnr_MCL2 : static_pkd_fnr;
281
282 ap_msg->length = size;
283 return 0;
284}
285
286/**
287 * Convert a XCRB message to a type6 CPRB message.
288 *
289 * @zdev: crypto device pointer
290 * @ap_msg: pointer to AP message
291 * @xcRB: pointer to user input data
292 *
293 * Returns 0 on success or -EFAULT, -EINVAL.
294 */
295struct type86_fmt2_msg {
296 struct type86_hdr hdr;
297 struct type86_fmt2_ext fmt2;
298} __packed;
299
300static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
301 struct ap_message *ap_msg,
302 struct ica_xcRB *xcRB)
303{
304 static struct type6_hdr static_type6_hdrX = {
305 .type = 0x06,
306 .offset1 = 0x00000058,
307 };
308 struct {
309 struct type6_hdr hdr;
310 struct CPRBX cprbx;
311 } __packed * msg = ap_msg->message;
312
313 int rcblen = CEIL4(xcRB->request_control_blk_length);
314 int replylen;
315 char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen;
316 char *function_code;
317
318 /* length checks */
319 ap_msg->length = sizeof(struct type6_hdr) +
320 CEIL4(xcRB->request_control_blk_length) +
321 xcRB->request_data_length;
322 if (ap_msg->length > MSGTYPE06_MAX_MSG_SIZE)
323 return -EINVAL;
324 replylen = sizeof(struct type86_fmt2_msg) +
325 CEIL4(xcRB->reply_control_blk_length) +
326 xcRB->reply_data_length;
327 if (replylen > MSGTYPE06_MAX_MSG_SIZE)
328 return -EINVAL;
329
330 /* prepare type6 header */
331 msg->hdr = static_type6_hdrX;
332 memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID));
333 msg->hdr.ToCardLen1 = xcRB->request_control_blk_length;
334 if (xcRB->request_data_length) {
335 msg->hdr.offset2 = msg->hdr.offset1 + rcblen;
336 msg->hdr.ToCardLen2 = xcRB->request_data_length;
337 }
338 msg->hdr.FromCardLen1 = xcRB->reply_control_blk_length;
339 msg->hdr.FromCardLen2 = xcRB->reply_data_length;
340
341 /* prepare CPRB */
342 if (copy_from_user(&(msg->cprbx), xcRB->request_control_blk_addr,
343 xcRB->request_control_blk_length))
344 return -EFAULT;
345 if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) >
346 xcRB->request_control_blk_length)
347 return -EINVAL;
348 function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len;
349 memcpy(msg->hdr.function_code, function_code,
350 sizeof(msg->hdr.function_code));
351
352 if (memcmp(function_code, "US", 2) == 0)
353 ap_msg->special = 1;
354 else
355 ap_msg->special = 0;
356
357 /* copy data block */
358 if (xcRB->request_data_length &&
359 copy_from_user(req_data, xcRB->request_data_address,
360 xcRB->request_data_length))
361 return -EFAULT;
362 return 0;
363}
364
Ingo Tuchscherer91f3e3e2013-11-20 10:47:13 +0100365static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev,
366 struct ap_message *ap_msg,
367 struct ep11_urb *xcRB)
368{
369 unsigned int lfmt;
370
371 static struct type6_hdr static_type6_ep11_hdr = {
372 .type = 0x06,
373 .rqid = {0x00, 0x01},
374 .function_code = {0x00, 0x00},
375 .agent_id[0] = 0x58, /* {'X'} */
376 .agent_id[1] = 0x43, /* {'C'} */
377 .offset1 = 0x00000058,
378 };
379
380 struct {
381 struct type6_hdr hdr;
382 struct ep11_cprb cprbx;
383 unsigned char pld_tag; /* fixed value 0x30 */
384 unsigned char pld_lenfmt; /* payload length format */
385 } __packed * msg = ap_msg->message;
386
387 struct pld_hdr {
388 unsigned char func_tag; /* fixed value 0x4 */
389 unsigned char func_len; /* fixed value 0x4 */
390 unsigned int func_val; /* function ID */
391 unsigned char dom_tag; /* fixed value 0x4 */
392 unsigned char dom_len; /* fixed value 0x4 */
393 unsigned int dom_val; /* domain id */
394 } __packed * payload_hdr;
395
396 /* length checks */
397 ap_msg->length = sizeof(struct type6_hdr) + xcRB->req_len;
398 if (CEIL4(xcRB->req_len) > MSGTYPE06_MAX_MSG_SIZE -
399 (sizeof(struct type6_hdr)))
400 return -EINVAL;
401
402 if (CEIL4(xcRB->resp_len) > MSGTYPE06_MAX_MSG_SIZE -
403 (sizeof(struct type86_fmt2_msg)))
404 return -EINVAL;
405
406 /* prepare type6 header */
407 msg->hdr = static_type6_ep11_hdr;
408 msg->hdr.ToCardLen1 = xcRB->req_len;
409 msg->hdr.FromCardLen1 = xcRB->resp_len;
410
411 /* Import CPRB data from the ioctl input parameter */
412 if (copy_from_user(&(msg->cprbx.cprb_len),
413 (char *)xcRB->req, xcRB->req_len)) {
414 return -EFAULT;
415 }
416
417 /*
418 The target domain field within the cprb body/payload block will be
419 replaced by the usage domain for non-management commands only.
420 Therefore we check the first bit of the 'flags' parameter for
421 management command indication.
Hendrik Bruecknerb4a96012013-12-13 12:53:42 +0100422 0 - non management command
Ingo Tuchscherer91f3e3e2013-11-20 10:47:13 +0100423 1 - management command
424 */
425 if (!((msg->cprbx.flags & 0x80) == 0x80)) {
426 msg->cprbx.target_id = (unsigned int)
427 AP_QID_QUEUE(zdev->ap_dev->qid);
428
429 if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/
430 switch (msg->pld_lenfmt & 0x03) {
431 case 1:
432 lfmt = 2;
433 break;
434 case 2:
435 lfmt = 3;
436 break;
437 default:
438 return -EINVAL;
439 }
440 } else {
441 lfmt = 1; /* length format #1 */
442 }
443 payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt);
444 payload_hdr->dom_val = (unsigned int)
445 AP_QID_QUEUE(zdev->ap_dev->qid);
446 }
447 return 0;
448}
449
Holger Dengler5e55a482012-08-28 16:45:36 +0200450/**
451 * Copy results from a type 86 ICA reply message back to user space.
452 *
453 * @zdev: crypto device pointer
454 * @reply: reply AP message.
455 * @data: pointer to user output data
456 * @length: size of user output data
457 *
458 * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
459 */
460struct type86x_reply {
461 struct type86_hdr hdr;
462 struct type86_fmt2_ext fmt2;
463 struct CPRBX cprbx;
464 unsigned char pad[4]; /* 4 byte function code/rules block ? */
465 unsigned short length;
466 char text[0];
467} __packed;
468
Ingo Tuchscherer91f3e3e2013-11-20 10:47:13 +0100469struct type86_ep11_reply {
470 struct type86_hdr hdr;
471 struct type86_fmt2_ext fmt2;
472 struct ep11_cprb cprbx;
473} __packed;
474
Holger Dengler5e55a482012-08-28 16:45:36 +0200475static int convert_type86_ica(struct zcrypt_device *zdev,
476 struct ap_message *reply,
477 char __user *outputdata,
478 unsigned int outputdatalength)
479{
480 static unsigned char static_pad[] = {
481 0x00, 0x02,
482 0x1B, 0x7B, 0x5D, 0xB5, 0x75, 0x01, 0x3D, 0xFD,
483 0x8D, 0xD1, 0xC7, 0x03, 0x2D, 0x09, 0x23, 0x57,
484 0x89, 0x49, 0xB9, 0x3F, 0xBB, 0x99, 0x41, 0x5B,
485 0x75, 0x21, 0x7B, 0x9D, 0x3B, 0x6B, 0x51, 0x39,
486 0xBB, 0x0D, 0x35, 0xB9, 0x89, 0x0F, 0x93, 0xA5,
487 0x0B, 0x47, 0xF1, 0xD3, 0xBB, 0xCB, 0xF1, 0x9D,
488 0x23, 0x73, 0x71, 0xFF, 0xF3, 0xF5, 0x45, 0xFB,
489 0x61, 0x29, 0x23, 0xFD, 0xF1, 0x29, 0x3F, 0x7F,
490 0x17, 0xB7, 0x1B, 0xA9, 0x19, 0xBD, 0x57, 0xA9,
491 0xD7, 0x95, 0xA3, 0xCB, 0xED, 0x1D, 0xDB, 0x45,
492 0x7D, 0x11, 0xD1, 0x51, 0x1B, 0xED, 0x71, 0xE9,
493 0xB1, 0xD1, 0xAB, 0xAB, 0x21, 0x2B, 0x1B, 0x9F,
494 0x3B, 0x9F, 0xF7, 0xF7, 0xBD, 0x63, 0xEB, 0xAD,
495 0xDF, 0xB3, 0x6F, 0x5B, 0xDB, 0x8D, 0xA9, 0x5D,
496 0xE3, 0x7D, 0x77, 0x49, 0x47, 0xF5, 0xA7, 0xFD,
497 0xAB, 0x2F, 0x27, 0x35, 0x77, 0xD3, 0x49, 0xC9,
498 0x09, 0xEB, 0xB1, 0xF9, 0xBF, 0x4B, 0xCB, 0x2B,
499 0xEB, 0xEB, 0x05, 0xFF, 0x7D, 0xC7, 0x91, 0x8B,
500 0x09, 0x83, 0xB9, 0xB9, 0x69, 0x33, 0x39, 0x6B,
501 0x79, 0x75, 0x19, 0xBF, 0xBB, 0x07, 0x1D, 0xBD,
502 0x29, 0xBF, 0x39, 0x95, 0x93, 0x1D, 0x35, 0xC7,
503 0xC9, 0x4D, 0xE5, 0x97, 0x0B, 0x43, 0x9B, 0xF1,
504 0x16, 0x93, 0x03, 0x1F, 0xA5, 0xFB, 0xDB, 0xF3,
505 0x27, 0x4F, 0x27, 0x61, 0x05, 0x1F, 0xB9, 0x23,
506 0x2F, 0xC3, 0x81, 0xA9, 0x23, 0x71, 0x55, 0x55,
507 0xEB, 0xED, 0x41, 0xE5, 0xF3, 0x11, 0xF1, 0x43,
508 0x69, 0x03, 0xBD, 0x0B, 0x37, 0x0F, 0x51, 0x8F,
509 0x0B, 0xB5, 0x89, 0x5B, 0x67, 0xA9, 0xD9, 0x4F,
510 0x01, 0xF9, 0x21, 0x77, 0x37, 0x73, 0x79, 0xC5,
511 0x7F, 0x51, 0xC1, 0xCF, 0x97, 0xA1, 0x75, 0xAD,
512 0x35, 0x9D, 0xD3, 0xD3, 0xA7, 0x9D, 0x5D, 0x41,
513 0x6F, 0x65, 0x1B, 0xCF, 0xA9, 0x87, 0x91, 0x09
514 };
515 struct type86x_reply *msg = reply->message;
516 unsigned short service_rc, service_rs;
517 unsigned int reply_len, pad_len;
518 char *data;
519
520 service_rc = msg->cprbx.ccp_rtcode;
521 if (unlikely(service_rc != 0)) {
522 service_rs = msg->cprbx.ccp_rscode;
523 if (service_rc == 8 && service_rs == 66)
524 return -EINVAL;
525 if (service_rc == 8 && service_rs == 65)
526 return -EINVAL;
527 if (service_rc == 8 && service_rs == 770)
528 return -EINVAL;
529 if (service_rc == 8 && service_rs == 783) {
530 zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
531 return -EAGAIN;
532 }
533 if (service_rc == 12 && service_rs == 769)
534 return -EINVAL;
535 if (service_rc == 8 && service_rs == 72)
536 return -EINVAL;
537 zdev->online = 0;
Ingo Tuchscherer91f3e3e2013-11-20 10:47:13 +0100538 pr_err("Cryptographic device %x failed and was set offline\n",
539 zdev->ap_dev->qid);
540 ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d",
541 zdev->ap_dev->qid, zdev->online,
542 msg->hdr.reply_code);
Holger Dengler5e55a482012-08-28 16:45:36 +0200543 return -EAGAIN; /* repeat the request on a different device. */
544 }
545 data = msg->text;
546 reply_len = msg->length - 2;
547 if (reply_len > outputdatalength)
548 return -EINVAL;
549 /*
550 * For all encipher requests, the length of the ciphertext (reply_len)
551 * will always equal the modulus length. For MEX decipher requests
552 * the output needs to get padded. Minimum pad size is 10.
553 *
554 * Currently, the cases where padding will be added is for:
555 * - PCIXCC_MCL2 using a CRT form token (since PKD didn't support
556 * ZERO-PAD and CRT is only supported for PKD requests)
557 * - PCICC, always
558 */
559 pad_len = outputdatalength - reply_len;
560 if (pad_len > 0) {
561 if (pad_len < 10)
562 return -EINVAL;
563 /* 'restore' padding left in the PCICC/PCIXCC card. */
564 if (copy_to_user(outputdata, static_pad, pad_len - 1))
565 return -EFAULT;
566 if (put_user(0, outputdata + pad_len - 1))
567 return -EFAULT;
568 }
569 /* Copy the crypto response to user space. */
570 if (copy_to_user(outputdata + pad_len, data, reply_len))
571 return -EFAULT;
572 return 0;
573}
574
575/**
576 * Copy results from a type 86 XCRB reply message back to user space.
577 *
578 * @zdev: crypto device pointer
579 * @reply: reply AP message.
580 * @xcRB: pointer to XCRB
581 *
582 * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
583 */
584static int convert_type86_xcrb(struct zcrypt_device *zdev,
585 struct ap_message *reply,
586 struct ica_xcRB *xcRB)
587{
588 struct type86_fmt2_msg *msg = reply->message;
589 char *data = reply->message;
590
591 /* Copy CPRB to user */
592 if (copy_to_user(xcRB->reply_control_blk_addr,
593 data + msg->fmt2.offset1, msg->fmt2.count1))
594 return -EFAULT;
595 xcRB->reply_control_blk_length = msg->fmt2.count1;
596
597 /* Copy data buffer to user */
598 if (msg->fmt2.count2)
599 if (copy_to_user(xcRB->reply_data_addr,
600 data + msg->fmt2.offset2, msg->fmt2.count2))
601 return -EFAULT;
602 xcRB->reply_data_length = msg->fmt2.count2;
603 return 0;
604}
605
Ingo Tuchscherer91f3e3e2013-11-20 10:47:13 +0100606/**
607 * Copy results from a type 86 EP11 XCRB reply message back to user space.
608 *
609 * @zdev: crypto device pointer
610 * @reply: reply AP message.
611 * @xcRB: pointer to EP11 user request block
612 *
613 * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
614 */
615static int convert_type86_ep11_xcrb(struct zcrypt_device *zdev,
616 struct ap_message *reply,
617 struct ep11_urb *xcRB)
618{
619 struct type86_fmt2_msg *msg = reply->message;
620 char *data = reply->message;
621
622 if (xcRB->resp_len < msg->fmt2.count1)
623 return -EINVAL;
624
625 /* Copy response CPRB to user */
626 if (copy_to_user((char *)xcRB->resp,
627 data + msg->fmt2.offset1, msg->fmt2.count1))
628 return -EFAULT;
629 xcRB->resp_len = msg->fmt2.count1;
630 return 0;
631}
632
Holger Dengler5e55a482012-08-28 16:45:36 +0200633static int convert_type86_rng(struct zcrypt_device *zdev,
634 struct ap_message *reply,
635 char *buffer)
636{
637 struct {
638 struct type86_hdr hdr;
639 struct type86_fmt2_ext fmt2;
640 struct CPRBX cprbx;
641 } __packed * msg = reply->message;
642 char *data = reply->message;
643
644 if (msg->cprbx.ccp_rtcode != 0 || msg->cprbx.ccp_rscode != 0)
645 return -EINVAL;
646 memcpy(buffer, data + msg->fmt2.offset2, msg->fmt2.count2);
647 return msg->fmt2.count2;
648}
649
650static int convert_response_ica(struct zcrypt_device *zdev,
651 struct ap_message *reply,
652 char __user *outputdata,
653 unsigned int outputdatalength)
654{
655 struct type86x_reply *msg = reply->message;
656
657 /* Response type byte is the second byte in the response. */
658 switch (((unsigned char *) reply->message)[1]) {
659 case TYPE82_RSP_CODE:
660 case TYPE88_RSP_CODE:
661 return convert_error(zdev, reply);
662 case TYPE86_RSP_CODE:
663 if (msg->cprbx.ccp_rtcode &&
664 (msg->cprbx.ccp_rscode == 0x14f) &&
665 (outputdatalength > 256)) {
666 if (zdev->max_exp_bit_length <= 17) {
667 zdev->max_exp_bit_length = 17;
668 return -EAGAIN;
669 } else
670 return -EINVAL;
671 }
672 if (msg->hdr.reply_code)
673 return convert_error(zdev, reply);
674 if (msg->cprbx.cprb_ver_id == 0x02)
675 return convert_type86_ica(zdev, reply,
676 outputdata, outputdatalength);
677 /* Fall through, no break, incorrect cprb version is an unknown
678 * response */
679 default: /* Unknown response type, this should NEVER EVER happen */
680 zdev->online = 0;
Ingo Tuchscherer91f3e3e2013-11-20 10:47:13 +0100681 pr_err("Cryptographic device %x failed and was set offline\n",
682 zdev->ap_dev->qid);
683 ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail",
684 zdev->ap_dev->qid, zdev->online);
Holger Dengler5e55a482012-08-28 16:45:36 +0200685 return -EAGAIN; /* repeat the request on a different device. */
686 }
687}
688
689static int convert_response_xcrb(struct zcrypt_device *zdev,
690 struct ap_message *reply,
691 struct ica_xcRB *xcRB)
692{
693 struct type86x_reply *msg = reply->message;
694
695 /* Response type byte is the second byte in the response. */
696 switch (((unsigned char *) reply->message)[1]) {
697 case TYPE82_RSP_CODE:
698 case TYPE88_RSP_CODE:
699 xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
700 return convert_error(zdev, reply);
701 case TYPE86_RSP_CODE:
702 if (msg->hdr.reply_code) {
703 memcpy(&(xcRB->status), msg->fmt2.apfs, sizeof(u32));
704 return convert_error(zdev, reply);
705 }
706 if (msg->cprbx.cprb_ver_id == 0x02)
707 return convert_type86_xcrb(zdev, reply, xcRB);
708 /* Fall through, no break, incorrect cprb version is an unknown
709 * response */
710 default: /* Unknown response type, this should NEVER EVER happen */
711 xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
712 zdev->online = 0;
Ingo Tuchscherer91f3e3e2013-11-20 10:47:13 +0100713 pr_err("Cryptographic device %x failed and was set offline\n",
714 zdev->ap_dev->qid);
715 ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail",
716 zdev->ap_dev->qid, zdev->online);
Holger Dengler5e55a482012-08-28 16:45:36 +0200717 return -EAGAIN; /* repeat the request on a different device. */
718 }
719}
720
Ingo Tuchscherer91f3e3e2013-11-20 10:47:13 +0100721static int convert_response_ep11_xcrb(struct zcrypt_device *zdev,
722 struct ap_message *reply, struct ep11_urb *xcRB)
723{
724 struct type86_ep11_reply *msg = reply->message;
725
726 /* Response type byte is the second byte in the response. */
727 switch (((unsigned char *)reply->message)[1]) {
728 case TYPE82_RSP_CODE:
729 case TYPE87_RSP_CODE:
730 return convert_error(zdev, reply);
731 case TYPE86_RSP_CODE:
732 if (msg->hdr.reply_code)
733 return convert_error(zdev, reply);
734 if (msg->cprbx.cprb_ver_id == 0x04)
735 return convert_type86_ep11_xcrb(zdev, reply, xcRB);
736 /* Fall through, no break, incorrect cprb version is an unknown resp.*/
737 default: /* Unknown response type, this should NEVER EVER happen */
738 zdev->online = 0;
739 pr_err("Cryptographic device %x failed and was set offline\n",
740 zdev->ap_dev->qid);
741 ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail",
742 zdev->ap_dev->qid, zdev->online);
743 return -EAGAIN; /* repeat the request on a different device. */
744 }
745}
746
Holger Dengler5e55a482012-08-28 16:45:36 +0200747static int convert_response_rng(struct zcrypt_device *zdev,
748 struct ap_message *reply,
749 char *data)
750{
751 struct type86x_reply *msg = reply->message;
752
753 switch (msg->hdr.type) {
754 case TYPE82_RSP_CODE:
755 case TYPE88_RSP_CODE:
756 return -EINVAL;
757 case TYPE86_RSP_CODE:
758 if (msg->hdr.reply_code)
759 return -EINVAL;
760 if (msg->cprbx.cprb_ver_id == 0x02)
761 return convert_type86_rng(zdev, reply, data);
762 /* Fall through, no break, incorrect cprb version is an unknown
763 * response */
764 default: /* Unknown response type, this should NEVER EVER happen */
765 zdev->online = 0;
Ingo Tuchscherer91f3e3e2013-11-20 10:47:13 +0100766 pr_err("Cryptographic device %x failed and was set offline\n",
767 zdev->ap_dev->qid);
768 ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail",
769 zdev->ap_dev->qid, zdev->online);
Holger Dengler5e55a482012-08-28 16:45:36 +0200770 return -EAGAIN; /* repeat the request on a different device. */
771 }
772}
773
774/**
775 * This function is called from the AP bus code after a crypto request
776 * "msg" has finished with the reply message "reply".
777 * It is called from tasklet context.
778 * @ap_dev: pointer to the AP device
779 * @msg: pointer to the AP message
780 * @reply: pointer to the AP reply message
781 */
782static void zcrypt_msgtype6_receive(struct ap_device *ap_dev,
783 struct ap_message *msg,
784 struct ap_message *reply)
785{
786 static struct error_hdr error_reply = {
787 .type = TYPE82_RSP_CODE,
788 .reply_code = REP82_ERROR_MACHINE_FAILURE,
789 };
790 struct response_type *resp_type =
791 (struct response_type *) msg->private;
792 struct type86x_reply *t86r;
793 int length;
794
795 /* Copy the reply message to the request message buffer. */
796 if (IS_ERR(reply)) {
797 memcpy(msg->message, &error_reply, sizeof(error_reply));
798 goto out;
799 }
800 t86r = reply->message;
801 if (t86r->hdr.type == TYPE86_RSP_CODE &&
802 t86r->cprbx.cprb_ver_id == 0x02) {
803 switch (resp_type->type) {
804 case PCIXCC_RESPONSE_TYPE_ICA:
805 length = sizeof(struct type86x_reply)
806 + t86r->length - 2;
807 length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length);
808 memcpy(msg->message, reply->message, length);
809 break;
810 case PCIXCC_RESPONSE_TYPE_XCRB:
811 length = t86r->fmt2.offset2 + t86r->fmt2.count2;
812 length = min(MSGTYPE06_MAX_MSG_SIZE, length);
813 memcpy(msg->message, reply->message, length);
814 break;
815 default:
816 memcpy(msg->message, &error_reply,
817 sizeof(error_reply));
818 }
819 } else
820 memcpy(msg->message, reply->message, sizeof(error_reply));
821out:
822 complete(&(resp_type->work));
823}
824
Ingo Tuchscherer91f3e3e2013-11-20 10:47:13 +0100825/**
826 * This function is called from the AP bus code after a crypto request
827 * "msg" has finished with the reply message "reply".
828 * It is called from tasklet context.
829 * @ap_dev: pointer to the AP device
830 * @msg: pointer to the AP message
831 * @reply: pointer to the AP reply message
832 */
833static void zcrypt_msgtype6_receive_ep11(struct ap_device *ap_dev,
834 struct ap_message *msg,
835 struct ap_message *reply)
836{
837 static struct error_hdr error_reply = {
838 .type = TYPE82_RSP_CODE,
839 .reply_code = REP82_ERROR_MACHINE_FAILURE,
840 };
841 struct response_type *resp_type =
842 (struct response_type *)msg->private;
843 struct type86_ep11_reply *t86r;
844 int length;
845
846 /* Copy the reply message to the request message buffer. */
847 if (IS_ERR(reply)) {
848 memcpy(msg->message, &error_reply, sizeof(error_reply));
849 goto out;
850 }
851 t86r = reply->message;
852 if (t86r->hdr.type == TYPE86_RSP_CODE &&
853 t86r->cprbx.cprb_ver_id == 0x04) {
854 switch (resp_type->type) {
855 case PCIXCC_RESPONSE_TYPE_EP11:
856 length = t86r->fmt2.offset1 + t86r->fmt2.count1;
857 length = min(MSGTYPE06_MAX_MSG_SIZE, length);
858 memcpy(msg->message, reply->message, length);
859 break;
860 default:
861 memcpy(msg->message, &error_reply, sizeof(error_reply));
862 }
863 } else {
864 memcpy(msg->message, reply->message, sizeof(error_reply));
865 }
866out:
867 complete(&(resp_type->work));
868}
869
Holger Dengler5e55a482012-08-28 16:45:36 +0200870static atomic_t zcrypt_step = ATOMIC_INIT(0);
871
872/**
873 * The request distributor calls this function if it picked the PCIXCC/CEX2C
874 * device to handle a modexpo request.
875 * @zdev: pointer to zcrypt_device structure that identifies the
876 * PCIXCC/CEX2C device to the request distributor
877 * @mex: pointer to the modexpo request buffer
878 */
879static long zcrypt_msgtype6_modexpo(struct zcrypt_device *zdev,
880 struct ica_rsa_modexpo *mex)
881{
882 struct ap_message ap_msg;
883 struct response_type resp_type = {
884 .type = PCIXCC_RESPONSE_TYPE_ICA,
885 };
886 int rc;
887
888 ap_init_message(&ap_msg);
889 ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
890 if (!ap_msg.message)
891 return -ENOMEM;
892 ap_msg.receive = zcrypt_msgtype6_receive;
893 ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
894 atomic_inc_return(&zcrypt_step);
895 ap_msg.private = &resp_type;
896 rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex);
897 if (rc)
898 goto out_free;
899 init_completion(&resp_type.work);
900 ap_queue_message(zdev->ap_dev, &ap_msg);
901 rc = wait_for_completion_interruptible(&resp_type.work);
902 if (rc == 0)
903 rc = convert_response_ica(zdev, &ap_msg, mex->outputdata,
904 mex->outputdatalength);
905 else
906 /* Signal pending. */
907 ap_cancel_message(zdev->ap_dev, &ap_msg);
908out_free:
909 free_page((unsigned long) ap_msg.message);
910 return rc;
911}
912
913/**
914 * The request distributor calls this function if it picked the PCIXCC/CEX2C
915 * device to handle a modexpo_crt request.
916 * @zdev: pointer to zcrypt_device structure that identifies the
917 * PCIXCC/CEX2C device to the request distributor
918 * @crt: pointer to the modexpoc_crt request buffer
919 */
920static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_device *zdev,
921 struct ica_rsa_modexpo_crt *crt)
922{
923 struct ap_message ap_msg;
924 struct response_type resp_type = {
925 .type = PCIXCC_RESPONSE_TYPE_ICA,
926 };
927 int rc;
928
929 ap_init_message(&ap_msg);
930 ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
931 if (!ap_msg.message)
932 return -ENOMEM;
933 ap_msg.receive = zcrypt_msgtype6_receive;
934 ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
935 atomic_inc_return(&zcrypt_step);
936 ap_msg.private = &resp_type;
937 rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt);
938 if (rc)
939 goto out_free;
940 init_completion(&resp_type.work);
941 ap_queue_message(zdev->ap_dev, &ap_msg);
942 rc = wait_for_completion_interruptible(&resp_type.work);
943 if (rc == 0)
944 rc = convert_response_ica(zdev, &ap_msg, crt->outputdata,
945 crt->outputdatalength);
946 else
947 /* Signal pending. */
948 ap_cancel_message(zdev->ap_dev, &ap_msg);
949out_free:
950 free_page((unsigned long) ap_msg.message);
951 return rc;
952}
953
954/**
955 * The request distributor calls this function if it picked the PCIXCC/CEX2C
956 * device to handle a send_cprb request.
957 * @zdev: pointer to zcrypt_device structure that identifies the
958 * PCIXCC/CEX2C device to the request distributor
959 * @xcRB: pointer to the send_cprb request buffer
960 */
961static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev,
962 struct ica_xcRB *xcRB)
963{
964 struct ap_message ap_msg;
965 struct response_type resp_type = {
966 .type = PCIXCC_RESPONSE_TYPE_XCRB,
967 };
968 int rc;
969
970 ap_init_message(&ap_msg);
971 ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
972 if (!ap_msg.message)
973 return -ENOMEM;
974 ap_msg.receive = zcrypt_msgtype6_receive;
975 ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
976 atomic_inc_return(&zcrypt_step);
977 ap_msg.private = &resp_type;
978 rc = XCRB_msg_to_type6CPRB_msgX(zdev, &ap_msg, xcRB);
979 if (rc)
980 goto out_free;
981 init_completion(&resp_type.work);
982 ap_queue_message(zdev->ap_dev, &ap_msg);
983 rc = wait_for_completion_interruptible(&resp_type.work);
984 if (rc == 0)
985 rc = convert_response_xcrb(zdev, &ap_msg, xcRB);
986 else
987 /* Signal pending. */
988 ap_cancel_message(zdev->ap_dev, &ap_msg);
989out_free:
990 kzfree(ap_msg.message);
991 return rc;
992}
993
994/**
Ingo Tuchscherer91f3e3e2013-11-20 10:47:13 +0100995 * The request distributor calls this function if it picked the CEX4P
996 * device to handle a send_ep11_cprb request.
997 * @zdev: pointer to zcrypt_device structure that identifies the
998 * CEX4P device to the request distributor
999 * @xcRB: pointer to the ep11 user request block
1000 */
1001static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev,
1002 struct ep11_urb *xcrb)
1003{
1004 struct ap_message ap_msg;
1005 struct response_type resp_type = {
1006 .type = PCIXCC_RESPONSE_TYPE_EP11,
1007 };
1008 int rc;
1009
1010 ap_init_message(&ap_msg);
1011 ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
1012 if (!ap_msg.message)
1013 return -ENOMEM;
1014 ap_msg.receive = zcrypt_msgtype6_receive_ep11;
1015 ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
1016 atomic_inc_return(&zcrypt_step);
1017 ap_msg.private = &resp_type;
1018 rc = xcrb_msg_to_type6_ep11cprb_msgx(zdev, &ap_msg, xcrb);
1019 if (rc)
1020 goto out_free;
1021 init_completion(&resp_type.work);
1022 ap_queue_message(zdev->ap_dev, &ap_msg);
1023 rc = wait_for_completion_interruptible(&resp_type.work);
1024 if (rc == 0)
1025 rc = convert_response_ep11_xcrb(zdev, &ap_msg, xcrb);
1026 else /* Signal pending. */
1027 ap_cancel_message(zdev->ap_dev, &ap_msg);
1028
1029out_free:
1030 kzfree(ap_msg.message);
1031 return rc;
1032}
1033
1034/**
Holger Dengler5e55a482012-08-28 16:45:36 +02001035 * The request distributor calls this function if it picked the PCIXCC/CEX2C
1036 * device to generate random data.
1037 * @zdev: pointer to zcrypt_device structure that identifies the
1038 * PCIXCC/CEX2C device to the request distributor
1039 * @buffer: pointer to a memory page to return random data
1040 */
1041
1042static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev,
1043 char *buffer)
1044{
1045 struct ap_message ap_msg;
1046 struct response_type resp_type = {
1047 .type = PCIXCC_RESPONSE_TYPE_XCRB,
1048 };
1049 int rc;
1050
1051 ap_init_message(&ap_msg);
1052 ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
1053 if (!ap_msg.message)
1054 return -ENOMEM;
1055 ap_msg.receive = zcrypt_msgtype6_receive;
1056 ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
1057 atomic_inc_return(&zcrypt_step);
1058 ap_msg.private = &resp_type;
1059 rng_type6CPRB_msgX(zdev->ap_dev, &ap_msg, ZCRYPT_RNG_BUFFER_SIZE);
1060 init_completion(&resp_type.work);
1061 ap_queue_message(zdev->ap_dev, &ap_msg);
1062 rc = wait_for_completion_interruptible(&resp_type.work);
1063 if (rc == 0)
1064 rc = convert_response_rng(zdev, &ap_msg, buffer);
1065 else
1066 /* Signal pending. */
1067 ap_cancel_message(zdev->ap_dev, &ap_msg);
1068 kfree(ap_msg.message);
1069 return rc;
1070}
1071
1072/**
1073 * The crypto operations for a PCIXCC/CEX2C card.
1074 */
1075static struct zcrypt_ops zcrypt_msgtype6_norng_ops = {
1076 .owner = THIS_MODULE,
1077 .variant = MSGTYPE06_VARIANT_NORNG,
1078 .rsa_modexpo = zcrypt_msgtype6_modexpo,
1079 .rsa_modexpo_crt = zcrypt_msgtype6_modexpo_crt,
1080 .send_cprb = zcrypt_msgtype6_send_cprb,
1081};
1082
1083static struct zcrypt_ops zcrypt_msgtype6_ops = {
1084 .owner = THIS_MODULE,
1085 .variant = MSGTYPE06_VARIANT_DEFAULT,
1086 .rsa_modexpo = zcrypt_msgtype6_modexpo,
1087 .rsa_modexpo_crt = zcrypt_msgtype6_modexpo_crt,
1088 .send_cprb = zcrypt_msgtype6_send_cprb,
1089 .rng = zcrypt_msgtype6_rng,
1090};
1091
Ingo Tuchscherer91f3e3e2013-11-20 10:47:13 +01001092static struct zcrypt_ops zcrypt_msgtype6_ep11_ops = {
1093 .owner = THIS_MODULE,
1094 .variant = MSGTYPE06_VARIANT_EP11,
1095 .rsa_modexpo = NULL,
1096 .rsa_modexpo_crt = NULL,
1097 .send_ep11_cprb = zcrypt_msgtype6_send_ep11_cprb,
1098};
1099
Holger Dengler5e55a482012-08-28 16:45:36 +02001100int __init zcrypt_msgtype6_init(void)
1101{
1102 zcrypt_msgtype_register(&zcrypt_msgtype6_norng_ops);
1103 zcrypt_msgtype_register(&zcrypt_msgtype6_ops);
Ingo Tuchscherer91f3e3e2013-11-20 10:47:13 +01001104 zcrypt_msgtype_register(&zcrypt_msgtype6_ep11_ops);
Holger Dengler5e55a482012-08-28 16:45:36 +02001105 return 0;
1106}
1107
1108void __exit zcrypt_msgtype6_exit(void)
1109{
1110 zcrypt_msgtype_unregister(&zcrypt_msgtype6_norng_ops);
1111 zcrypt_msgtype_unregister(&zcrypt_msgtype6_ops);
Ingo Tuchscherer91f3e3e2013-11-20 10:47:13 +01001112 zcrypt_msgtype_unregister(&zcrypt_msgtype6_ep11_ops);
Holger Dengler5e55a482012-08-28 16:45:36 +02001113}
1114
1115module_init(zcrypt_msgtype6_init);
1116module_exit(zcrypt_msgtype6_exit);