2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "ha_dispatcher.h"
19 #include <sa/ikev2/keymat_v2.h>
20 #include <sa/ikev1/keymat_v1.h>
21 #include <processing/jobs/callback_job.h>
22 #include <processing/jobs/adopt_children_job.h>
24 typedef struct private_ha_dispatcher_t private_ha_dispatcher_t
;
25 typedef struct ha_diffie_hellman_t ha_diffie_hellman_t
;
28 * Private data of an ha_dispatcher_t object.
30 struct private_ha_dispatcher_t
{
33 * Public ha_dispatcher_t interface.
35 ha_dispatcher_t
public;
38 * socket to pull messages from
45 ha_segments_t
*segments
;
64 * DH implementation for HA synced DH values
66 struct ha_diffie_hellman_t
{
69 * Implements diffie_hellman_t
84 METHOD(diffie_hellman_t
, dh_get_shared_secret
, bool,
85 ha_diffie_hellman_t
*this, chunk_t
*secret
)
87 *secret
= chunk_clone(this->secret
);
91 METHOD(diffie_hellman_t
, dh_get_my_public_value
, bool,
92 ha_diffie_hellman_t
*this, chunk_t
*value
)
94 *value
= chunk_clone(this->pub
);
98 METHOD(diffie_hellman_t
, dh_destroy
, void,
99 ha_diffie_hellman_t
*this)
105 * Create a HA synced DH implementation
107 static diffie_hellman_t
*ha_diffie_hellman_create(chunk_t secret
, chunk_t pub
)
109 ha_diffie_hellman_t
*this;
113 .get_shared_secret
= _dh_get_shared_secret
,
114 .get_my_public_value
= _dh_get_my_public_value
,
115 .destroy
= _dh_destroy
,
125 * Process messages of type IKE_ADD
127 static void process_ike_add(private_ha_dispatcher_t
*this, ha_message_t
*message
)
129 ha_message_attribute_t attribute
;
130 ha_message_value_t value
;
131 enumerator_t
*enumerator
;
132 ike_sa_t
*ike_sa
= NULL
, *old_sa
= NULL
;
133 ike_version_t version
= IKEV2
;
134 u_int16_t encr
= 0, len
= 0, integ
= 0, prf
= 0, old_prf
= PRF_UNDEFINED
;
135 chunk_t nonce_i
= chunk_empty
, nonce_r
= chunk_empty
;
136 chunk_t secret
= chunk_empty
, old_skd
= chunk_empty
;
137 chunk_t dh_local
= chunk_empty
, dh_remote
= chunk_empty
, psk
= chunk_empty
;
138 host_t
*other
= NULL
;
141 enumerator
= message
->create_attribute_enumerator(message
);
142 while (enumerator
->enumerate(enumerator
, &attribute
, &value
))
147 ike_sa
= ike_sa_create(value
.ike_sa_id
,
148 value
.ike_sa_id
->is_initiator(value
.ike_sa_id
), version
);
150 case HA_IKE_REKEY_ID
:
151 old_sa
= charon
->ike_sa_manager
->checkout(charon
->ike_sa_manager
,
155 other
= value
.host
->clone(value
.host
);
161 nonce_i
= value
.chunk
;
164 nonce_r
= value
.chunk
;
167 secret
= value
.chunk
;
170 dh_local
= value
.chunk
;
173 dh_remote
= value
.chunk
;
179 old_skd
= value
.chunk
;
184 case HA_ALG_ENCR_LEN
:
200 enumerator
->destroy(enumerator
);
204 proposal_t
*proposal
;
205 diffie_hellman_t
*dh
;
207 proposal
= proposal_create(PROTO_IKE
, 0);
210 proposal
->add_algorithm(proposal
, INTEGRITY_ALGORITHM
, integ
, 0);
214 proposal
->add_algorithm(proposal
, ENCRYPTION_ALGORITHM
, encr
, len
);
218 proposal
->add_algorithm(proposal
, PSEUDO_RANDOM_FUNCTION
, prf
, 0);
220 charon
->bus
->set_sa(charon
->bus
, ike_sa
);
221 dh
= ha_diffie_hellman_create(secret
, dh_local
);
222 if (ike_sa
->get_version(ike_sa
) == IKEV2
)
224 keymat_v2_t
*keymat_v2
= (keymat_v2_t
*)ike_sa
->get_keymat(ike_sa
);
226 ok
= keymat_v2
->derive_ike_keys(keymat_v2
, proposal
, dh
, nonce_i
,
227 nonce_r
, ike_sa
->get_id(ike_sa
), old_prf
, old_skd
);
229 if (ike_sa
->get_version(ike_sa
) == IKEV1
)
231 keymat_v1_t
*keymat_v1
= (keymat_v1_t
*)ike_sa
->get_keymat(ike_sa
);
232 shared_key_t
*shared
= NULL
;
233 auth_method_t method
= AUTH_RSA
;
238 shared
= shared_key_create(SHARED_IKE
, chunk_clone(psk
));
240 if (keymat_v1
->create_hasher(keymat_v1
, proposal
))
242 ok
= keymat_v1
->derive_ike_keys(keymat_v1
, proposal
,
243 dh
, dh_remote
, nonce_i
, nonce_r
,
244 ike_sa
->get_id(ike_sa
), method
, shared
);
253 ike_sa
->inherit_pre(ike_sa
, old_sa
);
254 ike_sa
->inherit_post(ike_sa
, old_sa
);
255 charon
->ike_sa_manager
->checkin_and_destroy(
256 charon
->ike_sa_manager
, old_sa
);
261 ike_sa
->set_other_host(ike_sa
, other
);
264 ike_sa
->set_state(ike_sa
, IKE_CONNECTING
);
265 ike_sa
->set_proposal(ike_sa
, proposal
);
266 this->cache
->cache(this->cache
, ike_sa
, message
);
268 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
272 DBG1(DBG_IKE
, "HA keymat derivation failed");
273 ike_sa
->destroy(ike_sa
);
275 charon
->bus
->set_sa(charon
->bus
, NULL
);
276 proposal
->destroy(proposal
);
280 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, old_sa
);
287 * Apply a condition flag to the IKE_SA if it is in set
289 static void set_condition(ike_sa_t
*ike_sa
, ike_condition_t set
,
290 ike_condition_t flag
)
292 ike_sa
->set_condition(ike_sa
, flag
, flag
& set
);
296 * Apply a extension flag to the IKE_SA if it is in set
298 static void set_extension(ike_sa_t
*ike_sa
, ike_extension_t set
,
299 ike_extension_t flag
)
303 ike_sa
->enable_extension(ike_sa
, flag
);
308 * Process messages of type IKE_UPDATE
310 static void process_ike_update(private_ha_dispatcher_t
*this,
311 ha_message_t
*message
)
313 ha_message_attribute_t attribute
;
314 ha_message_value_t value
;
315 enumerator_t
*enumerator
;
316 ike_sa_t
*ike_sa
= NULL
;
317 peer_cfg_t
*peer_cfg
= NULL
;
319 bool received_vip
= FALSE
, first_local_vip
= TRUE
, first_peer_addr
= TRUE
;
321 enumerator
= message
->create_attribute_enumerator(message
);
322 while (enumerator
->enumerate(enumerator
, &attribute
, &value
))
324 if (attribute
!= HA_IKE_ID
&& ike_sa
== NULL
)
326 /* must be first attribute */
332 ike_sa
= charon
->ike_sa_manager
->checkout(charon
->ike_sa_manager
,
336 ike_sa
->set_my_id(ike_sa
, value
.id
->clone(value
.id
));
339 ike_sa
->set_other_id(ike_sa
, value
.id
->clone(value
.id
));
341 case HA_REMOTE_EAP_ID
:
342 auth
= auth_cfg_create();
343 auth
->add(auth
, AUTH_RULE_EAP_IDENTITY
, value
.id
->clone(value
.id
));
344 ike_sa
->add_auth_cfg(ike_sa
, FALSE
, auth
);
347 ike_sa
->set_my_host(ike_sa
, value
.host
->clone(value
.host
));
350 ike_sa
->set_other_host(ike_sa
, value
.host
->clone(value
.host
));
355 ike_sa
->clear_virtual_ips(ike_sa
, TRUE
);
356 first_local_vip
= FALSE
;
358 ike_sa
->add_virtual_ip(ike_sa
, TRUE
, value
.host
);
363 ike_sa
->clear_virtual_ips(ike_sa
, FALSE
);
365 ike_sa
->add_virtual_ip(ike_sa
, FALSE
, value
.host
);
371 ike_sa
->clear_peer_addresses(ike_sa
);
372 first_peer_addr
= FALSE
;
374 ike_sa
->add_peer_address(ike_sa
, value
.host
->clone(value
.host
));
377 peer_cfg
= charon
->backends
->get_peer_cfg_by_name(
378 charon
->backends
, value
.str
);
381 ike_sa
->set_peer_cfg(ike_sa
, peer_cfg
);
382 peer_cfg
->destroy(peer_cfg
);
386 DBG1(DBG_IKE
, "HA is missing nodes peer configuration");
387 charon
->ike_sa_manager
->checkin_and_destroy(
388 charon
->ike_sa_manager
, ike_sa
);
393 set_extension(ike_sa
, value
.u32
, EXT_NATT
);
394 set_extension(ike_sa
, value
.u32
, EXT_MOBIKE
);
395 set_extension(ike_sa
, value
.u32
, EXT_HASH_AND_URL
);
396 set_extension(ike_sa
, value
.u32
, EXT_MULTIPLE_AUTH
);
397 set_extension(ike_sa
, value
.u32
, EXT_STRONGSWAN
);
398 set_extension(ike_sa
, value
.u32
, EXT_EAP_ONLY_AUTHENTICATION
);
399 set_extension(ike_sa
, value
.u32
, EXT_MS_WINDOWS
);
400 set_extension(ike_sa
, value
.u32
, EXT_XAUTH
);
401 set_extension(ike_sa
, value
.u32
, EXT_DPD
);
404 set_condition(ike_sa
, value
.u32
, COND_NAT_ANY
);
405 set_condition(ike_sa
, value
.u32
, COND_NAT_HERE
);
406 set_condition(ike_sa
, value
.u32
, COND_NAT_THERE
);
407 set_condition(ike_sa
, value
.u32
, COND_NAT_FAKE
);
408 set_condition(ike_sa
, value
.u32
, COND_EAP_AUTHENTICATED
);
409 set_condition(ike_sa
, value
.u32
, COND_CERTREQ_SEEN
);
410 set_condition(ike_sa
, value
.u32
, COND_ORIGINAL_INITIATOR
);
411 set_condition(ike_sa
, value
.u32
, COND_STALE
);
412 set_condition(ike_sa
, value
.u32
, COND_INIT_CONTACT_SEEN
);
413 set_condition(ike_sa
, value
.u32
, COND_XAUTH_AUTHENTICATED
);
419 enumerator
->destroy(enumerator
);
423 if (ike_sa
->get_state(ike_sa
) == IKE_CONNECTING
&&
424 ike_sa
->get_peer_cfg(ike_sa
))
426 DBG1(DBG_CFG
, "installed HA passive IKE_SA '%s' %H[%Y]...%H[%Y]",
427 ike_sa
->get_name(ike_sa
),
428 ike_sa
->get_my_host(ike_sa
), ike_sa
->get_my_id(ike_sa
),
429 ike_sa
->get_other_host(ike_sa
), ike_sa
->get_other_id(ike_sa
));
430 ike_sa
->set_state(ike_sa
, IKE_PASSIVE
);
434 enumerator_t
*pools
, *vips
;
438 peer_cfg
= ike_sa
->get_peer_cfg(ike_sa
);
441 pools
= peer_cfg
->create_pool_enumerator(peer_cfg
);
442 while (pools
->enumerate(pools
, &pool
))
444 vips
= ike_sa
->create_virtual_ip_enumerator(ike_sa
, FALSE
);
445 while (vips
->enumerate(vips
, &vip
))
447 this->attr
->reserve(this->attr
, pool
, vip
);
451 pools
->destroy(pools
);
455 if (ike_sa
->get_version(ike_sa
) == IKEV1
)
457 lib
->processor
->queue_job(lib
->processor
, (job_t
*)
458 adopt_children_job_create(ike_sa
->get_id(ike_sa
)));
460 #endif /* USE_IKEV1 */
461 this->cache
->cache(this->cache
, ike_sa
, message
);
462 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
466 DBG1(DBG_CFG
, "passive HA IKE_SA to update not found");
467 message
->destroy(message
);
472 * Process messages of type IKE_MID_INITIATOR/RESPONDER
474 static void process_ike_mid(private_ha_dispatcher_t
*this,
475 ha_message_t
*message
, bool initiator
)
477 ha_message_attribute_t attribute
;
478 ha_message_value_t value
;
479 enumerator_t
*enumerator
;
480 ike_sa_t
*ike_sa
= NULL
;
483 enumerator
= message
->create_attribute_enumerator(message
);
484 while (enumerator
->enumerate(enumerator
, &attribute
, &value
))
489 ike_sa
= charon
->ike_sa_manager
->checkout(charon
->ike_sa_manager
,
499 enumerator
->destroy(enumerator
);
505 ike_sa
->set_message_id(ike_sa
, initiator
, mid
);
507 this->cache
->cache(this->cache
, ike_sa
, message
);
508 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
512 message
->destroy(message
);
517 * Process messages of type IKE_IV
519 static void process_ike_iv(private_ha_dispatcher_t
*this, ha_message_t
*message
)
521 ha_message_attribute_t attribute
;
522 ha_message_value_t value
;
523 enumerator_t
*enumerator
;
524 ike_sa_t
*ike_sa
= NULL
;
525 chunk_t iv
= chunk_empty
;
527 enumerator
= message
->create_attribute_enumerator(message
);
528 while (enumerator
->enumerate(enumerator
, &attribute
, &value
))
533 ike_sa
= charon
->ike_sa_manager
->checkout(charon
->ike_sa_manager
,
543 enumerator
->destroy(enumerator
);
547 if (ike_sa
->get_version(ike_sa
) == IKEV1
)
553 keymat
= (keymat_v1_t
*)ike_sa
->get_keymat(ike_sa
);
554 if (keymat
->update_iv(keymat
, 0, iv
))
556 keymat
->confirm_iv(keymat
, 0);
560 this->cache
->cache(this->cache
, ike_sa
, message
);
561 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
565 message
->destroy(message
);
570 * Process messages of type IKE_DELETE
572 static void process_ike_delete(private_ha_dispatcher_t
*this,
573 ha_message_t
*message
)
575 ha_message_attribute_t attribute
;
576 ha_message_value_t value
;
577 enumerator_t
*enumerator
;
578 ike_sa_t
*ike_sa
= NULL
;
580 enumerator
= message
->create_attribute_enumerator(message
);
581 while (enumerator
->enumerate(enumerator
, &attribute
, &value
))
586 ike_sa
= charon
->ike_sa_manager
->checkout(
587 charon
->ike_sa_manager
, value
.ike_sa_id
);
593 enumerator
->destroy(enumerator
);
596 this->cache
->cache(this->cache
, ike_sa
, message
);
597 charon
->ike_sa_manager
->checkin_and_destroy(
598 charon
->ike_sa_manager
, ike_sa
);
602 message
->destroy(message
);
607 * Lookup a child cfg from the peer cfg by name
609 static child_cfg_t
* find_child_cfg(ike_sa_t
*ike_sa
, char *name
)
611 peer_cfg_t
*peer_cfg
;
612 child_cfg_t
*current
, *found
= NULL
;
613 enumerator_t
*enumerator
;
615 peer_cfg
= ike_sa
->get_peer_cfg(ike_sa
);
618 enumerator
= peer_cfg
->create_child_cfg_enumerator(peer_cfg
);
619 while (enumerator
->enumerate(enumerator
, ¤t
))
621 if (streq(current
->get_name(current
), name
))
627 enumerator
->destroy(enumerator
);
633 * Process messages of type CHILD_ADD
635 static void process_child_add(private_ha_dispatcher_t
*this,
636 ha_message_t
*message
)
638 ha_message_attribute_t attribute
;
639 ha_message_value_t value
;
640 enumerator_t
*enumerator
;
641 ike_sa_t
*ike_sa
= NULL
;
642 char *config_name
= "";
643 child_cfg_t
*config
= NULL
;
644 child_sa_t
*child_sa
;
645 proposal_t
*proposal
;
646 bool initiator
= FALSE
, failed
= FALSE
, ok
= FALSE
;
647 u_int32_t inbound_spi
= 0, outbound_spi
= 0;
648 u_int16_t inbound_cpi
= 0, outbound_cpi
= 0;
649 u_int8_t mode
= MODE_TUNNEL
, ipcomp
= 0;
650 u_int16_t encr
= 0, integ
= 0, len
= 0;
651 u_int16_t esn
= NO_EXT_SEQ_NUMBERS
;
653 chunk_t nonce_i
= chunk_empty
, nonce_r
= chunk_empty
, secret
= chunk_empty
;
654 chunk_t encr_i
, integ_i
, encr_r
, integ_r
;
655 linked_list_t
*local_ts
, *remote_ts
;
656 diffie_hellman_t
*dh
= NULL
;
658 enumerator
= message
->create_attribute_enumerator(message
);
659 while (enumerator
->enumerate(enumerator
, &attribute
, &value
))
664 ike_sa
= charon
->ike_sa_manager
->checkout(charon
->ike_sa_manager
,
668 config_name
= value
.str
;
671 initiator
= value
.u8
;
674 inbound_spi
= value
.u32
;
676 case HA_OUTBOUND_SPI
:
677 outbound_spi
= value
.u32
;
680 inbound_cpi
= value
.u32
;
682 case HA_OUTBOUND_CPI
:
683 outbound_cpi
= value
.u32
;
694 case HA_ALG_ENCR_LEN
:
704 nonce_i
= value
.chunk
;
707 nonce_r
= value
.chunk
;
710 secret
= value
.chunk
;
716 enumerator
->destroy(enumerator
);
720 DBG1(DBG_CHD
, "IKE_SA for HA CHILD_SA not found");
721 message
->destroy(message
);
724 config
= find_child_cfg(ike_sa
, config_name
);
727 DBG1(DBG_CHD
, "HA is missing nodes child configuration");
728 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
729 message
->destroy(message
);
733 child_sa
= child_sa_create(ike_sa
->get_my_host(ike_sa
),
734 ike_sa
->get_other_host(ike_sa
), config
, 0,
735 ike_sa
->has_condition(ike_sa
, COND_NAT_ANY
),
737 child_sa
->set_mode(child_sa
, mode
);
738 child_sa
->set_protocol(child_sa
, PROTO_ESP
);
739 child_sa
->set_ipcomp(child_sa
, ipcomp
);
741 proposal
= proposal_create(PROTO_ESP
, 0);
744 proposal
->add_algorithm(proposal
, INTEGRITY_ALGORITHM
, integ
, 0);
748 proposal
->add_algorithm(proposal
, ENCRYPTION_ALGORITHM
, encr
, len
);
750 proposal
->add_algorithm(proposal
, EXTENDED_SEQUENCE_NUMBERS
, esn
, 0);
753 dh
= ha_diffie_hellman_create(secret
, chunk_empty
);
755 if (ike_sa
->get_version(ike_sa
) == IKEV2
)
757 keymat_v2_t
*keymat_v2
= (keymat_v2_t
*)ike_sa
->get_keymat(ike_sa
);
759 ok
= keymat_v2
->derive_child_keys(keymat_v2
, proposal
, dh
,
760 nonce_i
, nonce_r
, &encr_i
, &integ_i
, &encr_r
, &integ_r
);
762 if (ike_sa
->get_version(ike_sa
) == IKEV1
)
764 keymat_v1_t
*keymat_v1
= (keymat_v1_t
*)ike_sa
->get_keymat(ike_sa
);
765 u_int32_t spi_i
, spi_r
;
767 spi_i
= initiator ? inbound_spi
: outbound_spi
;
768 spi_r
= initiator ? outbound_spi
: inbound_spi
;
770 ok
= keymat_v1
->derive_child_keys(keymat_v1
, proposal
, dh
, spi_i
, spi_r
,
771 nonce_i
, nonce_r
, &encr_i
, &integ_i
, &encr_r
, &integ_r
);
776 DBG1(DBG_CHD
, "HA CHILD_SA key derivation failed");
777 child_sa
->destroy(child_sa
);
778 proposal
->destroy(proposal
);
779 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
782 child_sa
->set_proposal(child_sa
, proposal
);
783 child_sa
->set_state(child_sa
, CHILD_INSTALLING
);
784 proposal
->destroy(proposal
);
786 /* TODO: Change CHILD_SA API to avoid cloning twice */
787 local_ts
= linked_list_create();
788 remote_ts
= linked_list_create();
789 enumerator
= message
->create_attribute_enumerator(message
);
790 while (enumerator
->enumerate(enumerator
, &attribute
, &value
))
795 local_ts
->insert_last(local_ts
, value
.ts
->clone(value
.ts
));
798 remote_ts
->insert_last(remote_ts
, value
.ts
->clone(value
.ts
));
804 enumerator
->destroy(enumerator
);
808 if (child_sa
->install(child_sa
, encr_r
, integ_r
, inbound_spi
,
809 inbound_cpi
, initiator
, TRUE
, TRUE
,
810 local_ts
, remote_ts
) != SUCCESS
||
811 child_sa
->install(child_sa
, encr_i
, integ_i
, outbound_spi
,
812 outbound_cpi
, initiator
, FALSE
, TRUE
,
813 local_ts
, remote_ts
) != SUCCESS
)
820 if (child_sa
->install(child_sa
, encr_i
, integ_i
, inbound_spi
,
821 inbound_cpi
, initiator
, TRUE
, TRUE
,
822 local_ts
, remote_ts
) != SUCCESS
||
823 child_sa
->install(child_sa
, encr_r
, integ_r
, outbound_spi
,
824 outbound_cpi
, initiator
, FALSE
, TRUE
,
825 local_ts
, remote_ts
) != SUCCESS
)
830 chunk_clear(&encr_i
);
831 chunk_clear(&integ_i
);
832 chunk_clear(&encr_r
);
833 chunk_clear(&integ_r
);
837 DBG1(DBG_CHD
, "HA CHILD_SA installation failed");
838 child_sa
->destroy(child_sa
);
839 local_ts
->destroy_offset(local_ts
, offsetof(traffic_selector_t
, destroy
));
840 remote_ts
->destroy_offset(remote_ts
, offsetof(traffic_selector_t
, destroy
));
841 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
842 message
->destroy(message
);
846 seg_i
= this->kernel
->get_segment_spi(this->kernel
,
847 ike_sa
->get_my_host(ike_sa
), inbound_spi
);
848 seg_o
= this->kernel
->get_segment_spi(this->kernel
,
849 ike_sa
->get_other_host(ike_sa
), outbound_spi
);
851 DBG1(DBG_CFG
, "installed HA CHILD_SA %s{%d} %#R === %#R "
852 "(segment in: %d%s, out: %d%s)", child_sa
->get_name(child_sa
),
853 child_sa
->get_unique_id(child_sa
), local_ts
, remote_ts
,
854 seg_i
, this->segments
->is_active(this->segments
, seg_i
) ?
"*" : "",
855 seg_o
, this->segments
->is_active(this->segments
, seg_o
) ?
"*" : "");
856 child_sa
->add_policies(child_sa
, local_ts
, remote_ts
);
857 local_ts
->destroy_offset(local_ts
, offsetof(traffic_selector_t
, destroy
));
858 remote_ts
->destroy_offset(remote_ts
, offsetof(traffic_selector_t
, destroy
));
860 child_sa
->set_state(child_sa
, CHILD_INSTALLED
);
861 ike_sa
->add_child_sa(ike_sa
, child_sa
);
862 message
->destroy(message
);
863 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
867 * Process messages of type CHILD_DELETE
869 static void process_child_delete(private_ha_dispatcher_t
*this,
870 ha_message_t
*message
)
872 ha_message_attribute_t attribute
;
873 ha_message_value_t value
;
874 enumerator_t
*enumerator
;
875 ike_sa_t
*ike_sa
= NULL
;
876 child_sa_t
*child_sa
;
879 enumerator
= message
->create_attribute_enumerator(message
);
880 while (enumerator
->enumerate(enumerator
, &attribute
, &value
))
885 ike_sa
= charon
->ike_sa_manager
->checkout(charon
->ike_sa_manager
,
895 enumerator
->destroy(enumerator
);
899 child_sa
= ike_sa
->get_child_sa(ike_sa
, PROTO_ESP
, spi
, TRUE
);
902 ike_sa
->destroy_child_sa(ike_sa
, PROTO_ESP
, spi
);
904 charon
->ike_sa_manager
->checkin(charon
->ike_sa_manager
, ike_sa
);
906 message
->destroy(message
);
910 * Process messages of type SEGMENT_TAKE/DROP
912 static void process_segment(private_ha_dispatcher_t
*this,
913 ha_message_t
*message
, bool take
)
915 ha_message_attribute_t attribute
;
916 ha_message_value_t value
;
917 enumerator_t
*enumerator
;
919 enumerator
= message
->create_attribute_enumerator(message
);
920 while (enumerator
->enumerate(enumerator
, &attribute
, &value
))
927 DBG1(DBG_CFG
, "remote node takes segment %d", value
.u16
);
928 this->segments
->deactivate(this->segments
, value
.u16
, FALSE
);
932 DBG1(DBG_CFG
, "remote node drops segment %d", value
.u16
);
933 this->segments
->activate(this->segments
, value
.u16
, FALSE
);
940 enumerator
->destroy(enumerator
);
941 message
->destroy(message
);
945 * Process messages of type STATUS
947 static void process_status(private_ha_dispatcher_t
*this,
948 ha_message_t
*message
)
950 ha_message_attribute_t attribute
;
951 ha_message_value_t value
;
952 enumerator_t
*enumerator
;
953 segment_mask_t mask
= 0;
955 enumerator
= message
->create_attribute_enumerator(message
);
956 while (enumerator
->enumerate(enumerator
, &attribute
, &value
))
961 mask
|= SEGMENTS_BIT(value
.u16
);
967 enumerator
->destroy(enumerator
);
969 this->segments
->handle_status(this->segments
, mask
);
970 message
->destroy(message
);
974 * Process messages of type RESYNC
976 static void process_resync(private_ha_dispatcher_t
*this,
977 ha_message_t
*message
)
979 ha_message_attribute_t attribute
;
980 ha_message_value_t value
;
981 enumerator_t
*enumerator
;
983 enumerator
= message
->create_attribute_enumerator(message
);
984 while (enumerator
->enumerate(enumerator
, &attribute
, &value
))
989 this->cache
->resync(this->cache
, value
.u16
);
995 enumerator
->destroy(enumerator
);
996 message
->destroy(message
);
1000 * Dispatcher job function
1002 static job_requeue_t
dispatch(private_ha_dispatcher_t
*this)
1004 ha_message_t
*message
;
1005 ha_message_type_t type
;
1007 message
= this->socket
->pull(this->socket
);
1008 type
= message
->get_type(message
);
1009 if (type
!= HA_STATUS
)
1011 DBG2(DBG_CFG
, "received HA %N message", ha_message_type_names
,
1012 message
->get_type(message
));
1017 process_ike_add(this, message
);
1020 process_ike_update(this, message
);
1022 case HA_IKE_MID_INITIATOR
:
1023 process_ike_mid(this, message
, TRUE
);
1025 case HA_IKE_MID_RESPONDER
:
1026 process_ike_mid(this, message
, FALSE
);
1029 process_ike_iv(this, message
);
1032 process_ike_delete(this, message
);
1035 process_child_add(this, message
);
1037 case HA_CHILD_DELETE
:
1038 process_child_delete(this, message
);
1040 case HA_SEGMENT_DROP
:
1041 process_segment(this, message
, FALSE
);
1043 case HA_SEGMENT_TAKE
:
1044 process_segment(this, message
, TRUE
);
1047 process_status(this, message
);
1050 process_resync(this, message
);
1053 DBG1(DBG_CFG
, "received unknown HA message type %d", type
);
1054 message
->destroy(message
);
1057 return JOB_REQUEUE_DIRECT
;
1060 METHOD(ha_dispatcher_t
, destroy
, void,
1061 private_ha_dispatcher_t
*this)
1069 ha_dispatcher_t
*ha_dispatcher_create(ha_socket_t
*socket
,
1070 ha_segments_t
*segments
, ha_cache_t
*cache
,
1071 ha_kernel_t
*kernel
, ha_attribute_t
*attr
)
1073 private_ha_dispatcher_t
*this;
1078 .destroy
= _destroy
,
1081 .segments
= segments
,
1086 lib
->processor
->queue_job(lib
->processor
,
1087 (job_t
*)callback_job_create_with_prio((callback_job_cb_t
)dispatch
, this,
1088 NULL
, (callback_job_cancel_t
)return_false
, JOB_PRIO_CRITICAL
));
1090 return &this->public;