Split out the IV generation function so that we can add other ones in the
future. The cryptoloop compatible one is too predictable.

The -cbc cipher suffix is therefore changed to -plain.

[Christophe Saout]
--- diff/drivers/md/dm-crypt.c	2004-01-03 12:14:25.000000000 +0000
+++ source/drivers/md/dm-crypt.c	2004-01-03 12:14:31.000000000 +0000
@@ -62,6 +62,7 @@
 	 */
 	struct crypto_tfm *tfm;
 	sector_t iv_offset;
+	int (*iv_generator)(struct crypt_config *cc, u8 *iv, sector_t sector);
 	int iv_size;
 	int key_size;
 	u8 key[0];
@@ -86,6 +87,20 @@
 	__free_page(page);
 }
 
+
+/*
+ * Different IV generation algorithms
+ */
+static int crypt_iv_plain(struct crypt_config *cc, u8 *iv, sector_t sector)
+{
+	*(u32 *)iv = cpu_to_le32(sector & 0xffffffff);
+	if (cc->iv_size > sizeof(u32) / sizeof(u8))
+		memset(iv + (sizeof(u32) / sizeof(u8)), 0,
+		       cc->iv_size - (sizeof(u32) / sizeof(u8)));
+
+	return 0;
+}
+
 /*
  * Encrypt / decrypt a single sector, source and destination buffers
  * are stored in scatterlists. In CBC mode initialise the "previous
@@ -100,11 +115,10 @@
 	u8 iv[cc->iv_size];
 	int r;
 
-	if (cc->iv_size) {
-		*(u32 *)iv = cpu_to_le32(sector & 0xffffffff);
-		if (cc->iv_size > sizeof(u32) / sizeof(u8))
-			memset(iv + (sizeof(u32) / sizeof(u8)), 0,
-			       cc->iv_size - (sizeof(u32) / sizeof(u8)));
+	if (cc->iv_generator) {
+		r = cc->iv_generator(cc, iv, sector);
+		if (r < 0)
+			return r;
 
 		if (write)
 			r = crypto_cipher_encrypt_iv(cc->tfm, out, in, length, iv);
@@ -428,7 +442,6 @@
 	char *cipher;
 	char *mode;
 	int crypto_flags;
-	int iv_size;
 	int key_size;
 
 	if (argc != 5) {
@@ -443,88 +456,99 @@
 	if (tmp)
 		DMWARN("dm-crypt: Unexpected additional cipher options");
 
-	if (!mode || strcmp(mode, "cbc") == 0)
-		crypto_flags = CRYPTO_TFM_MODE_CBC;
+	key_size = strlen(argv[1]) >> 1;
+
+	cc = kmalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
+	if (cc == NULL) {
+		ti->error =
+			"dm-crypt: Cannot allocate transparent encryption context";
+		return -ENOMEM;
+	}
+
+	if (!mode || strcmp(mode, "plain") == 0)
+		cc->iv_generator = crypt_iv_plain;
 	else if (strcmp(mode, "ecb") == 0)
-		crypto_flags = CRYPTO_TFM_MODE_ECB;
+		cc->iv_generator = NULL;
 	else {
 		ti->error = "dm-crypt: Invalid chaining mode";
 		return -EINVAL;
 	}
 
+	if (cc->iv_generator)
+		crypto_flags = CRYPTO_TFM_MODE_CBC;
+	else
+		crypto_flags = CRYPTO_TFM_MODE_ECB;
+
 	tfm = crypto_alloc_tfm(cipher, crypto_flags);
 	if (!tfm) {
 		ti->error = "dm-crypt: Error allocating crypto tfm";
-		return -EINVAL;
+		goto bad1;
 	}
 
-	key_size = strlen(argv[1]) >> 1;
 	if (tfm->crt_u.cipher.cit_decrypt_iv && tfm->crt_u.cipher.cit_encrypt_iv)
-		iv_size = max(crypto_tfm_alg_ivsize(tfm), sizeof(u32) / sizeof(u8));
-	else
-		iv_size = 0;
-
-	cc = kmalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
-	if (cc == NULL) {
-		ti->error =
-			"dm-crypt: Cannot allocate transparent encryption context";
-		crypto_free_tfm(tfm);
-		return -ENOMEM;
+		/* at least a 32 bit sector number should fit in our buffer */
+		cc->iv_size = max(crypto_tfm_alg_ivsize(tfm), sizeof(u32) / sizeof(u8));
+	else {
+		cc->iv_size = 0;
+		if (cc->iv_generator) {
+			DMWARN("dm-crypt: Selected cipher does not support IVs");
+			cc->iv_generator = NULL;
+		}
 	}
 
 	cc->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
 				     mempool_free_slab, _crypt_io_pool);
 	if (!cc->io_pool) {
 		ti->error = "dm-crypt: Cannot allocate crypt io mempool";
-		goto bad1;
+		goto bad2;
 	}
 
 	cc->page_pool = mempool_create(MIN_POOL_PAGES, mempool_alloc_page,
 				       mempool_free_page, NULL);
 	if (!cc->page_pool) {
 		ti->error = "dm-crypt: Cannot allocate page mempool";
-		goto bad2;
+		goto bad3;
 	}
 
 	cc->tfm = tfm;
-	cc->iv_size = iv_size;
 	cc->key_size = key_size;
 	if ((key_size == 0 && strcmp(argv[1], "-") != 0)
 	    || crypt_decode_key(cc->key, argv[1], key_size) < 0) {
 		ti->error = "dm-crypt: Error decoding key";
-		goto bad3;
+		goto bad4;
 	}
 
 	if (tfm->crt_u.cipher.cit_setkey(tfm, cc->key, key_size) < 0) {
 		ti->error = "dm-crypt: Error setting key";
-		goto bad3;
+		goto bad4;
 	}
 
 	if (sscanf(argv[2], SECTOR_FORMAT, &cc->iv_offset) != 1) {
 		ti->error = "dm-crypt: Invalid iv_offset sector";
-		goto bad3;
+		goto bad4;
 	}
 
 	if (sscanf(argv[4], SECTOR_FORMAT, &cc->start) != 1) {
 		ti->error = "dm-crypt: Invalid device sector";
-		goto bad3;
+		goto bad4;
 	}
 
 	if (dm_get_device(ti, argv[3], cc->start, ti->len,
 	                  dm_table_get_mode(ti->table), &cc->dev)) {
 		ti->error = "dm-crypt: Device lookup failed";
-		goto bad3;
+		goto bad4;
 	}
 
 	ti->private = cc;
 	return 0;
 
-bad3:
+bad4:
 	mempool_destroy(cc->page_pool);
-bad2:
+bad3:
 	mempool_destroy(cc->io_pool);
-bad1:
+bad2:
 	crypto_free_tfm(tfm);
+bad1:
 	kfree(cc);
 	return -EINVAL;
 }
