rngd_rdrand: Code style cleanups

Break up the code into smaller functions for readability, make the
code conform a little closer to Linux standard, and try to reduce the
number of #ifdefs.

Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
diff --git a/rngd_rdrand.c b/rngd_rdrand.c
index 8d469b9..9a20d7d 100644
--- a/rngd_rdrand.c
+++ b/rngd_rdrand.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Intel Corporation
+ * Copyright (c) 2012-2014, Intel Corporation
  * Authors: Richard B. Hill <richard.b.hill@intel.com>,
  *          H. Peter Anvin <hpa@linux.intel.com>,
  *          John P. Mechalas <john.p.mechalas@intel.com>
@@ -59,26 +59,32 @@
 extern void x86_aes_mangle(void *data, void *state);
 
 /* Checking eflags to confirm cpuid instruction available */
-/* Only necessary for 32 bit processors */
-#if defined (__i386__)
-static int x86_has_eflag(uint32_t flag)
+static inline int x86_has_eflag(unsigned long flag)
 {
-        uint32_t f0, f1;
-		asm("pushfl ; "
-            "pushfl ; "
-            "popl %0 ; "
-            "movl %0,%1 ; "
-            "xorl %2,%1 ; "
-            "pushl %1 ; "
-            "popfl ; "
-            "pushfl ; "
-            "popl %1 ; "
-            "popfl"
-            : "=&r" (f0), "=&r" (f1)
-            : "ri" (flag));
-        return !!((f0^f1) & flag);
+	unsigned long f0, f1;
+	asm("pushf ; "
+	    "pushf ; "
+	    "pop %0 ; "
+	    "mov %0,%1 ; "
+	    "xor %2,%1 ; "
+	    "push %1 ; "
+	    "popf ; "
+	    "pushf ; "
+	    "pop %1 ; "
+	    "popf"
+	    : "=&r" (f0), "=&r" (f1)
+	    : "ri" (flag));
+	return !!((f0^f1) & flag);
 }
+
+static inline int x86_has_cpuid(void)
+{
+#ifdef __i386__
+	return x86_has_eflag(1 << 21); /* ID flag */
+#else
+	return 1;		/* x86-64 always has CPUID */
 #endif
+}
 
 /* Calling cpuid instruction to verify rdrand and aes-ni capability */
 static void cpuid(unsigned int leaf, unsigned int subleaf, struct cpuid *out)
@@ -105,7 +111,7 @@
 #define CHUNK_SIZE		(16*8)
 
 static unsigned char iv_buf[CHUNK_SIZE] __attribute__((aligned(128)));
-static int have_aesni= 0;
+static int have_aesni;
 
 /* Necessary if we have RDRAND but not AES-NI */
 
@@ -115,15 +121,29 @@
 
 static gcry_cipher_hd_t gcry_cipher_hd;
 
-/* Arbitrary 128-bit AES key 0x00102030405060708090A0B0C0D0E0F0 */
-
-static const unsigned char key[16]= {
-	0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
-	0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0
-};
-
 #endif
 
+static inline int gcrypt_mangle(unsigned char *tmp)
+{
+#ifdef HAVE_LIBGCRYPT
+	gcry_error_t gcry_error;
+
+	/* Encrypt tmp in-place. */
+
+	gcry_error = gcry_cipher_encrypt(gcry_cipher_hd, tmp, CHUNK_SIZE,
+					 NULL, 0);
+
+	if (gcry_error) {
+		message(LOG_DAEMON|LOG_ERR,
+			"gcry_cipher_encrypt error: %s\n",
+			gcry_strerror(gcry_error));
+		return -1;
+	}
+	return 0;
+#else
+	return -1;
+#endif
+}
 
 int xread_drng(void *buf, size_t size, struct rng *ent_src)
 {
@@ -140,28 +160,14 @@
 				return -1;
 			}
 
-			// Use 128-bit AES in CBC mode to mangle our random data
-
-			if ( have_aesni ) x86_aes_mangle(tmp, iv_buf);
-			else {
-#ifdef HAVE_LIBGCRYPT
-				gcry_error_t gcry_error;
-
-				/* Encrypt tmp in-place. */
-
-				gcry_error= gcry_cipher_encrypt(gcry_cipher_hd,
-					tmp, CHUNK_SIZE, NULL, 0);
-
-				if ( gcry_error ) {
-					message(LOG_DAEMON|LOG_ERR,
-						"gcry_cipher_encrypt error: %s\n",
-						gcry_strerror(gcry_error));
-					return -1;
-				}
-#else
+			/*
+			 * Use 128-bit AES in CBC mode to reduce the
+			 * data by a factor of rdrand_round_count
+			 */
+			if (have_aesni)
+				x86_aes_mangle(tmp, iv_buf);
+			else if (gcrypt_mangle(tmp))
 				return -1;
-#endif
-			}
 		}
 		chunk = (sizeof(tmp) > size) ? size : sizeof(tmp);
 		memcpy(p, tmp, chunk);
