*/
 
 #include <crypto/internal/aead.h>
+#include <crypto/scatterwalk.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 }
 EXPORT_SYMBOL_GPL(crypto_aead_setauthsize);
 
+struct aead_old_request {
+       struct scatterlist srcbuf[2];
+       struct scatterlist dstbuf[2];
+       struct aead_request subreq;
+};
+
+unsigned int crypto_aead_reqsize(struct crypto_aead *tfm)
+{
+       return tfm->reqsize + sizeof(struct aead_old_request);
+}
+EXPORT_SYMBOL_GPL(crypto_aead_reqsize);
+
+static int old_crypt(struct aead_request *req,
+                    int (*crypt)(struct aead_request *req))
+{
+       struct aead_old_request *nreq = aead_request_ctx(req);
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       struct scatterlist *src, *dst;
+
+       if (req->old)
+               return crypt(req);
+
+       src = scatterwalk_ffwd(nreq->srcbuf, req->src,
+                              req->assoclen + req->cryptoff);
+       dst = scatterwalk_ffwd(nreq->dstbuf, req->dst,
+                              req->assoclen + req->cryptoff);
+
+       aead_request_set_tfm(&nreq->subreq, aead);
+       aead_request_set_callback(&nreq->subreq, aead_request_flags(req),
+                                 req->base.complete, req->base.data);
+       aead_request_set_crypt(&nreq->subreq, src, dst, req->cryptlen,
+                              req->iv);
+       aead_request_set_assoc(&nreq->subreq, req->src, req->assoclen);
+
+       return crypt(&nreq->subreq);
+}
+
+static int old_encrypt(struct aead_request *req)
+{
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       struct aead_alg *alg = crypto_aead_alg(aead);
+
+       return old_crypt(req, alg->encrypt);
+}
+
+static int old_decrypt(struct aead_request *req)
+{
+       struct crypto_aead *aead = crypto_aead_reqtfm(req);
+       struct aead_alg *alg = crypto_aead_alg(aead);
+
+       return old_crypt(req, alg->decrypt);
+}
+
 static int no_givcrypt(struct aead_givcrypt_request *req)
 {
        return -ENOSYS;
        if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8)
                return -EINVAL;
 
-       crt->encrypt = alg->encrypt;
-       crt->decrypt = alg->decrypt;
+       crt->encrypt = old_encrypt;
+       crt->decrypt = old_decrypt;
        if (alg->ivsize) {
                crt->givencrypt = alg->givencrypt ?: no_givcrypt;
                crt->givdecrypt = alg->givdecrypt ?: no_givcrypt;
 
  *     @base: Common attributes for async crypto requests
  *     @assoclen: Length in bytes of associated data for authentication
  *     @cryptlen: Length of data to be encrypted or decrypted
+ *     @cryptoff: Bytes to skip after AD before plain/cipher text
  *     @iv: Initialisation vector
  *     @assoc: Associated data
  *     @src: Source data
 struct aead_request {
        struct crypto_async_request base;
 
+       bool old;
+
        unsigned int assoclen;
        unsigned int cryptlen;
+       unsigned int cryptoff;
 
        u8 *iv;
 
  *
  * Return: number of bytes
  */
-static inline unsigned int crypto_aead_reqsize(struct crypto_aead *tfm)
-{
-       return tfm->reqsize;
-}
+unsigned int crypto_aead_reqsize(struct crypto_aead *tfm);
 
 /**
  * aead_request_set_tfm() - update cipher handle reference in request
  * destination is the ciphertext. For a decryption operation, the use is
  * reversed - the source is the ciphertext and the destination is the plaintext.
  *
+ * For both src/dst the layout is associated data, skipped data,
+ * plain/cipher text, authentication tag.
+ *
  * IMPORTANT NOTE AEAD requires an authentication tag (MAC). For decryption,
  *               the caller must concatenate the ciphertext followed by the
  *               authentication tag and provide the entire data stream to the
  * @assoc: associated data scatter / gather list
  * @assoclen: number of bytes to process from @assoc
  *
- * For encryption, the memory is filled with the associated data. For
- * decryption, the memory must point to the associated data.
+ * Obsolete, do not use.
  */
 static inline void aead_request_set_assoc(struct aead_request *req,
                                          struct scatterlist *assoc,
 {
        req->assoc = assoc;
        req->assoclen = assoclen;
+       req->old = true;
+}
+
+/**
+ * aead_request_set_ad - set associated data information
+ * @req: request handle
+ * @assoclen: number of bytes in associated data
+ * @cryptoff: Number of bytes to skip after AD before plain/cipher text
+ *
+ * Setting the AD information.  This function sets the length of
+ * the associated data and the number of bytes to skip after it to
+ * access the plain/cipher text.
+ */
+static inline void aead_request_set_ad(struct aead_request *req,
+                                      unsigned int assoclen,
+                                      unsigned int cryptoff)
+{
+       req->assoclen = assoclen;
+       req->cryptoff = cryptoff;
+       req->old = false;
 }
 
 static inline struct crypto_aead *aead_givcrypt_reqtfm(