Use CRITICAL job priority class for long running dispatcher jobs
[strongswan.git] / src / libcharon / plugins / ha / ha_dispatcher.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
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>.
9 *
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
13 * for more details.
14 */
15
16 #include "ha_dispatcher.h"
17
18 #include <daemon.h>
19 #include <processing/jobs/callback_job.h>
20
21 typedef struct private_ha_dispatcher_t private_ha_dispatcher_t;
22
23 /**
24 * Private data of an ha_dispatcher_t object.
25 */
26 struct private_ha_dispatcher_t {
27
28 /**
29 * Public ha_dispatcher_t interface.
30 */
31 ha_dispatcher_t public;
32
33 /**
34 * socket to pull messages from
35 */
36 ha_socket_t *socket;
37
38 /**
39 * segments to control
40 */
41 ha_segments_t *segments;
42
43 /**
44 * Cache for resync
45 */
46 ha_cache_t *cache;
47
48 /**
49 * Kernel helper
50 */
51 ha_kernel_t *kernel;
52
53 /**
54 * HA enabled pool
55 */
56 ha_attribute_t *attr;
57
58 /**
59 * Dispatcher job
60 */
61 callback_job_t *job;
62 };
63
64 /**
65 * Quick and dirty hack implementation of diffie_hellman_t.get_shared_secret
66 */
67 static status_t get_shared_secret(diffie_hellman_t *this, chunk_t *secret)
68 {
69 *secret = chunk_clone((*(chunk_t*)this->destroy));
70 return SUCCESS;
71 }
72
73 /**
74 * Process messages of type IKE_ADD
75 */
76 static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message)
77 {
78 ha_message_attribute_t attribute;
79 ha_message_value_t value;
80 enumerator_t *enumerator;
81 ike_sa_t *ike_sa = NULL, *old_sa = NULL;
82 u_int16_t encr = 0, len = 0, integ = 0, prf = 0, old_prf = PRF_UNDEFINED;
83 chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty;
84 chunk_t secret = chunk_empty, old_skd = chunk_empty;
85
86 enumerator = message->create_attribute_enumerator(message);
87 while (enumerator->enumerate(enumerator, &attribute, &value))
88 {
89 switch (attribute)
90 {
91 case HA_IKE_ID:
92 ike_sa = ike_sa_create(value.ike_sa_id);
93 break;
94 case HA_IKE_REKEY_ID:
95 old_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
96 value.ike_sa_id);
97 break;
98 case HA_NONCE_I:
99 nonce_i = value.chunk;
100 break;
101 case HA_NONCE_R:
102 nonce_r = value.chunk;
103 break;
104 case HA_SECRET:
105 secret = value.chunk;
106 break;
107 case HA_OLD_SKD:
108 old_skd = value.chunk;
109 break;
110 case HA_ALG_ENCR:
111 encr = value.u16;
112 break;
113 case HA_ALG_ENCR_LEN:
114 len = value.u16;
115 break;
116 case HA_ALG_INTEG:
117 integ = value.u16;
118 break;
119 case HA_ALG_PRF:
120 prf = value.u16;
121 break;
122 case HA_ALG_OLD_PRF:
123 old_prf = value.u16;
124 break;
125 default:
126 break;
127 }
128 }
129 enumerator->destroy(enumerator);
130
131 if (ike_sa)
132 {
133 proposal_t *proposal;
134 keymat_t *keymat;
135 /* quick and dirty hack of a DH implementation ;-) */
136 diffie_hellman_t dh = { .get_shared_secret = get_shared_secret,
137 .destroy = (void*)&secret };
138
139 proposal = proposal_create(PROTO_IKE, 0);
140 keymat = ike_sa->get_keymat(ike_sa);
141 if (integ)
142 {
143 proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, integ, 0);
144 }
145 if (encr)
146 {
147 proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, len);
148 }
149 if (prf)
150 {
151 proposal->add_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, prf, 0);
152 }
153 charon->bus->set_sa(charon->bus, ike_sa);
154 if (keymat->derive_ike_keys(keymat, proposal, &dh, nonce_i, nonce_r,
155 ike_sa->get_id(ike_sa), old_prf, old_skd))
156 {
157 if (old_sa)
158 {
159 peer_cfg_t *peer_cfg = old_sa->get_peer_cfg(old_sa);
160
161 if (peer_cfg)
162 {
163 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
164 ike_sa->inherit(ike_sa, old_sa);
165 }
166 charon->ike_sa_manager->checkin_and_destroy(
167 charon->ike_sa_manager, old_sa);
168 old_sa = NULL;
169 }
170 ike_sa->set_state(ike_sa, IKE_CONNECTING);
171 this->cache->cache(this->cache, ike_sa, message);
172 message = NULL;
173 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
174 }
175 else
176 {
177 DBG1(DBG_IKE, "HA keymat derivation failed");
178 ike_sa->destroy(ike_sa);
179 }
180 charon->bus->set_sa(charon->bus, NULL);
181 proposal->destroy(proposal);
182 }
183 if (old_sa)
184 {
185 charon->ike_sa_manager->checkin(charon->ike_sa_manager, old_sa);
186 }
187 DESTROY_IF(message);
188 }
189
190 /**
191 * Apply a condition flag to the IKE_SA if it is in set
192 */
193 static void set_condition(ike_sa_t *ike_sa, ike_condition_t set,
194 ike_condition_t flag)
195 {
196 ike_sa->set_condition(ike_sa, flag, flag & set);
197 }
198
199 /**
200 * Apply a extension flag to the IKE_SA if it is in set
201 */
202 static void set_extension(ike_sa_t *ike_sa, ike_extension_t set,
203 ike_extension_t flag)
204 {
205 if (flag & set)
206 {
207 ike_sa->enable_extension(ike_sa, flag);
208 }
209 }
210
211 /**
212 * Process messages of type IKE_UPDATE
213 */
214 static void process_ike_update(private_ha_dispatcher_t *this,
215 ha_message_t *message)
216 {
217 ha_message_attribute_t attribute;
218 ha_message_value_t value;
219 enumerator_t *enumerator;
220 ike_sa_t *ike_sa = NULL;
221 peer_cfg_t *peer_cfg = NULL;
222 auth_cfg_t *auth;
223 bool received_vip = FALSE;
224
225 enumerator = message->create_attribute_enumerator(message);
226 while (enumerator->enumerate(enumerator, &attribute, &value))
227 {
228 if (attribute != HA_IKE_ID && ike_sa == NULL)
229 {
230 /* must be first attribute */
231 break;
232 }
233 switch (attribute)
234 {
235 case HA_IKE_ID:
236 ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
237 value.ike_sa_id);
238 break;
239 case HA_LOCAL_ID:
240 ike_sa->set_my_id(ike_sa, value.id->clone(value.id));
241 break;
242 case HA_REMOTE_ID:
243 ike_sa->set_other_id(ike_sa, value.id->clone(value.id));
244 break;
245 case HA_REMOTE_EAP_ID:
246 auth = auth_cfg_create();
247 auth->add(auth, AUTH_RULE_EAP_IDENTITY, value.id->clone(value.id));
248 ike_sa->add_auth_cfg(ike_sa, FALSE, auth);
249 break;
250 case HA_LOCAL_ADDR:
251 ike_sa->set_my_host(ike_sa, value.host->clone(value.host));
252 break;
253 case HA_REMOTE_ADDR:
254 ike_sa->set_other_host(ike_sa, value.host->clone(value.host));
255 break;
256 case HA_LOCAL_VIP:
257 ike_sa->set_virtual_ip(ike_sa, TRUE, value.host);
258 break;
259 case HA_REMOTE_VIP:
260 ike_sa->set_virtual_ip(ike_sa, FALSE, value.host);
261 received_vip = TRUE;
262 break;
263 case HA_ADDITIONAL_ADDR:
264 ike_sa->add_additional_address(ike_sa,
265 value.host->clone(value.host));
266 break;
267 case HA_CONFIG_NAME:
268 peer_cfg = charon->backends->get_peer_cfg_by_name(
269 charon->backends, value.str);
270 if (peer_cfg)
271 {
272 ike_sa->set_peer_cfg(ike_sa, peer_cfg);
273 peer_cfg->destroy(peer_cfg);
274 }
275 else
276 {
277 DBG1(DBG_IKE, "HA is missing nodes peer configuration");
278 }
279 break;
280 case HA_EXTENSIONS:
281 set_extension(ike_sa, value.u32, EXT_NATT);
282 set_extension(ike_sa, value.u32, EXT_MOBIKE);
283 set_extension(ike_sa, value.u32, EXT_HASH_AND_URL);
284 break;
285 case HA_CONDITIONS:
286 set_condition(ike_sa, value.u32, COND_NAT_ANY);
287 set_condition(ike_sa, value.u32, COND_NAT_HERE);
288 set_condition(ike_sa, value.u32, COND_NAT_THERE);
289 set_condition(ike_sa, value.u32, COND_NAT_FAKE);
290 set_condition(ike_sa, value.u32, COND_EAP_AUTHENTICATED);
291 set_condition(ike_sa, value.u32, COND_CERTREQ_SEEN);
292 set_condition(ike_sa, value.u32, COND_ORIGINAL_INITIATOR);
293 break;
294 default:
295 break;
296 }
297 }
298 enumerator->destroy(enumerator);
299
300 if (ike_sa)
301 {
302 if (ike_sa->get_state(ike_sa) == IKE_CONNECTING &&
303 ike_sa->get_peer_cfg(ike_sa))
304 {
305 DBG1(DBG_CFG, "installed HA passive IKE_SA '%s' %H[%Y]...%H[%Y]",
306 ike_sa->get_name(ike_sa),
307 ike_sa->get_my_host(ike_sa), ike_sa->get_my_id(ike_sa),
308 ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa));
309 ike_sa->set_state(ike_sa, IKE_PASSIVE);
310 }
311 if (received_vip)
312 {
313 host_t *vip;
314 char *pool;
315
316 peer_cfg = ike_sa->get_peer_cfg(ike_sa);
317 vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
318 if (peer_cfg && vip)
319 {
320 pool = peer_cfg->get_pool(peer_cfg);
321 if (pool)
322 {
323 this->attr->reserve(this->attr, pool, vip);
324 }
325 }
326 }
327 this->cache->cache(this->cache, ike_sa, message);
328 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
329 }
330 else
331 {
332 DBG1(DBG_CFG, "passive HA IKE_SA to update not found");
333 message->destroy(message);
334 }
335 }
336
337 /**
338 * Process messages of type IKE_MID_INITIATOR/RESPONDER
339 */
340 static void process_ike_mid(private_ha_dispatcher_t *this,
341 ha_message_t *message, bool initiator)
342 {
343 ha_message_attribute_t attribute;
344 ha_message_value_t value;
345 enumerator_t *enumerator;
346 ike_sa_t *ike_sa = NULL;
347 u_int32_t mid = 0;
348
349 enumerator = message->create_attribute_enumerator(message);
350 while (enumerator->enumerate(enumerator, &attribute, &value))
351 {
352 switch (attribute)
353 {
354 case HA_IKE_ID:
355 ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
356 value.ike_sa_id);
357 break;
358 case HA_MID:
359 mid = value.u32;
360 break;
361 default:
362 break;
363 }
364 }
365 enumerator->destroy(enumerator);
366
367 if (ike_sa)
368 {
369 if (mid)
370 {
371 ike_sa->set_message_id(ike_sa, initiator, mid);
372 }
373 this->cache->cache(this->cache, ike_sa, message);
374 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
375 }
376 else
377 {
378 message->destroy(message);
379 }
380 }
381
382 /**
383 * Process messages of type IKE_DELETE
384 */
385 static void process_ike_delete(private_ha_dispatcher_t *this,
386 ha_message_t *message)
387 {
388 ha_message_attribute_t attribute;
389 ha_message_value_t value;
390 enumerator_t *enumerator;
391 ike_sa_t *ike_sa = NULL;
392
393 enumerator = message->create_attribute_enumerator(message);
394 while (enumerator->enumerate(enumerator, &attribute, &value))
395 {
396 switch (attribute)
397 {
398 case HA_IKE_ID:
399 ike_sa = charon->ike_sa_manager->checkout(
400 charon->ike_sa_manager, value.ike_sa_id);
401 break;
402 default:
403 break;
404 }
405 }
406 enumerator->destroy(enumerator);
407 if (ike_sa)
408 {
409 this->cache->cache(this->cache, ike_sa, message);
410 charon->ike_sa_manager->checkin_and_destroy(
411 charon->ike_sa_manager, ike_sa);
412 }
413 else
414 {
415 message->destroy(message);
416 }
417 }
418
419 /**
420 * Lookup a child cfg from the peer cfg by name
421 */
422 static child_cfg_t* find_child_cfg(ike_sa_t *ike_sa, char *name)
423 {
424 peer_cfg_t *peer_cfg;
425 child_cfg_t *current, *found = NULL;
426 enumerator_t *enumerator;
427
428 peer_cfg = ike_sa->get_peer_cfg(ike_sa);
429 if (peer_cfg)
430 {
431 enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
432 while (enumerator->enumerate(enumerator, &current))
433 {
434 if (streq(current->get_name(current), name))
435 {
436 found = current;
437 break;
438 }
439 }
440 enumerator->destroy(enumerator);
441 }
442 return found;
443 }
444
445 /**
446 * Process messages of type CHILD_ADD
447 */
448 static void process_child_add(private_ha_dispatcher_t *this,
449 ha_message_t *message)
450 {
451 ha_message_attribute_t attribute;
452 ha_message_value_t value;
453 enumerator_t *enumerator;
454 ike_sa_t *ike_sa = NULL;
455 char *config_name = "";
456 child_cfg_t *config = NULL;
457 child_sa_t *child_sa;
458 proposal_t *proposal;
459 keymat_t *keymat;
460 bool initiator = FALSE, failed = FALSE;
461 u_int32_t inbound_spi = 0, outbound_spi = 0;
462 u_int16_t inbound_cpi = 0, outbound_cpi = 0;
463 u_int8_t mode = MODE_TUNNEL, ipcomp = 0;
464 u_int16_t encr = ENCR_UNDEFINED, integ = AUTH_UNDEFINED, len = 0;
465 u_int16_t esn = NO_EXT_SEQ_NUMBERS;
466 u_int seg_i, seg_o;
467 chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty, secret = chunk_empty;
468 chunk_t encr_i, integ_i, encr_r, integ_r;
469 linked_list_t *local_ts, *remote_ts;
470 /* quick and dirty hack of a DH implementation */
471 diffie_hellman_t dh = { .get_shared_secret = get_shared_secret,
472 .destroy = (void*)&secret };
473
474 enumerator = message->create_attribute_enumerator(message);
475 while (enumerator->enumerate(enumerator, &attribute, &value))
476 {
477 switch (attribute)
478 {
479 case HA_IKE_ID:
480 ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
481 value.ike_sa_id);
482 break;
483 case HA_CONFIG_NAME:
484 config_name = value.str;
485 break;
486 case HA_INITIATOR:
487 initiator = value.u8;
488 break;
489 case HA_INBOUND_SPI:
490 inbound_spi = value.u32;
491 break;
492 case HA_OUTBOUND_SPI:
493 outbound_spi = value.u32;
494 break;
495 case HA_INBOUND_CPI:
496 inbound_cpi = value.u32;
497 break;
498 case HA_OUTBOUND_CPI:
499 outbound_cpi = value.u32;
500 break;
501 case HA_IPSEC_MODE:
502 mode = value.u8;
503 break;
504 case HA_IPCOMP:
505 ipcomp = value.u8;
506 break;
507 case HA_ALG_ENCR:
508 encr = value.u16;
509 break;
510 case HA_ALG_ENCR_LEN:
511 len = value.u16;
512 break;
513 case HA_ALG_INTEG:
514 integ = value.u16;
515 break;
516 case HA_ESN:
517 esn = value.u16;
518 break;
519 case HA_NONCE_I:
520 nonce_i = value.chunk;
521 break;
522 case HA_NONCE_R:
523 nonce_r = value.chunk;
524 break;
525 case HA_SECRET:
526 secret = value.chunk;
527 break;
528 default:
529 break;
530 }
531 }
532 enumerator->destroy(enumerator);
533
534 if (!ike_sa)
535 {
536 DBG1(DBG_CHD, "IKE_SA for HA CHILD_SA not found");
537 message->destroy(message);
538 return;
539 }
540 config = find_child_cfg(ike_sa, config_name);
541 if (!config)
542 {
543 DBG1(DBG_CHD, "HA is missing nodes child configuration");
544 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
545 message->destroy(message);
546 return;
547 }
548
549 child_sa = child_sa_create(ike_sa->get_my_host(ike_sa),
550 ike_sa->get_other_host(ike_sa), config, 0,
551 ike_sa->has_condition(ike_sa, COND_NAT_ANY));
552 child_sa->set_mode(child_sa, mode);
553 child_sa->set_protocol(child_sa, PROTO_ESP);
554 child_sa->set_ipcomp(child_sa, ipcomp);
555
556 proposal = proposal_create(PROTO_ESP, 0);
557 if (integ)
558 {
559 proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, integ, 0);
560 }
561 if (encr)
562 {
563 proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, len);
564 }
565 proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, esn, 0);
566 keymat = ike_sa->get_keymat(ike_sa);
567
568 if (!keymat->derive_child_keys(keymat, proposal, secret.ptr ? &dh : NULL,
569 nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r))
570 {
571 DBG1(DBG_CHD, "HA CHILD_SA key derivation failed");
572 child_sa->destroy(child_sa);
573 proposal->destroy(proposal);
574 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
575 return;
576 }
577 child_sa->set_proposal(child_sa, proposal);
578 child_sa->set_state(child_sa, CHILD_INSTALLING);
579 proposal->destroy(proposal);
580
581 /* TODO: Change CHILD_SA API to avoid cloning twice */
582 local_ts = linked_list_create();
583 remote_ts = linked_list_create();
584 enumerator = message->create_attribute_enumerator(message);
585 while (enumerator->enumerate(enumerator, &attribute, &value))
586 {
587 switch (attribute)
588 {
589 case HA_LOCAL_TS:
590 local_ts->insert_last(local_ts, value.ts->clone(value.ts));
591 break;
592 case HA_REMOTE_TS:
593 remote_ts->insert_last(remote_ts, value.ts->clone(value.ts));
594 break;
595 default:
596 break;
597 }
598 }
599 enumerator->destroy(enumerator);
600
601 if (initiator)
602 {
603 if (child_sa->install(child_sa, encr_r, integ_r, inbound_spi,
604 inbound_cpi, TRUE, TRUE, local_ts, remote_ts) != SUCCESS ||
605 child_sa->install(child_sa, encr_i, integ_i, outbound_spi,
606 outbound_cpi, FALSE, TRUE, local_ts, remote_ts) != SUCCESS)
607 {
608 failed = TRUE;
609 }
610 }
611 else
612 {
613 if (child_sa->install(child_sa, encr_i, integ_i, inbound_spi,
614 inbound_cpi, TRUE, TRUE, local_ts, remote_ts) != SUCCESS ||
615 child_sa->install(child_sa, encr_r, integ_r, outbound_spi,
616 outbound_cpi, FALSE, TRUE, local_ts, remote_ts) != SUCCESS)
617 {
618 failed = TRUE;
619 }
620 }
621 chunk_clear(&encr_i);
622 chunk_clear(&integ_i);
623 chunk_clear(&encr_r);
624 chunk_clear(&integ_r);
625
626 if (failed)
627 {
628 DBG1(DBG_CHD, "HA CHILD_SA installation failed");
629 child_sa->destroy(child_sa);
630 local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
631 remote_ts->destroy_offset(remote_ts, offsetof(traffic_selector_t, destroy));
632 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
633 message->destroy(message);
634 return;
635 }
636
637 seg_i = this->kernel->get_segment_spi(this->kernel,
638 ike_sa->get_my_host(ike_sa), inbound_spi);
639 seg_o = this->kernel->get_segment_spi(this->kernel,
640 ike_sa->get_other_host(ike_sa), outbound_spi);
641
642 DBG1(DBG_CFG, "installed HA CHILD_SA %s{%d} %#R=== %#R "
643 "(segment in: %d%s, out: %d%s)", child_sa->get_name(child_sa),
644 child_sa->get_reqid(child_sa), local_ts, remote_ts,
645 seg_i, this->segments->is_active(this->segments, seg_i) ? "*" : "",
646 seg_o, this->segments->is_active(this->segments, seg_o) ? "*" : "");
647 child_sa->add_policies(child_sa, local_ts, remote_ts);
648 local_ts->destroy_offset(local_ts, offsetof(traffic_selector_t, destroy));
649 remote_ts->destroy_offset(remote_ts, offsetof(traffic_selector_t, destroy));
650
651 child_sa->set_state(child_sa, CHILD_INSTALLED);
652 ike_sa->add_child_sa(ike_sa, child_sa);
653 message->destroy(message);
654 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
655 }
656
657 /**
658 * Process messages of type CHILD_DELETE
659 */
660 static void process_child_delete(private_ha_dispatcher_t *this,
661 ha_message_t *message)
662 {
663 ha_message_attribute_t attribute;
664 ha_message_value_t value;
665 enumerator_t *enumerator;
666 ike_sa_t *ike_sa = NULL;
667 child_sa_t *child_sa;
668 u_int32_t spi = 0;
669
670 enumerator = message->create_attribute_enumerator(message);
671 while (enumerator->enumerate(enumerator, &attribute, &value))
672 {
673 switch (attribute)
674 {
675 case HA_IKE_ID:
676 ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
677 value.ike_sa_id);
678 break;
679 case HA_INBOUND_SPI:
680 spi = value.u32;
681 break;
682 default:
683 break;
684 }
685 }
686 enumerator->destroy(enumerator);
687
688 if (ike_sa)
689 {
690 child_sa = ike_sa->get_child_sa(ike_sa, PROTO_ESP, spi, TRUE);
691 if (child_sa)
692 {
693 ike_sa->destroy_child_sa(ike_sa, PROTO_ESP, spi);
694 }
695 charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
696 }
697 message->destroy(message);
698 }
699
700 /**
701 * Process messages of type SEGMENT_TAKE/DROP
702 */
703 static void process_segment(private_ha_dispatcher_t *this,
704 ha_message_t *message, bool take)
705 {
706 ha_message_attribute_t attribute;
707 ha_message_value_t value;
708 enumerator_t *enumerator;
709
710 enumerator = message->create_attribute_enumerator(message);
711 while (enumerator->enumerate(enumerator, &attribute, &value))
712 {
713 switch (attribute)
714 {
715 case HA_SEGMENT:
716 if (take)
717 {
718 DBG1(DBG_CFG, "remote node takes segment %d", value.u16);
719 this->segments->deactivate(this->segments, value.u16, FALSE);
720 }
721 else
722 {
723 DBG1(DBG_CFG, "remote node drops segment %d", value.u16);
724 this->segments->activate(this->segments, value.u16, FALSE);
725 }
726 break;
727 default:
728 break;
729 }
730 }
731 enumerator->destroy(enumerator);
732 message->destroy(message);
733 }
734
735 /**
736 * Process messages of type STATUS
737 */
738 static void process_status(private_ha_dispatcher_t *this,
739 ha_message_t *message)
740 {
741 ha_message_attribute_t attribute;
742 ha_message_value_t value;
743 enumerator_t *enumerator;
744 segment_mask_t mask = 0;
745
746 enumerator = message->create_attribute_enumerator(message);
747 while (enumerator->enumerate(enumerator, &attribute, &value))
748 {
749 switch (attribute)
750 {
751 case HA_SEGMENT:
752 mask |= SEGMENTS_BIT(value.u16);
753 break;
754 default:
755 break;
756 }
757 }
758 enumerator->destroy(enumerator);
759
760 this->segments->handle_status(this->segments, mask);
761 message->destroy(message);
762 }
763
764 /**
765 * Process messages of type RESYNC
766 */
767 static void process_resync(private_ha_dispatcher_t *this,
768 ha_message_t *message)
769 {
770 ha_message_attribute_t attribute;
771 ha_message_value_t value;
772 enumerator_t *enumerator;
773
774 enumerator = message->create_attribute_enumerator(message);
775 while (enumerator->enumerate(enumerator, &attribute, &value))
776 {
777 switch (attribute)
778 {
779 case HA_SEGMENT:
780 this->cache->resync(this->cache, value.u16);
781 break;
782 default:
783 break;
784 }
785 }
786 enumerator->destroy(enumerator);
787 message->destroy(message);
788 }
789
790 /**
791 * Dispatcher job function
792 */
793 static job_requeue_t dispatch(private_ha_dispatcher_t *this)
794 {
795 ha_message_t *message;
796 ha_message_type_t type;
797
798 message = this->socket->pull(this->socket);
799 type = message->get_type(message);
800 if (type != HA_STATUS)
801 {
802 DBG2(DBG_CFG, "received HA %N message", ha_message_type_names,
803 message->get_type(message));
804 }
805 switch (type)
806 {
807 case HA_IKE_ADD:
808 process_ike_add(this, message);
809 break;
810 case HA_IKE_UPDATE:
811 process_ike_update(this, message);
812 break;
813 case HA_IKE_MID_INITIATOR:
814 process_ike_mid(this, message, TRUE);
815 break;
816 case HA_IKE_MID_RESPONDER:
817 process_ike_mid(this, message, FALSE);
818 break;
819 case HA_IKE_DELETE:
820 process_ike_delete(this, message);
821 break;
822 case HA_CHILD_ADD:
823 process_child_add(this, message);
824 break;
825 case HA_CHILD_DELETE:
826 process_child_delete(this, message);
827 break;
828 case HA_SEGMENT_DROP:
829 process_segment(this, message, FALSE);
830 break;
831 case HA_SEGMENT_TAKE:
832 process_segment(this, message, TRUE);
833 break;
834 case HA_STATUS:
835 process_status(this, message);
836 break;
837 case HA_RESYNC:
838 process_resync(this, message);
839 break;
840 default:
841 DBG1(DBG_CFG, "received unknown HA message type %d", type);
842 message->destroy(message);
843 break;
844 }
845 return JOB_REQUEUE_DIRECT;
846 }
847
848 METHOD(ha_dispatcher_t, destroy, void,
849 private_ha_dispatcher_t *this)
850 {
851 this->job->cancel(this->job);
852 free(this);
853 }
854
855 /**
856 * See header
857 */
858 ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
859 ha_segments_t *segments, ha_cache_t *cache,
860 ha_kernel_t *kernel, ha_attribute_t *attr)
861 {
862 private_ha_dispatcher_t *this;
863
864
865 INIT(this,
866 .public = {
867 .destroy = _destroy,
868 },
869 .socket = socket,
870 .segments = segments,
871 .cache = cache,
872 .kernel = kernel,
873 .attr = attr,
874 );
875 this->job = callback_job_create_with_prio((callback_job_cb_t)dispatch,
876 this, NULL, NULL, JOB_PRIO_CRITICAL);
877 lib->processor->queue_job(lib->processor, (job_t*)this->job);
878
879 return &this->public;
880 }
881