@@ -172,6 +178,50 @@
 	return 0;
 }
 
+static int init_gcrypt(void)
+{
+#ifdef HAVE_LIBGCRYPT
+	/* Arbitrary 128-bit AES key 0x00102030405060708090A0B0C0D0E0F0 */
+	static const unsigned char key[16] = {
+		0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+		0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0
+	};
+	gcry_error_t gcry_error;
+
+	if (!gcry_check_version(MIN_GCRYPT_VERSION)) {
+		message(LOG_DAEMON|LOG_ERR,
+			"libgcrypt version mismatch: have %s, require >= %s\n",
+			gcry_check_version(NULL), MIN_GCRYPT_VERSION);
+		return 1;
+	}
+
+	gcry_error = gcry_cipher_open(&gcry_cipher_hd, GCRY_CIPHER_AES128,
+				      GCRY_CIPHER_MODE_CBC, 0);
+
+	if (!gcry_error)
+		gcry_error = gcry_cipher_setkey(gcry_cipher_hd, key, 16);
+
+	if (!gcry_error) {
+		/*
+		 * Only need the first 16 bytes of iv_buf. AES-NI can
+		 * encrypt multiple blocks in parallel but we can't.
+		 */
+		gcry_error = gcry_cipher_setiv(gcry_cipher_hd, iv_buf, 16);
+	}
+
+	if (gcry_error) {
+		message(LOG_DAEMON|LOG_ERR,
+			"could not set key or IV: %s\n",
+			gcry_strerror(gcry_error));
+		gcry_cipher_close(gcry_cipher_hd);
+		return 1;
+	}
+	return 0;
+#else
+	return 1;
+#endif
+}
+
 /*
  * Confirm RDRAND capabilities for drng entropy source
  */
@@ -180,65 +230,28 @@
 	struct cpuid info;
 	/* We need RDRAND, but AESni is optional */
 	const uint32_t features_ecx1_rdrand = 1 << 30;
-	const uint32_t features_ecx1_aesni = 1 << 25;
+	const uint32_t features_ecx1_aesni  = 1 << 25;
 
-#if defined(__i386__)
-	if (!x86_has_eflag(1 << 21))
+	if (!x86_has_cpuid())
 		return 1;	/* No CPUID instruction */
-#endif
 
 	cpuid(0, 0, &info);
 	if (info.eax < 1)
 		return 1;
 	cpuid(1, 0, &info);
-	if (! (info.ecx & features_ecx1_rdrand) )
+	if (!(info.ecx & features_ecx1_rdrand))
 		return 1;
 
-	have_aesni= (info.ecx & features_ecx1_aesni) ? 1 : 0;
-#ifndef HAVE_LIBGCRYPT
-	if ( ! have_aesni ) return 1;
-#endif
+	have_aesni = !!(info.ecx & features_ecx1_aesni);
+
+	/* Initialize the AES key */
 
 	/* Initialize the IV buffer */
 	if (!x86_rdrand_nlong(iv_buf, CHUNK_SIZE/sizeof(long)))
 		return 1;
 
-#ifdef HAVE_LIBGCRYPT
-	if ( ! have_aesni ) {
-		gcry_error_t gcry_error;
-
-		if (! gcry_check_version(MIN_GCRYPT_VERSION) ) {
-			message(LOG_DAEMON|LOG_ERR,
-				"libgcrypt version mismatch: have %s, require >= %s\n",
-				gcry_check_version(NULL), MIN_GCRYPT_VERSION);
-			return 1;
-		}
-
-		gcry_error= gcry_cipher_open(&gcry_cipher_hd,
-			GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, 0);
-
-		if ( ! gcry_error ) {
-			gcry_error= gcry_cipher_setkey(gcry_cipher_hd, key, 16);
-		}
-
-		if ( ! gcry_error ) {
-			/*
-			 * Only need the first 16 bytes of iv_buf. AES-NI can
-			 * encrypt multiple blocks in parallel but we can't.
-			 */
-
-			gcry_error= gcry_cipher_setiv(gcry_cipher_hd, iv_buf, 16);
-		}
-
-		if ( gcry_error ) {
-			message(LOG_DAEMON|LOG_ERR,
-				"could not set key or IV: %s\n",
-				gcry_strerror(gcry_error));
-			gcry_cipher_close(gcry_cipher_hd);
-			return 1;
-		}
-	}
-#endif
+	if (!have_aesni && init_gcrypt())
+		return 1;	/* We need one crypto or the other... */
 
 	src_list_add(ent_src);
 	/* Bootstrap FIPS tests */