ike-sa-manager: Add a method to register/check out new IKE_SAs
authorTobias Brunner <tobias@strongswan.org>
Fri, 15 Jan 2021 15:09:59 +0000 (16:09 +0100)
committerTobias Brunner <tobias@strongswan.org>
Fri, 12 Feb 2021 14:49:08 +0000 (15:49 +0100)
This way, jobs for new IKE_SAs (created via create_new()) may be
scheduled/queued before checkin() is called.  If they run before
that happens, they will now correctly block in checkout() instead of
doing nothing because the IKE_SA was not found.

src/libcharon/sa/ike_sa_manager.c
src/libcharon/sa/ike_sa_manager.h

index b7df1d8..9fec033 100644 (file)
@@ -1277,6 +1277,17 @@ METHOD(ike_sa_manager_t, create_new, ike_sa_t*,
        return ike_sa;
 }
 
+METHOD(ike_sa_manager_t, checkout_new, void,
+       private_ike_sa_manager_t *this, ike_sa_t *ike_sa)
+{
+       u_int segment;
+       entry_t *entry;
+
+       segment = create_and_put_entry(this, ike_sa, &entry);
+       entry->checked_out = thread_current();
+       unlock_single_segment(this, segment);
+}
+
 /**
  * Get the message ID or message hash to detect early retransmissions
  */
@@ -1491,10 +1502,7 @@ METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*,
        {       /* IKE_SA reuse disabled by config (not possible for IKEv1) */
                ike_sa = create_new(this, peer_cfg->get_ike_version(peer_cfg), TRUE);
                ike_sa->set_peer_cfg(ike_sa, peer_cfg);
-
-               segment = create_and_put_entry(this, ike_sa, &entry);
-               entry->checked_out = thread_current();
-               unlock_single_segment(this, segment);
+               checkout_new(this, ike_sa);
                charon->bus->set_sa(charon->bus, ike_sa);
                goto out;
        }
@@ -1566,10 +1574,7 @@ METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*,
        {
                ike_sa = create_new(this, peer_cfg->get_ike_version(peer_cfg), TRUE);
                ike_sa->set_peer_cfg(ike_sa, peer_cfg);
-
-               segment = create_and_put_entry(this, ike_sa, &entry);
-               entry->checked_out = thread_current();
-               unlock_single_segment(this, segment);
+               checkout_new(this, ike_sa);
        }
        charon->bus->set_sa(charon->bus, ike_sa);
 
@@ -2468,6 +2473,7 @@ ike_sa_manager_t *ike_sa_manager_create()
        INIT(this,
                .public = {
                        .create_new = _create_new,
+                       .checkout_new = _checkout_new,
                        .checkout = _checkout,
                        .checkout_by_message = _checkout_by_message,
                        .checkout_by_config = _checkout_by_config,
index 5695c94..b68ec7c 100644 (file)
@@ -60,6 +60,22 @@ struct ike_sa_manager_t {
                                                        bool initiator);
 
        /**
+        * Register/checkout an IKE_SA created with create_new().
+        *
+        * This may be used shortly before calling checkin() for unregistered SAs
+        * created via create_new() to avoid race conditions so e.g. jobs may
+        * find the SA and block on it until checkin() is called.
+        *
+        * @note There is no check that verifies that the IKE_SA is not yet
+        * registered.
+        *
+        * @note The IKE_SA on the bus is not changed by this method.
+        *
+        * @param ike_sa                        IKE_SA to register
+        */
+       void (*checkout_new)(ike_sa_manager_t* this, ike_sa_t *ike_sa);
+
+       /**
         * Checkout an existing IKE_SA.
         *
         * @param ike_sa_id                     the SA identifier, will be updated