]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
sctp: add SCTP_AUTH_FREE_KEY type for AUTHENTICATION_EVENT
authorXin Long <lucien.xin@gmail.com>
Wed, 14 Mar 2018 11:05:33 +0000 (19:05 +0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 14 Mar 2018 17:48:27 +0000 (13:48 -0400)
This patch is to add SCTP_AUTH_FREE_KEY type for AUTHENTICATION_EVENT,
as described in section 6.1.8 of RFC6458.

      SCTP_AUTH_FREE_KEY:  This report indicates that the SCTP
         implementation will no longer use the key identifier specified
         in auth_keynumber.

After deactivating a key, it would never be used again, which means
it's refcnt can't be held/increased by new chunks. But there may be
some chunks in out queue still using it. So only when refcnt is 1,
which means no chunk in outqueue is using/holding this key either,
this EVENT would be sent.

When users receive this notification, they could do DEL_KEY sockopt to
remove this shkey, and also tell the peer that this key won't be used
in any chunk thoroughly from now on, then the peer can remove it as
well safely.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/uapi/linux/sctp.h
net/sctp/auth.c
net/sctp/sm_make_chunk.c
net/sctp/sm_statefuns.c
net/sctp/socket.c

index 08fc313829f439b6dba2ada37f813210f29d7b86..18ebbfeee4af7c5848a679a3e0f6d7a1e4410b56 100644 (file)
@@ -518,7 +518,11 @@ struct sctp_authkey_event {
        sctp_assoc_t auth_assoc_id;
 };
 
-enum { SCTP_AUTH_NEWKEY = 0, };
+enum {
+       SCTP_AUTH_NEW_KEY,
+#define        SCTP_AUTH_NEWKEY        SCTP_AUTH_NEW_KEY /* compatible with before */
+       SCTP_AUTH_FREE_KEY,
+};
 
 /*
  * 6.1.9. SCTP_SENDER_DRY_EVENT
index a073123fc4850eaa70c8932f345e7c4fb1505679..e64630cd33318ef3c90339bd61388fafd27928f3 100644 (file)
@@ -992,6 +992,20 @@ int sctp_auth_deact_key_id(struct sctp_endpoint *ep,
        if (!found)
                return -EINVAL;
 
+       /* refcnt == 1 and !list_empty mean it's not being used anywhere
+        * and deactivated will be set, so it's time to notify userland
+        * that this shkey can be freed.
+        */
+       if (asoc && !list_empty(&key->key_list) &&
+           refcount_read(&key->refcnt) == 1) {
+               struct sctp_ulpevent *ev;
+
+               ev = sctp_ulpevent_make_authkey(asoc, key->key_id,
+                                               SCTP_AUTH_FREE_KEY, GFP_KERNEL);
+               if (ev)
+                       asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
+       }
+
        key->deactivated = 1;
 
        return 0;
index 10f071cdf1889bded4036b4833fa60098a1ac9aa..cc20bc39ee7ca97330ba8cc3202c01079f5e4e72 100644 (file)
@@ -89,8 +89,26 @@ static void sctp_control_release_owner(struct sk_buff *skb)
 {
        struct sctp_chunk *chunk = skb_shinfo(skb)->destructor_arg;
 
-       if (chunk->shkey)
+       if (chunk->shkey) {
+               struct sctp_shared_key *shkey = chunk->shkey;
+               struct sctp_association *asoc = chunk->asoc;
+
+               /* refcnt == 2 and !list_empty mean after this release, it's
+                * not being used anywhere, and it's time to notify userland
+                * that this shkey can be freed if it's been deactivated.
+                */
+               if (shkey->deactivated && !list_empty(&shkey->key_list) &&
+                   refcount_read(&shkey->refcnt) == 2) {
+                       struct sctp_ulpevent *ev;
+
+                       ev = sctp_ulpevent_make_authkey(asoc, shkey->key_id,
+                                                       SCTP_AUTH_FREE_KEY,
+                                                       GFP_KERNEL);
+                       if (ev)
+                               asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
+               }
                sctp_auth_shkey_release(chunk->shkey);
+       }
 }
 
 static void sctp_control_set_owner_w(struct sctp_chunk *chunk)
index 792e0e2be3204bcea6d5c65044062de8db094d93..1e41dee70b512a9921d504289815af2b2c71cb54 100644 (file)
@@ -4246,7 +4246,7 @@ enum sctp_disposition sctp_sf_eat_auth(struct net *net,
                struct sctp_ulpevent *ev;
 
                ev = sctp_ulpevent_make_authkey(asoc, ntohs(auth_hdr->shkey_id),
-                                   SCTP_AUTH_NEWKEY, GFP_ATOMIC);
+                                   SCTP_AUTH_NEW_KEY, GFP_ATOMIC);
 
                if (!ev)
                        return -ENOMEM;
index 65cc354c520f5cdf48e6540e643c5ee0ca64b527..aeecdd620c450380b7a09a22b0ec0311cb33d125 100644 (file)
@@ -8166,8 +8166,25 @@ static void sctp_wfree(struct sk_buff *skb)
        sk->sk_wmem_queued   -= skb->truesize;
        sk_mem_uncharge(sk, skb->truesize);
 
-       if (chunk->shkey)
+       if (chunk->shkey) {
+               struct sctp_shared_key *shkey = chunk->shkey;
+
+               /* refcnt == 2 and !list_empty mean after this release, it's
+                * not being used anywhere, and it's time to notify userland
+                * that this shkey can be freed if it's been deactivated.
+                */
+               if (shkey->deactivated && !list_empty(&shkey->key_list) &&
+                   refcount_read(&shkey->refcnt) == 2) {
+                       struct sctp_ulpevent *ev;
+
+                       ev = sctp_ulpevent_make_authkey(asoc, shkey->key_id,
+                                                       SCTP_AUTH_FREE_KEY,
+                                                       GFP_KERNEL);
+                       if (ev)
+                               asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
+               }
                sctp_auth_shkey_release(chunk->shkey);
+       }
 
        sock_wfree(skb);
        sctp_wake_up_waiters(sk, asoc);