--- /dev/null
+From d3dde52209ab571e4e2ec26c66f85ad1355f7475 Mon Sep 17 00:00:00 2001
+From: Jussi Kivilinna <jussi.kivilinna@iki.fi>
+Date: Thu, 28 Mar 2013 21:54:03 +0200
+Subject: crypto: gcm - fix assumption that assoc has one segment
+
+From: Jussi Kivilinna <jussi.kivilinna@iki.fi>
+
+commit d3dde52209ab571e4e2ec26c66f85ad1355f7475 upstream.
+
+rfc4543(gcm(*)) code for GMAC assumes that assoc scatterlist always contains
+only one segment and only makes use of this first segment. However ipsec passes
+assoc with three segments when using 'extended sequence number' thus in this
+case rfc4543(gcm(*)) fails to function correctly. Patch fixes this issue.
+
+Reported-by: Chaoxing Lin <Chaoxing.Lin@ultra-3eti.com>
+Tested-by: Chaoxing Lin <Chaoxing.Lin@ultra-3eti.com>
+Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ crypto/gcm.c | 17 ++++++++++++++---
+ 1 file changed, 14 insertions(+), 3 deletions(-)
+
+--- a/crypto/gcm.c
++++ b/crypto/gcm.c
+@@ -44,6 +44,7 @@ struct crypto_rfc4543_ctx {
+
+ struct crypto_rfc4543_req_ctx {
+ u8 auth_tag[16];
++ u8 assocbuf[32];
+ struct scatterlist cipher[1];
+ struct scatterlist payload[2];
+ struct scatterlist assoc[2];
+@@ -1142,9 +1143,19 @@ static struct aead_request *crypto_rfc45
+ scatterwalk_crypto_chain(payload, dst, vdst == req->iv + 8, 2);
+ assoclen += 8 + req->cryptlen - (enc ? 0 : authsize);
+
+- sg_init_table(assoc, 2);
+- sg_set_page(assoc, sg_page(req->assoc), req->assoc->length,
+- req->assoc->offset);
++ if (req->assoc->length == req->assoclen) {
++ sg_init_table(assoc, 2);
++ sg_set_page(assoc, sg_page(req->assoc), req->assoc->length,
++ req->assoc->offset);
++ } else {
++ BUG_ON(req->assoclen > sizeof(rctx->assocbuf));
++
++ scatterwalk_map_and_copy(rctx->assocbuf, req->assoc, 0,
++ req->assoclen, 0);
++
++ sg_init_table(assoc, 2);
++ sg_set_buf(assoc, rctx->assocbuf, req->assoclen);
++ }
+ scatterwalk_crypto_chain(assoc, payload, 0, 2);
+
+ aead_request_set_tfm(subreq, ctx->child);