2
* iSCSI digest handling.
3
* (C) 2004 - 2006 Xiranet Communications GmbH <arne.redlich@xiranet.com>
4
* This code is licensed under the GPL.
7
#include <linux/types.h>
11
#include "iscsi_dbg.h"
13
void digest_alg_available(unsigned int *val)
15
if (*val & DIGEST_CRC32C &&
16
!crypto_has_alg("crc32c", 0, CRYPTO_ALG_ASYNC)) {
17
printk("CRC32C digest algorithm not available in kernel\n");
18
*val |= ~DIGEST_CRC32C;
23
* initialize support for digest calculation.
26
* @conn: ptr to connection to make use of digests
28
* @return: 0 on success, < 0 on error
30
int digest_init(struct iscsi_conn *conn)
34
if (!(conn->hdigest_type & DIGEST_ALL))
35
conn->hdigest_type = DIGEST_NONE;
37
if (!(conn->ddigest_type & DIGEST_ALL))
38
conn->ddigest_type = DIGEST_NONE;
40
if (conn->hdigest_type & DIGEST_CRC32C ||
41
conn->ddigest_type & DIGEST_CRC32C) {
42
conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
44
conn->rx_hash.flags = 0;
45
if (IS_ERR(conn->rx_hash.tfm)) {
46
conn->rx_hash.tfm = NULL;
51
conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
53
conn->tx_hash.flags = 0;
54
if (IS_ERR(conn->tx_hash.tfm)) {
55
conn->tx_hash.tfm = NULL;
69
* free resources used for digest calculation.
72
* @conn: ptr to connection that made use of digests
74
void digest_cleanup(struct iscsi_conn *conn)
76
if (conn->tx_hash.tfm)
77
crypto_free_hash(conn->tx_hash.tfm);
78
if (conn->rx_hash.tfm)
79
crypto_free_hash(conn->rx_hash.tfm);
83
* debug handling of header digest errors:
84
* simulates a digest error after n PDUs / every n-th PDU of type
85
* HDIGEST_ERR_CORRUPT_PDU_TYPE.
87
static inline void __dbg_simulate_header_digest_error(struct iscsi_cmnd *cmnd)
89
#define HDIGEST_ERR_AFTER_N_CMNDS 1000
90
#define HDIGEST_ERR_ONLY_ONCE 1
91
#define HDIGEST_ERR_CORRUPT_PDU_TYPE ISCSI_OP_SCSI_CMD
92
#define HDIGEST_ERR_CORRUPT_PDU_WITH_DATA_ONLY 0
94
static int num_cmnds = 0;
95
static int num_errs = 0;
97
if (cmnd_opcode(cmnd) == HDIGEST_ERR_CORRUPT_PDU_TYPE) {
98
if (HDIGEST_ERR_CORRUPT_PDU_WITH_DATA_ONLY) {
99
if (cmnd->pdu.datasize)
105
if ((num_cmnds == HDIGEST_ERR_AFTER_N_CMNDS)
106
&& (!(HDIGEST_ERR_ONLY_ONCE && num_errs))) {
107
printk("*** Faking header digest error ***\n");
108
printk("\tcmnd: 0x%x, itt 0x%x, sn 0x%x\n",
110
be32_to_cpu(cmnd->pdu.bhs.itt),
111
be32_to_cpu(cmnd->pdu.bhs.sn));
112
cmnd->hdigest = ~cmnd->hdigest;
113
/* make things even worse by manipulating header fields */
114
cmnd->pdu.datasize += 8;
122
* debug handling of data digest errors:
123
* simulates a digest error after n PDUs / every n-th PDU of type
124
* DDIGEST_ERR_CORRUPT_PDU_TYPE.
126
static inline void __dbg_simulate_data_digest_error(struct iscsi_cmnd *cmnd)
128
#define DDIGEST_ERR_AFTER_N_CMNDS 50
129
#define DDIGEST_ERR_ONLY_ONCE 1
130
#define DDIGEST_ERR_CORRUPT_PDU_TYPE ISCSI_OP_SCSI_DATA_OUT
131
#define DDIGEST_ERR_CORRUPT_UNSOL_DATA_ONLY 0
133
static int num_cmnds = 0;
134
static int num_errs = 0;
136
if ((cmnd->pdu.datasize)
137
&& (cmnd_opcode(cmnd) == DDIGEST_ERR_CORRUPT_PDU_TYPE)) {
138
switch (cmnd_opcode(cmnd)) {
139
case ISCSI_OP_SCSI_DATA_OUT:
140
if ((DDIGEST_ERR_CORRUPT_UNSOL_DATA_ONLY)
141
&& (cmnd->pdu.bhs.ttt != ISCSI_RESERVED_TAG))
148
if ((num_cmnds == DDIGEST_ERR_AFTER_N_CMNDS)
149
&& (!(DDIGEST_ERR_ONLY_ONCE && num_errs))
150
&& (cmnd->pdu.datasize)
151
&& (!cmnd->conn->read_overflow)) {
152
printk("*** Faking data digest error: ***");
153
printk("\tcmnd 0x%x, itt 0x%x, sn 0x%x\n",
155
be32_to_cpu(cmnd->pdu.bhs.itt),
156
be32_to_cpu(cmnd->pdu.bhs.sn));
157
cmnd->ddigest = ~cmnd->ddigest;
163
static void digest_header(struct hash_desc *hash, struct iscsi_pdu *pdu,
166
struct scatterlist sg[2];
167
unsigned int nbytes = sizeof(struct iscsi_hdr);
169
sg_init_table(sg, pdu->ahssize ? 2 : 1);
171
sg_set_buf(&sg[0], &pdu->bhs, nbytes);
173
sg_set_buf(&sg[1], pdu->ahs, pdu->ahssize);
174
nbytes += pdu->ahssize;
177
crypto_hash_init(hash);
178
crypto_hash_update(hash, sg, nbytes);
179
crypto_hash_final(hash, crc);
182
int digest_rx_header(struct iscsi_cmnd *cmnd)
186
digest_header(&cmnd->conn->rx_hash, &cmnd->pdu, (u8 *) &crc);
187
if (crc != cmnd->hdigest)
193
void digest_tx_header(struct iscsi_cmnd *cmnd)
195
digest_header(&cmnd->conn->tx_hash, &cmnd->pdu, (u8 *) &cmnd->hdigest);
198
static void digest_data(struct hash_desc *hash, struct iscsi_cmnd *cmnd,
199
struct tio *tio, u32 offset, u8 *crc)
201
struct scatterlist *sg = cmnd->conn->hash_sg;
206
size = cmnd->pdu.datasize;
207
nbytes = size = (size + 3) & ~3;
209
offset += tio->offset;
210
idx = offset >> PAGE_CACHE_SHIFT;
211
offset &= ~PAGE_CACHE_MASK;
212
count = get_pgcnt(size, offset);
213
assert(idx + count <= tio->pg_cnt);
215
assert(count <= ISCSI_CONN_IOV_MAX);
217
sg_init_table(sg, ARRAY_SIZE(cmnd->conn->hash_sg));
218
crypto_hash_init(hash);
220
for (i = 0; size; i++) {
221
if (offset + size > PAGE_CACHE_SIZE)
222
length = PAGE_CACHE_SIZE - offset;
226
sg_set_page(&sg[i], tio->pvec[idx + i], length, offset);
231
sg_mark_end(&sg[i - 1]);
233
crypto_hash_update(hash, sg, nbytes);
234
crypto_hash_final(hash, crc);
237
int digest_rx_data(struct iscsi_cmnd *cmnd)
240
struct iscsi_cmnd *scsi_cmnd;
241
struct iscsi_data_out_hdr *req;
244
switch (cmnd_opcode(cmnd)) {
245
case ISCSI_OP_SCSI_REJECT:
246
case ISCSI_OP_PDU_REJECT:
247
case ISCSI_OP_DATA_REJECT:
249
case ISCSI_OP_SCSI_DATA_OUT:
250
scsi_cmnd = cmnd->req;
251
req = (struct iscsi_data_out_hdr *) &cmnd->pdu.bhs;
252
tio = scsi_cmnd->tio;
253
offset = be32_to_cpu(req->buffer_offset);
260
digest_data(&cmnd->conn->rx_hash, cmnd, tio, offset, (u8 *) &crc);
262
if (!cmnd->conn->read_overflow &&
263
(cmnd_opcode(cmnd) != ISCSI_OP_PDU_REJECT)) {
264
if (crc != cmnd->ddigest)
271
void digest_tx_data(struct iscsi_cmnd *cmnd)
273
struct tio *tio = cmnd->tio;
274
struct iscsi_data_out_hdr *req = (struct iscsi_data_out_hdr *)&cmnd->pdu.bhs;
277
digest_data(&cmnd->conn->tx_hash, cmnd, tio,
278
be32_to_cpu(req->buffer_offset), (u8 *) &cmnd->ddigest);