ip: xfrm: Add AEAD support

This patch allows the user to create/manage AEAD algorithms with
the ip xfrm command.  AEAD algorithms are also known as combined-
mode algorithms.  They provide the functionality of encryption
algorithms as well as authentication algorithms.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
diff --git a/ip/ipxfrm.c b/ip/ipxfrm.c
index 80dbb52..0a7d39a 100644
--- a/ip/ipxfrm.c
+++ b/ip/ipxfrm.c
@@ -154,7 +154,8 @@
 
 static const struct typeent algo_types[]= {
 	{ "enc", XFRMA_ALG_CRYPT }, { "auth", XFRMA_ALG_AUTH },
-	{ "comp", XFRMA_ALG_COMP }, { NULL, -1 }
+	{ "comp", XFRMA_ALG_COMP }, { "aead", XFRMA_ALG_AEAD },
+	{ NULL, -1 }
 };
 
 int xfrm_algotype_getbyname(char *name)
@@ -525,8 +526,8 @@
 	fprintf(fp, "%s", _SL_);
 }
 
-static void xfrm_algo_print(struct xfrm_algo *algo, int type, int len,
-			    FILE *fp, const char *prefix)
+static void __xfrm_algo_print(struct xfrm_algo *algo, int type, int len,
+			      FILE *fp, const char *prefix, int newline)
 {
 	int keylen;
 	int i;
@@ -558,6 +559,32 @@
 		fprintf(fp, " (%d bits)", algo->alg_key_len);
 
  fin:
+	if (newline)
+		fprintf(fp, "%s", _SL_);
+}
+
+static inline void xfrm_algo_print(struct xfrm_algo *algo, int type, int len,
+				   FILE *fp, const char *prefix)
+{
+	return __xfrm_algo_print(algo, type, len, fp, prefix, 1);
+}
+
+static void xfrm_aead_print(struct xfrm_algo_aead *algo, int len,
+			    FILE *fp, const char *prefix)
+{
+	struct {
+		struct xfrm_algo algo;
+		char key[algo->alg_key_len / 8];
+	} base;
+
+	memcpy(base.algo.alg_name, algo->alg_name, sizeof(base.algo.alg_name));
+	base.algo.alg_key_len = algo->alg_key_len;
+	memcpy(base.algo.alg_key, algo->alg_key, algo->alg_key_len / 8);
+
+	__xfrm_algo_print(&base.algo, XFRMA_ALG_AEAD, len, fp, prefix, 0);
+
+	fprintf(fp, " %d", algo->alg_icv_len);
+
 	fprintf(fp, "%s", _SL_);
 }
 
@@ -635,6 +662,12 @@
 				XFRMA_ALG_AUTH, RTA_PAYLOAD(rta), fp, prefix);
 	}
 
+	if (tb[XFRMA_ALG_AEAD]) {
+		struct rtattr *rta = tb[XFRMA_ALG_AEAD];
+		xfrm_aead_print((struct xfrm_algo_aead *)RTA_DATA(rta),
+				RTA_PAYLOAD(rta), fp, prefix);
+	}
+
 	if (tb[XFRMA_ALG_CRYPT]) {
 		struct rtattr *rta = tb[XFRMA_ALG_CRYPT];
 		xfrm_algo_print((struct xfrm_algo *) RTA_DATA(rta),