#include <linux/tcp.h>
 #include <linux/rcupdate.h>
 #include <linux/rculist.h>
+#include <linux/siphash.h>
 #include <net/inetpeer.h>
 #include <net/tcp.h>
 
 {
        struct tcp_fastopen_context *ctx =
            container_of(head, struct tcp_fastopen_context, rcu);
-       int i;
 
-       /* We own ctx, thus no need to hold the Fastopen-lock */
-       for (i = 0; i < TCP_FASTOPEN_KEY_MAX; i++) {
-               if (ctx->tfm[i])
-                       crypto_free_cipher(ctx->tfm[i]);
-       }
-       kfree(ctx);
+       kzfree(ctx);
 }
 
 void tcp_fastopen_destroy_cipher(struct sock *sk)
                call_rcu(&ctxt->rcu, tcp_fastopen_ctx_free);
 }
 
-static struct tcp_fastopen_context *tcp_fastopen_alloc_ctx(void *primary_key,
-                                                          void *backup_key,
-                                                          unsigned int len)
-{
-       struct tcp_fastopen_context *new_ctx;
-       void *key = primary_key;
-       int err, i;
-
-       new_ctx = kmalloc(sizeof(*new_ctx), GFP_KERNEL);
-       if (!new_ctx)
-               return ERR_PTR(-ENOMEM);
-       for (i = 0; i < TCP_FASTOPEN_KEY_MAX; i++)
-               new_ctx->tfm[i] = NULL;
-       for (i = 0; i < (backup_key ? 2 : 1); i++) {
-               new_ctx->tfm[i] = crypto_alloc_cipher("aes", 0, 0);
-               if (IS_ERR(new_ctx->tfm[i])) {
-                       err = PTR_ERR(new_ctx->tfm[i]);
-                       new_ctx->tfm[i] = NULL;
-                       pr_err("TCP: TFO aes cipher alloc error: %d\n", err);
-                       goto out;
-               }
-               err = crypto_cipher_setkey(new_ctx->tfm[i], key, len);
-               if (err) {
-                       pr_err("TCP: TFO cipher key error: %d\n", err);
-                       goto out;
-               }
-               memcpy(&new_ctx->key[i * TCP_FASTOPEN_KEY_LENGTH], key, len);
-               key = backup_key;
-       }
-       return new_ctx;
-out:
-       tcp_fastopen_ctx_free(&new_ctx->rcu);
-       return ERR_PTR(err);
-}
-
 int tcp_fastopen_reset_cipher(struct net *net, struct sock *sk,
                              void *primary_key, void *backup_key,
                              unsigned int len)
        struct fastopen_queue *q;
        int err = 0;
 
-       ctx = tcp_fastopen_alloc_ctx(primary_key, backup_key, len);
-       if (IS_ERR(ctx)) {
-               err = PTR_ERR(ctx);
+       ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx) {
+               err = -ENOMEM;
                goto out;
        }
+
+       memcpy(ctx->key[0], primary_key, len);
+       if (backup_key) {
+               memcpy(ctx->key[1], backup_key, len);
+               ctx->num = 2;
+       } else {
+               ctx->num = 1;
+       }
+
        spin_lock(&net->ipv4.tcp_fastopen_ctx_lock);
        if (sk) {
                q = &inet_csk(sk)->icsk_accept_queue.fastopenq;
 
 static bool __tcp_fastopen_cookie_gen_cipher(struct request_sock *req,
                                             struct sk_buff *syn,
-                                            struct crypto_cipher *tfm,
+                                            const u8 *key,
                                             struct tcp_fastopen_cookie *foc)
 {
+       BUILD_BUG_ON(TCP_FASTOPEN_KEY_LENGTH != sizeof(siphash_key_t));
+       BUILD_BUG_ON(TCP_FASTOPEN_COOKIE_SIZE != sizeof(u64));
+
        if (req->rsk_ops->family == AF_INET) {
                const struct iphdr *iph = ip_hdr(syn);
-               __be32 path[4] = { iph->saddr, iph->daddr, 0, 0 };
 
-               crypto_cipher_encrypt_one(tfm, foc->val, (void *)path);
+               foc->val[0] = siphash(&iph->saddr,
+                                     sizeof(iph->saddr) +
+                                     sizeof(iph->daddr),
+                                     (const siphash_key_t *)key);
                foc->len = TCP_FASTOPEN_COOKIE_SIZE;
                return true;
        }
-
 #if IS_ENABLED(CONFIG_IPV6)
        if (req->rsk_ops->family == AF_INET6) {
                const struct ipv6hdr *ip6h = ipv6_hdr(syn);
-               struct tcp_fastopen_cookie tmp;
-               struct in6_addr *buf;
-               int i;
-
-               crypto_cipher_encrypt_one(tfm, tmp.val,
-                                         (void *)&ip6h->saddr);
-               buf = &tmp.addr;
-               for (i = 0; i < 4; i++)
-                       buf->s6_addr32[i] ^= ip6h->daddr.s6_addr32[i];
-               crypto_cipher_encrypt_one(tfm, foc->val, (void *)buf);
+
+               foc->val[0] = siphash(&ip6h->saddr,
+                                     sizeof(ip6h->saddr) +
+                                     sizeof(ip6h->daddr),
+                                     (const siphash_key_t *)key);
                foc->len = TCP_FASTOPEN_COOKIE_SIZE;
                return true;
        }
        return false;
 }
 
-/* Generate the fastopen cookie by doing aes128 encryption on both
- * the source and destination addresses. Pad 0s for IPv4 or IPv4-mapped-IPv6
- * addresses. For the longer IPv6 addresses use CBC-MAC.
- *
- * XXX (TFO) - refactor when TCP_FASTOPEN_COOKIE_SIZE != AES_BLOCK_SIZE.
+/* Generate the fastopen cookie by applying SipHash to both the source and
+ * destination addresses.
  */
 static void tcp_fastopen_cookie_gen(struct sock *sk,
                                    struct request_sock *req,
        rcu_read_lock();
        ctx = tcp_fastopen_get_ctx(sk);
        if (ctx)
-               __tcp_fastopen_cookie_gen_cipher(req, syn, ctx->tfm[0], foc);
+               __tcp_fastopen_cookie_gen_cipher(req, syn, ctx->key[0], foc);
        rcu_read_unlock();
 }
 
        if (!ctx)
                goto out;
        for (i = 0; i < tcp_fastopen_context_len(ctx); i++) {
-               __tcp_fastopen_cookie_gen_cipher(req, syn, ctx->tfm[i], foc);
+               __tcp_fastopen_cookie_gen_cipher(req, syn, ctx->key[i], foc);
                if (tcp_fastopen_cookie_match(foc, orig)) {
                        ret = i + 1;
                        goto out;