cleaned up and fixed DPD handling code
authorMartin Willi <martin@strongswan.org>
Wed, 14 Mar 2007 11:07:12 +0000 (11:07 -0000)
committerMartin Willi <martin@strongswan.org>
Wed, 14 Mar 2007 11:07:12 +0000 (11:07 -0000)
src/charon/sa/ike_sa.c
src/charon/sa/task_manager.c

index b8bfed5..a3dbaa4 100644 (file)
@@ -408,99 +408,6 @@ static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
 }
 
 /**
- * Implementation of ike_sa_t.retransmit.
- */
-static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
-{
-       this->time.outbound = time(NULL);
-       if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS)
-       {
-               connection_t *connection = NULL;
-               policy_t *policy;
-               linked_list_t *my_ts, *other_ts;
-               child_sa_t* child_sa;
-               dpd_action_t action;
-               job_t *job;
-               
-               DBG2(DBG_IKE, "dead peer detected, handling CHILD_SAs dpd action");
-               
-               /* check for childrens with dpdaction = hold */
-               while(this->child_sas->remove_first(this->child_sas,
-                                                                                       (void**)&child_sa) == SUCCESS)
-               {
-                       /* get the policy which belongs to this CHILD */
-                       my_ts = child_sa->get_my_traffic_selectors(child_sa);
-                       other_ts = child_sa->get_other_traffic_selectors(child_sa);
-                       policy = charon->policies->get_policy(charon->policies,
-                                                                                                 this->my_id, this->other_id,
-                                                                                                 my_ts, other_ts,
-                                                                                                 this->my_host, this->other_host);
-                       if (policy == NULL)
-                       {
-                               DBG1(DBG_IKE, "no policy for CHILD to handle DPD");
-                               continue;
-                       }
-                       
-                       action = policy->get_dpd_action(policy);
-                       /* get a connection for further actions */
-                       if (connection == NULL &&
-                               (action == DPD_ROUTE || action == DPD_RESTART))
-                       {
-                               connection = charon->connections->get_connection_by_hosts(
-                                                                                               charon->connections,
-                                                                                               this->my_host, this->other_host);
-                               if (connection == NULL)
-                               {
-                                       SIG(IKE_UP_FAILED, "no connection found to handle DPD");
-                                       break;
-                               }
-                       }
-                       
-                       DBG1(DBG_IKE, "dpd action for %s is %N",
-                                policy->get_name(policy), dpd_action_names, action);
-                       
-                       switch (action)
-                       {
-                               case DPD_ROUTE:
-                                       connection->get_ref(connection);
-                                       job = (job_t*)route_job_create(connection, policy, TRUE);
-                                       charon->job_queue->add(charon->job_queue, job);
-                                       break;
-                               case DPD_RESTART:
-                                       connection->get_ref(connection);
-                                       job = (job_t*)initiate_job_create(connection, policy);
-                                       charon->job_queue->add(charon->job_queue, job);
-                                       break;
-                               default:
-                                       policy->destroy(policy);
-                                       break;
-                       }
-                       child_sa->destroy(child_sa);
-               }
-               
-               /* send a proper signal to brief interested bus listeners */
-               switch (this->state)
-               {
-                       case IKE_CONNECTING:
-                               SIG(IKE_UP_FAILED, "establishing IKE_SA failed, peer not responding");
-                               break;
-                       case IKE_REKEYING:
-                               SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed, peer not responding");
-                               break;
-                       case IKE_DELETING:
-                               SIG(IKE_DOWN_FAILED, "proper IKE_SA delete failed, peer not responding");
-                               break;
-                       default:
-                               break;
-               }
-               
-               DESTROY_IF(connection);
-               return DESTROY_ME;
-       }
-       return SUCCESS;
-}
-
-/**
  * Implementation of ike_sa_t.generate
  */
 static status_t generate_message(private_ike_sa_t *this, message_t *message,
@@ -917,6 +824,119 @@ static status_t unroute(private_ike_sa_t *this, policy_t *policy)
 }
 
 /**
+ * Implementation of ike_sa_t.retransmit.
+ */
+static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
+{
+       this->time.outbound = time(NULL);
+       if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS)
+       {
+               policy_t *policy;
+               child_sa_t* child_sa;
+               linked_list_t *to_route, *to_restart;
+               iterator_t *iterator;
+               
+               /* send a proper signal to brief interested bus listeners */
+               switch (this->state)
+               {
+                       case IKE_CONNECTING:
+                               SIG(IKE_UP_FAILED, "establishing IKE_SA failed, peer not responding");
+                               break;
+                       case IKE_REKEYING:
+                               SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed, peer not responding");
+                               break;
+                       case IKE_DELETING:
+                               SIG(IKE_DOWN_FAILED, "proper IKE_SA delete failed, peer not responding");
+                               break;
+                       default:
+                               break;
+               }
+               
+               /* summarize how we have to handle each child */
+               to_route = linked_list_create();
+               to_restart = linked_list_create();
+               iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+               while (iterator->iterate(iterator, (void**)&child_sa))
+               {
+                       policy = child_sa->get_policy(child_sa);
+                       
+                       if (child_sa->get_state(child_sa) == CHILD_ROUTED)
+                       {
+                               /* reroute routed CHILD_SAs */
+                               to_route->insert_last(to_route, policy);
+                       }
+                       else
+                       {
+                               /* use DPD action for established CHILD_SAs */
+                               switch (policy->get_dpd_action(policy))
+                               {
+                                       case DPD_ROUTE:
+                                               to_route->insert_last(to_route, policy);
+                                               break;
+                                       case DPD_RESTART:
+                                               to_restart->insert_last(to_restart, policy);
+                                               break;
+                                       default:
+                                               break;
+                               }
+                       }
+               }
+               iterator->destroy(iterator);
+               
+               /* create a new IKE_SA if we have to route or to restart */
+               if (to_route->get_count(to_route) || to_restart->get_count(to_restart))
+               {
+                       ike_sa_id_t *other_id;
+                       private_ike_sa_t *new;
+                       task_t *task;
+                       
+                       other_id =  ike_sa_id_create(0, 0, TRUE);
+                       new = (private_ike_sa_t*)charon->ike_sa_manager->checkout(
+                                                                                       charon->ike_sa_manager, other_id);
+                       other_id->destroy(other_id);
+                       
+                       apply_config(new, this->connection, this->policy);
+                       /* use actual used host, not the wildcarded one in connection */
+                       new->other_host->destroy(new->other_host);
+                       new->other_host = this->other_host->clone(this->other_host);
+                       
+                       /* install routes */
+                       while (to_route->remove_last(to_route, (void**)&policy) == SUCCESS)
+                       {
+                               route(new, new->connection, policy);
+                       }
+                       
+                       /* restart children */
+                       if (to_restart->get_count(to_restart))
+                       {
+                               task = (task_t*)ike_init_create(&new->public, TRUE, NULL);
+                               new->task_manager->queue_task(new->task_manager, task);
+                               task = (task_t*)ike_natd_create(&new->public, TRUE);
+                               new->task_manager->queue_task(new->task_manager, task);
+                               task = (task_t*)ike_cert_create(&new->public, TRUE);
+                               new->task_manager->queue_task(new->task_manager, task);
+                               task = (task_t*)ike_config_create(&new->public, new->policy);
+                               new->task_manager->queue_task(new->task_manager, task);
+                               task = (task_t*)ike_auth_create(&new->public, TRUE);
+                               new->task_manager->queue_task(new->task_manager, task);
+                               
+                               while (to_restart->remove_last(to_restart, (void**)&policy) == SUCCESS)
+                               {
+                                       task = (task_t*)child_create_create(&new->public, policy);
+                                       new->task_manager->queue_task(new->task_manager, task);
+                               }
+                               new->task_manager->initiate(new->task_manager);
+                       }
+                       charon->ike_sa_manager->checkin(charon->ike_sa_manager, &new->public);
+               }
+               to_route->destroy(to_route);
+               to_restart->destroy(to_restart);
+               return DESTROY_ME;
+       }
+       return SUCCESS;
+}
+
+/**
  * Implementation of ike_sa_t.send_dpd
  */
 static status_t send_dpd(private_ike_sa_t *this)
index 4c6a199..be35cea 100644 (file)
@@ -739,7 +739,7 @@ static void destroy(private_task_manager_t *this)
                                SIG(IKE_UP_FAILED, "establishing IKE_SA failed");
                                break;
                        case IKE_DELETE:
-                               SIG(IKE_DOWN_FAILED, "deleting IKE_SA properly failed");
+                               SIG(IKE_DOWN_FAILED, "IKE_SA deleted");
                                break;
                        case IKE_REKEY:
                                SIG(IKE_REKEY_FAILED, "rekeying IKE_SA failed");