summaryrefslogtreecommitdiff
path: root/src/charon
diff options
context:
space:
mode:
authorRene Mayrhofer <rene@mayrhofer.eu.org>2007-07-04 23:47:20 +0000
committerRene Mayrhofer <rene@mayrhofer.eu.org>2007-07-04 23:47:20 +0000
commit7b0305f59ddab9ea026b202a8c569912e5bf9a90 (patch)
tree131d39a22cf97e9e8c6da58ddefabc8138a731c2 /src/charon
parent08ee5250bd9c43fda5f24d10b791ca2c4c17fcee (diff)
downloadvyos-strongswan-7b0305f59ddab9ea026b202a8c569912e5bf9a90.tar.gz
vyos-strongswan-7b0305f59ddab9ea026b202a8c569912e5bf9a90.zip
[svn-upgrade] Integrating new upstream version, strongswan (4.1.4)
Diffstat (limited to 'src/charon')
-rw-r--r--src/charon/Makefile.am10
-rw-r--r--src/charon/Makefile.in148
-rw-r--r--src/charon/bus/bus.c34
-rw-r--r--src/charon/bus/bus.h16
-rw-r--r--src/charon/config/credentials/local_credential_store.c10
-rw-r--r--src/charon/config/traffic_selector.c20
-rw-r--r--src/charon/control/interfaces/dbus_interface.c23
-rwxr-xr-xsrc/charon/control/interfaces/stroke_interface.c204
-rw-r--r--src/charon/control/interfaces/xml_interface.c200
-rw-r--r--src/charon/daemon.c175
-rw-r--r--src/charon/daemon.h137
-rw-r--r--src/charon/encoding/message.c38
-rw-r--r--src/charon/encoding/payloads/notify_payload.c117
-rw-r--r--src/charon/encoding/payloads/notify_payload.h9
-rw-r--r--src/charon/kernel/kernel_interface.c1323
-rw-r--r--src/charon/kernel/kernel_interface.h70
-rw-r--r--src/charon/network/receiver.c164
-rw-r--r--src/charon/network/sender.c69
-rw-r--r--src/charon/processing/event_queue.c290
-rw-r--r--src/charon/processing/event_queue.h118
-rw-r--r--src/charon/processing/job_queue.c139
-rw-r--r--src/charon/processing/job_queue.h100
-rw-r--r--src/charon/processing/jobs/acquire_job.c33
-rw-r--r--src/charon/processing/jobs/callback_job.c213
-rw-r--r--src/charon/processing/jobs/callback_job.h135
-rw-r--r--src/charon/processing/jobs/delete_child_sa_job.c34
-rw-r--r--src/charon/processing/jobs/delete_ike_sa_job.c24
-rw-r--r--src/charon/processing/jobs/job.c39
-rw-r--r--src/charon/processing/jobs/job.h118
-rw-r--r--src/charon/processing/jobs/process_message_job.c23
-rw-r--r--src/charon/processing/jobs/rekey_child_sa_job.c32
-rw-r--r--src/charon/processing/jobs/rekey_ike_sa_job.c56
-rw-r--r--src/charon/processing/jobs/retransmit_job.c23
-rw-r--r--src/charon/processing/jobs/roam_job.c115
-rw-r--r--src/charon/processing/jobs/roam_job.h61
-rw-r--r--src/charon/processing/jobs/send_dpd_job.c49
-rw-r--r--src/charon/processing/jobs/send_dpd_job.h7
-rw-r--r--src/charon/processing/jobs/send_keepalive_job.c36
-rw-r--r--src/charon/processing/jobs/send_keepalive_job.h7
-rw-r--r--src/charon/processing/processor.c233
-rw-r--r--src/charon/processing/processor.h111
-rw-r--r--src/charon/processing/scheduler.c214
-rw-r--r--src/charon/processing/scheduler.h45
-rw-r--r--src/charon/processing/thread_pool.c183
-rw-r--r--src/charon/processing/thread_pool.h87
-rw-r--r--src/charon/sa/child_sa.c251
-rw-r--r--src/charon/sa/child_sa.h28
-rw-r--r--src/charon/sa/ike_sa.c621
-rw-r--r--src/charon/sa/ike_sa.h172
-rw-r--r--src/charon/sa/ike_sa_manager.c19
-rw-r--r--src/charon/sa/task_manager.c103
-rw-r--r--src/charon/sa/tasks/child_create.c77
-rw-r--r--src/charon/sa/tasks/child_rekey.c2
-rw-r--r--src/charon/sa/tasks/ike_auth.c7
-rw-r--r--src/charon/sa/tasks/ike_dpd.c2
-rw-r--r--src/charon/sa/tasks/ike_mobike.c431
-rw-r--r--src/charon/sa/tasks/ike_mobike.h73
-rw-r--r--src/charon/sa/tasks/ike_natd.c78
-rw-r--r--src/charon/sa/tasks/ike_reauth.c175
-rw-r--r--src/charon/sa/tasks/ike_reauth.h59
-rw-r--r--src/charon/sa/tasks/ike_rekey.c9
-rw-r--r--src/charon/sa/tasks/task.c6
-rw-r--r--src/charon/sa/tasks/task.h6
63 files changed, 4534 insertions, 2877 deletions
diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am
index a64d9fa70..9812a32ae 100644
--- a/src/charon/Makefile.am
+++ b/src/charon/Makefile.am
@@ -48,20 +48,20 @@ network/packet.c network/packet.h \
network/receiver.c network/receiver.h \
network/sender.c network/sender.h \
network/socket.c network/socket.h \
-processing/event_queue.c processing/event_queue.h \
-processing/job_queue.c processing/job_queue.h \
+processing/jobs/job.h \
processing/jobs/acquire_job.c processing/jobs/acquire_job.h \
+processing/jobs/callback_job.c processing/jobs/callback_job.h \
processing/jobs/delete_child_sa_job.c processing/jobs/delete_child_sa_job.h \
processing/jobs/delete_ike_sa_job.c processing/jobs/delete_ike_sa_job.h \
-processing/jobs/job.c processing/jobs/job.h \
processing/jobs/process_message_job.c processing/jobs/process_message_job.h \
processing/jobs/rekey_child_sa_job.c processing/jobs/rekey_child_sa_job.h \
processing/jobs/rekey_ike_sa_job.c processing/jobs/rekey_ike_sa_job.h \
processing/jobs/retransmit_job.c processing/jobs/retransmit_job.h \
processing/jobs/send_dpd_job.c processing/jobs/send_dpd_job.h \
processing/jobs/send_keepalive_job.c processing/jobs/send_keepalive_job.h \
+processing/jobs/roam_job.c processing/jobs/roam_job.h \
processing/scheduler.c processing/scheduler.h \
-processing/thread_pool.c processing/thread_pool.h \
+processing/processor.c processing/processor.h \
sa/authenticators/authenticator.c sa/authenticators/authenticator.h \
sa/authenticators/eap_authenticator.c sa/authenticators/eap_authenticator.h \
sa/authenticators/eap/eap_method.c sa/authenticators/eap/eap_method.h \
@@ -82,7 +82,9 @@ sa/tasks/ike_delete.c sa/tasks/ike_delete.h \
sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \
sa/tasks/ike_init.c sa/tasks/ike_init.h \
sa/tasks/ike_natd.c sa/tasks/ike_natd.h \
+sa/tasks/ike_mobike.c sa/tasks/ike_mobike.h \
sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \
+sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \
sa/tasks/task.c sa/tasks/task.h
diff --git a/src/charon/Makefile.in b/src/charon/Makefile.in
index 9f4177f60..1646eec6c 100644
--- a/src/charon/Makefile.in
+++ b/src/charon/Makefile.in
@@ -114,13 +114,12 @@ am_charon_OBJECTS = bus.$(OBJEXT) file_logger.$(OBJEXT) \
ts_payload.$(OBJEXT) unknown_payload.$(OBJEXT) \
vendor_id_payload.$(OBJEXT) kernel_interface.$(OBJEXT) \
packet.$(OBJEXT) receiver.$(OBJEXT) sender.$(OBJEXT) \
- socket.$(OBJEXT) event_queue.$(OBJEXT) job_queue.$(OBJEXT) \
- acquire_job.$(OBJEXT) delete_child_sa_job.$(OBJEXT) \
- delete_ike_sa_job.$(OBJEXT) job.$(OBJEXT) \
+ socket.$(OBJEXT) acquire_job.$(OBJEXT) callback_job.$(OBJEXT) \
+ delete_child_sa_job.$(OBJEXT) delete_ike_sa_job.$(OBJEXT) \
process_message_job.$(OBJEXT) rekey_child_sa_job.$(OBJEXT) \
rekey_ike_sa_job.$(OBJEXT) retransmit_job.$(OBJEXT) \
send_dpd_job.$(OBJEXT) send_keepalive_job.$(OBJEXT) \
- scheduler.$(OBJEXT) thread_pool.$(OBJEXT) \
+ roam_job.$(OBJEXT) scheduler.$(OBJEXT) processor.$(OBJEXT) \
authenticator.$(OBJEXT) eap_authenticator.$(OBJEXT) \
eap_method.$(OBJEXT) psk_authenticator.$(OBJEXT) \
rsa_authenticator.$(OBJEXT) child_sa.$(OBJEXT) \
@@ -129,7 +128,8 @@ am_charon_OBJECTS = bus.$(OBJEXT) file_logger.$(OBJEXT) \
child_delete.$(OBJEXT) child_rekey.$(OBJEXT) \
ike_auth.$(OBJEXT) ike_cert.$(OBJEXT) ike_config.$(OBJEXT) \
ike_delete.$(OBJEXT) ike_dpd.$(OBJEXT) ike_init.$(OBJEXT) \
- ike_natd.$(OBJEXT) ike_rekey.$(OBJEXT) task.$(OBJEXT)
+ ike_natd.$(OBJEXT) ike_mobike.$(OBJEXT) ike_rekey.$(OBJEXT) \
+ ike_reauth.$(OBJEXT) task.$(OBJEXT)
charon_OBJECTS = $(am_charon_OBJECTS)
charon_DEPENDENCIES = \
$(top_builddir)/src/libstrongswan/libstrongswan.la \
@@ -214,6 +214,7 @@ PATH_SEPARATOR = @PATH_SEPARATOR@
PERL = @PERL@
PKG_CONFIG = @PKG_CONFIG@
RANLIB = @RANLIB@
+SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
@@ -344,20 +345,20 @@ network/packet.c network/packet.h \
network/receiver.c network/receiver.h \
network/sender.c network/sender.h \
network/socket.c network/socket.h \
-processing/event_queue.c processing/event_queue.h \
-processing/job_queue.c processing/job_queue.h \
+processing/jobs/job.h \
processing/jobs/acquire_job.c processing/jobs/acquire_job.h \
+processing/jobs/callback_job.c processing/jobs/callback_job.h \
processing/jobs/delete_child_sa_job.c processing/jobs/delete_child_sa_job.h \
processing/jobs/delete_ike_sa_job.c processing/jobs/delete_ike_sa_job.h \
-processing/jobs/job.c processing/jobs/job.h \
processing/jobs/process_message_job.c processing/jobs/process_message_job.h \
processing/jobs/rekey_child_sa_job.c processing/jobs/rekey_child_sa_job.h \
processing/jobs/rekey_ike_sa_job.c processing/jobs/rekey_ike_sa_job.h \
processing/jobs/retransmit_job.c processing/jobs/retransmit_job.h \
processing/jobs/send_dpd_job.c processing/jobs/send_dpd_job.h \
processing/jobs/send_keepalive_job.c processing/jobs/send_keepalive_job.h \
+processing/jobs/roam_job.c processing/jobs/roam_job.h \
processing/scheduler.c processing/scheduler.h \
-processing/thread_pool.c processing/thread_pool.h \
+processing/processor.c processing/processor.h \
sa/authenticators/authenticator.c sa/authenticators/authenticator.h \
sa/authenticators/eap_authenticator.c sa/authenticators/eap_authenticator.h \
sa/authenticators/eap/eap_method.c sa/authenticators/eap/eap_method.h \
@@ -378,7 +379,9 @@ sa/tasks/ike_delete.c sa/tasks/ike_delete.h \
sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \
sa/tasks/ike_init.c sa/tasks/ike_init.h \
sa/tasks/ike_natd.c sa/tasks/ike_natd.h \
+sa/tasks/ike_mobike.c sa/tasks/ike_mobike.h \
sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \
+sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \
sa/tasks/task.c sa/tasks/task.h
INCLUDES = -I${linuxdir} -I$(top_srcdir)/src/libstrongswan \
@@ -584,6 +587,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/authenticator.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backend_manager.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bus.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/callback_job.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cert_payload.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/certreq_payload.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/child_cfg.Po@am__quote@
@@ -605,7 +609,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eap_sim.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encodings.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/encryption_payload.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/event_queue.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_logger.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generator.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/id_payload.Po@am__quote@
@@ -617,14 +620,14 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_dpd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_header.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_init.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_mobike.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_natd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_reauth.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_rekey.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_sa.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_sa_id.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ike_sa_manager.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interface_manager.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/job.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/job_queue.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ke_payload.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kernel_interface.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/local_backend.Plo@am__quote@
@@ -637,6 +640,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/payload.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/peer_cfg.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/process_message_job.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/processor.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proposal.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proposal_substructure.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/psk_authenticator.Po@am__quote@
@@ -644,6 +648,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rekey_child_sa_job.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rekey_ike_sa_job.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/retransmit_job.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/roam_job.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rsa_authenticator.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sa_payload.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scheduler.Po@am__quote@
@@ -655,7 +660,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sys_logger.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task_manager.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread_pool.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/traffic_selector.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/traffic_selector_substructure.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transform_attribute.Po@am__quote@
@@ -1316,34 +1320,6 @@ socket.obj: network/socket.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o socket.obj `if test -f 'network/socket.c'; then $(CYGPATH_W) 'network/socket.c'; else $(CYGPATH_W) '$(srcdir)/network/socket.c'; fi`
-event_queue.o: processing/event_queue.c
-@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT event_queue.o -MD -MP -MF "$(DEPDIR)/event_queue.Tpo" -c -o event_queue.o `test -f 'processing/event_queue.c' || echo '$(srcdir)/'`processing/event_queue.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/event_queue.Tpo" "$(DEPDIR)/event_queue.Po"; else rm -f "$(DEPDIR)/event_queue.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/event_queue.c' object='event_queue.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o event_queue.o `test -f 'processing/event_queue.c' || echo '$(srcdir)/'`processing/event_queue.c
-
-event_queue.obj: processing/event_queue.c
-@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT event_queue.obj -MD -MP -MF "$(DEPDIR)/event_queue.Tpo" -c -o event_queue.obj `if test -f 'processing/event_queue.c'; then $(CYGPATH_W) 'processing/event_queue.c'; else $(CYGPATH_W) '$(srcdir)/processing/event_queue.c'; fi`; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/event_queue.Tpo" "$(DEPDIR)/event_queue.Po"; else rm -f "$(DEPDIR)/event_queue.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/event_queue.c' object='event_queue.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o event_queue.obj `if test -f 'processing/event_queue.c'; then $(CYGPATH_W) 'processing/event_queue.c'; else $(CYGPATH_W) '$(srcdir)/processing/event_queue.c'; fi`
-
-job_queue.o: processing/job_queue.c
-@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT job_queue.o -MD -MP -MF "$(DEPDIR)/job_queue.Tpo" -c -o job_queue.o `test -f 'processing/job_queue.c' || echo '$(srcdir)/'`processing/job_queue.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/job_queue.Tpo" "$(DEPDIR)/job_queue.Po"; else rm -f "$(DEPDIR)/job_queue.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/job_queue.c' object='job_queue.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o job_queue.o `test -f 'processing/job_queue.c' || echo '$(srcdir)/'`processing/job_queue.c
-
-job_queue.obj: processing/job_queue.c
-@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT job_queue.obj -MD -MP -MF "$(DEPDIR)/job_queue.Tpo" -c -o job_queue.obj `if test -f 'processing/job_queue.c'; then $(CYGPATH_W) 'processing/job_queue.c'; else $(CYGPATH_W) '$(srcdir)/processing/job_queue.c'; fi`; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/job_queue.Tpo" "$(DEPDIR)/job_queue.Po"; else rm -f "$(DEPDIR)/job_queue.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/job_queue.c' object='job_queue.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o job_queue.obj `if test -f 'processing/job_queue.c'; then $(CYGPATH_W) 'processing/job_queue.c'; else $(CYGPATH_W) '$(srcdir)/processing/job_queue.c'; fi`
-
acquire_job.o: processing/jobs/acquire_job.c
@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT acquire_job.o -MD -MP -MF "$(DEPDIR)/acquire_job.Tpo" -c -o acquire_job.o `test -f 'processing/jobs/acquire_job.c' || echo '$(srcdir)/'`processing/jobs/acquire_job.c; \
@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/acquire_job.Tpo" "$(DEPDIR)/acquire_job.Po"; else rm -f "$(DEPDIR)/acquire_job.Tpo"; exit 1; fi
@@ -1358,6 +1334,20 @@ acquire_job.obj: processing/jobs/acquire_job.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o acquire_job.obj `if test -f 'processing/jobs/acquire_job.c'; then $(CYGPATH_W) 'processing/jobs/acquire_job.c'; else $(CYGPATH_W) '$(srcdir)/processing/jobs/acquire_job.c'; fi`
+callback_job.o: processing/jobs/callback_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT callback_job.o -MD -MP -MF "$(DEPDIR)/callback_job.Tpo" -c -o callback_job.o `test -f 'processing/jobs/callback_job.c' || echo '$(srcdir)/'`processing/jobs/callback_job.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/callback_job.Tpo" "$(DEPDIR)/callback_job.Po"; else rm -f "$(DEPDIR)/callback_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/jobs/callback_job.c' object='callback_job.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o callback_job.o `test -f 'processing/jobs/callback_job.c' || echo '$(srcdir)/'`processing/jobs/callback_job.c
+
+callback_job.obj: processing/jobs/callback_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT callback_job.obj -MD -MP -MF "$(DEPDIR)/callback_job.Tpo" -c -o callback_job.obj `if test -f 'processing/jobs/callback_job.c'; then $(CYGPATH_W) 'processing/jobs/callback_job.c'; else $(CYGPATH_W) '$(srcdir)/processing/jobs/callback_job.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/callback_job.Tpo" "$(DEPDIR)/callback_job.Po"; else rm -f "$(DEPDIR)/callback_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/jobs/callback_job.c' object='callback_job.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o callback_job.obj `if test -f 'processing/jobs/callback_job.c'; then $(CYGPATH_W) 'processing/jobs/callback_job.c'; else $(CYGPATH_W) '$(srcdir)/processing/jobs/callback_job.c'; fi`
+
delete_child_sa_job.o: processing/jobs/delete_child_sa_job.c
@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT delete_child_sa_job.o -MD -MP -MF "$(DEPDIR)/delete_child_sa_job.Tpo" -c -o delete_child_sa_job.o `test -f 'processing/jobs/delete_child_sa_job.c' || echo '$(srcdir)/'`processing/jobs/delete_child_sa_job.c; \
@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/delete_child_sa_job.Tpo" "$(DEPDIR)/delete_child_sa_job.Po"; else rm -f "$(DEPDIR)/delete_child_sa_job.Tpo"; exit 1; fi
@@ -1386,20 +1376,6 @@ delete_ike_sa_job.obj: processing/jobs/delete_ike_sa_job.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o delete_ike_sa_job.obj `if test -f 'processing/jobs/delete_ike_sa_job.c'; then $(CYGPATH_W) 'processing/jobs/delete_ike_sa_job.c'; else $(CYGPATH_W) '$(srcdir)/processing/jobs/delete_ike_sa_job.c'; fi`
-job.o: processing/jobs/job.c
-@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT job.o -MD -MP -MF "$(DEPDIR)/job.Tpo" -c -o job.o `test -f 'processing/jobs/job.c' || echo '$(srcdir)/'`processing/jobs/job.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/job.Tpo" "$(DEPDIR)/job.Po"; else rm -f "$(DEPDIR)/job.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/jobs/job.c' object='job.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o job.o `test -f 'processing/jobs/job.c' || echo '$(srcdir)/'`processing/jobs/job.c
-
-job.obj: processing/jobs/job.c
-@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT job.obj -MD -MP -MF "$(DEPDIR)/job.Tpo" -c -o job.obj `if test -f 'processing/jobs/job.c'; then $(CYGPATH_W) 'processing/jobs/job.c'; else $(CYGPATH_W) '$(srcdir)/processing/jobs/job.c'; fi`; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/job.Tpo" "$(DEPDIR)/job.Po"; else rm -f "$(DEPDIR)/job.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/jobs/job.c' object='job.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o job.obj `if test -f 'processing/jobs/job.c'; then $(CYGPATH_W) 'processing/jobs/job.c'; else $(CYGPATH_W) '$(srcdir)/processing/jobs/job.c'; fi`
-
process_message_job.o: processing/jobs/process_message_job.c
@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT process_message_job.o -MD -MP -MF "$(DEPDIR)/process_message_job.Tpo" -c -o process_message_job.o `test -f 'processing/jobs/process_message_job.c' || echo '$(srcdir)/'`processing/jobs/process_message_job.c; \
@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/process_message_job.Tpo" "$(DEPDIR)/process_message_job.Po"; else rm -f "$(DEPDIR)/process_message_job.Tpo"; exit 1; fi
@@ -1484,6 +1460,20 @@ send_keepalive_job.obj: processing/jobs/send_keepalive_job.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o send_keepalive_job.obj `if test -f 'processing/jobs/send_keepalive_job.c'; then $(CYGPATH_W) 'processing/jobs/send_keepalive_job.c'; else $(CYGPATH_W) '$(srcdir)/processing/jobs/send_keepalive_job.c'; fi`
+roam_job.o: processing/jobs/roam_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT roam_job.o -MD -MP -MF "$(DEPDIR)/roam_job.Tpo" -c -o roam_job.o `test -f 'processing/jobs/roam_job.c' || echo '$(srcdir)/'`processing/jobs/roam_job.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/roam_job.Tpo" "$(DEPDIR)/roam_job.Po"; else rm -f "$(DEPDIR)/roam_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/jobs/roam_job.c' object='roam_job.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o roam_job.o `test -f 'processing/jobs/roam_job.c' || echo '$(srcdir)/'`processing/jobs/roam_job.c
+
+roam_job.obj: processing/jobs/roam_job.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT roam_job.obj -MD -MP -MF "$(DEPDIR)/roam_job.Tpo" -c -o roam_job.obj `if test -f 'processing/jobs/roam_job.c'; then $(CYGPATH_W) 'processing/jobs/roam_job.c'; else $(CYGPATH_W) '$(srcdir)/processing/jobs/roam_job.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/roam_job.Tpo" "$(DEPDIR)/roam_job.Po"; else rm -f "$(DEPDIR)/roam_job.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/jobs/roam_job.c' object='roam_job.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o roam_job.obj `if test -f 'processing/jobs/roam_job.c'; then $(CYGPATH_W) 'processing/jobs/roam_job.c'; else $(CYGPATH_W) '$(srcdir)/processing/jobs/roam_job.c'; fi`
+
scheduler.o: processing/scheduler.c
@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT scheduler.o -MD -MP -MF "$(DEPDIR)/scheduler.Tpo" -c -o scheduler.o `test -f 'processing/scheduler.c' || echo '$(srcdir)/'`processing/scheduler.c; \
@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/scheduler.Tpo" "$(DEPDIR)/scheduler.Po"; else rm -f "$(DEPDIR)/scheduler.Tpo"; exit 1; fi
@@ -1498,19 +1488,19 @@ scheduler.obj: processing/scheduler.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o scheduler.obj `if test -f 'processing/scheduler.c'; then $(CYGPATH_W) 'processing/scheduler.c'; else $(CYGPATH_W) '$(srcdir)/processing/scheduler.c'; fi`
-thread_pool.o: processing/thread_pool.c
-@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread_pool.o -MD -MP -MF "$(DEPDIR)/thread_pool.Tpo" -c -o thread_pool.o `test -f 'processing/thread_pool.c' || echo '$(srcdir)/'`processing/thread_pool.c; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/thread_pool.Tpo" "$(DEPDIR)/thread_pool.Po"; else rm -f "$(DEPDIR)/thread_pool.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/thread_pool.c' object='thread_pool.o' libtool=no @AMDEPBACKSLASH@
+processor.o: processing/processor.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT processor.o -MD -MP -MF "$(DEPDIR)/processor.Tpo" -c -o processor.o `test -f 'processing/processor.c' || echo '$(srcdir)/'`processing/processor.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/processor.Tpo" "$(DEPDIR)/processor.Po"; else rm -f "$(DEPDIR)/processor.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/processor.c' object='processor.o' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o thread_pool.o `test -f 'processing/thread_pool.c' || echo '$(srcdir)/'`processing/thread_pool.c
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o processor.o `test -f 'processing/processor.c' || echo '$(srcdir)/'`processing/processor.c
-thread_pool.obj: processing/thread_pool.c
-@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT thread_pool.obj -MD -MP -MF "$(DEPDIR)/thread_pool.Tpo" -c -o thread_pool.obj `if test -f 'processing/thread_pool.c'; then $(CYGPATH_W) 'processing/thread_pool.c'; else $(CYGPATH_W) '$(srcdir)/processing/thread_pool.c'; fi`; \
-@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/thread_pool.Tpo" "$(DEPDIR)/thread_pool.Po"; else rm -f "$(DEPDIR)/thread_pool.Tpo"; exit 1; fi
-@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/thread_pool.c' object='thread_pool.obj' libtool=no @AMDEPBACKSLASH@
+processor.obj: processing/processor.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT processor.obj -MD -MP -MF "$(DEPDIR)/processor.Tpo" -c -o processor.obj `if test -f 'processing/processor.c'; then $(CYGPATH_W) 'processing/processor.c'; else $(CYGPATH_W) '$(srcdir)/processing/processor.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/processor.Tpo" "$(DEPDIR)/processor.Po"; else rm -f "$(DEPDIR)/processor.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='processing/processor.c' object='processor.obj' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o thread_pool.obj `if test -f 'processing/thread_pool.c'; then $(CYGPATH_W) 'processing/thread_pool.c'; else $(CYGPATH_W) '$(srcdir)/processing/thread_pool.c'; fi`
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o processor.obj `if test -f 'processing/processor.c'; then $(CYGPATH_W) 'processing/processor.c'; else $(CYGPATH_W) '$(srcdir)/processing/processor.c'; fi`
authenticator.o: sa/authenticators/authenticator.c
@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT authenticator.o -MD -MP -MF "$(DEPDIR)/authenticator.Tpo" -c -o authenticator.o `test -f 'sa/authenticators/authenticator.c' || echo '$(srcdir)/'`sa/authenticators/authenticator.c; \
@@ -1792,6 +1782,20 @@ ike_natd.obj: sa/tasks/ike_natd.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_natd.obj `if test -f 'sa/tasks/ike_natd.c'; then $(CYGPATH_W) 'sa/tasks/ike_natd.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_natd.c'; fi`
+ike_mobike.o: sa/tasks/ike_mobike.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_mobike.o -MD -MP -MF "$(DEPDIR)/ike_mobike.Tpo" -c -o ike_mobike.o `test -f 'sa/tasks/ike_mobike.c' || echo '$(srcdir)/'`sa/tasks/ike_mobike.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_mobike.Tpo" "$(DEPDIR)/ike_mobike.Po"; else rm -f "$(DEPDIR)/ike_mobike.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_mobike.c' object='ike_mobike.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_mobike.o `test -f 'sa/tasks/ike_mobike.c' || echo '$(srcdir)/'`sa/tasks/ike_mobike.c
+
+ike_mobike.obj: sa/tasks/ike_mobike.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_mobike.obj -MD -MP -MF "$(DEPDIR)/ike_mobike.Tpo" -c -o ike_mobike.obj `if test -f 'sa/tasks/ike_mobike.c'; then $(CYGPATH_W) 'sa/tasks/ike_mobike.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_mobike.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_mobike.Tpo" "$(DEPDIR)/ike_mobike.Po"; else rm -f "$(DEPDIR)/ike_mobike.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_mobike.c' object='ike_mobike.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_mobike.obj `if test -f 'sa/tasks/ike_mobike.c'; then $(CYGPATH_W) 'sa/tasks/ike_mobike.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_mobike.c'; fi`
+
ike_rekey.o: sa/tasks/ike_rekey.c
@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_rekey.o -MD -MP -MF "$(DEPDIR)/ike_rekey.Tpo" -c -o ike_rekey.o `test -f 'sa/tasks/ike_rekey.c' || echo '$(srcdir)/'`sa/tasks/ike_rekey.c; \
@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_rekey.Tpo" "$(DEPDIR)/ike_rekey.Po"; else rm -f "$(DEPDIR)/ike_rekey.Tpo"; exit 1; fi
@@ -1806,6 +1810,20 @@ ike_rekey.obj: sa/tasks/ike_rekey.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_rekey.obj `if test -f 'sa/tasks/ike_rekey.c'; then $(CYGPATH_W) 'sa/tasks/ike_rekey.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_rekey.c'; fi`
+ike_reauth.o: sa/tasks/ike_reauth.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_reauth.o -MD -MP -MF "$(DEPDIR)/ike_reauth.Tpo" -c -o ike_reauth.o `test -f 'sa/tasks/ike_reauth.c' || echo '$(srcdir)/'`sa/tasks/ike_reauth.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_reauth.Tpo" "$(DEPDIR)/ike_reauth.Po"; else rm -f "$(DEPDIR)/ike_reauth.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_reauth.c' object='ike_reauth.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_reauth.o `test -f 'sa/tasks/ike_reauth.c' || echo '$(srcdir)/'`sa/tasks/ike_reauth.c
+
+ike_reauth.obj: sa/tasks/ike_reauth.c
+@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ike_reauth.obj -MD -MP -MF "$(DEPDIR)/ike_reauth.Tpo" -c -o ike_reauth.obj `if test -f 'sa/tasks/ike_reauth.c'; then $(CYGPATH_W) 'sa/tasks/ike_reauth.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_reauth.c'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/ike_reauth.Tpo" "$(DEPDIR)/ike_reauth.Po"; else rm -f "$(DEPDIR)/ike_reauth.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sa/tasks/ike_reauth.c' object='ike_reauth.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ike_reauth.obj `if test -f 'sa/tasks/ike_reauth.c'; then $(CYGPATH_W) 'sa/tasks/ike_reauth.c'; else $(CYGPATH_W) '$(srcdir)/sa/tasks/ike_reauth.c'; fi`
+
task.o: sa/tasks/task.c
@am__fastdepCC_TRUE@ if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT task.o -MD -MP -MF "$(DEPDIR)/task.Tpo" -c -o task.o `test -f 'sa/tasks/task.c' || echo '$(srcdir)/'`sa/tasks/task.c; \
@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/task.Tpo" "$(DEPDIR)/task.Po"; else rm -f "$(DEPDIR)/task.Tpo"; exit 1; fi
diff --git a/src/charon/bus/bus.c b/src/charon/bus/bus.c
index 5f46cd29e..5fda36925 100644
--- a/src/charon/bus/bus.c
+++ b/src/charon/bus/bus.c
@@ -238,30 +238,13 @@ static active_listener_t *get_active_listener(private_bus_t *this)
return found;
}
-typedef struct cancel_info_t cancel_info_t;
-
-/**
- * cancellation info to cancel a listening operation cleanly
- */
-struct cancel_info_t {
- /**
- * mutex to unlock on cancellation
- */
- pthread_mutex_t *mutex;
-
- /**
- * listener to unregister
- */
- active_listener_t *listener;
-};
-
/**
* disable a listener to cleanly clean up
*/
-static void unregister(cancel_info_t *info)
+static void unregister(active_listener_t *listener)
{
- info->listener->state = UNREGISTERED;
- pthread_mutex_unlock(info->mutex);
+ listener->state = UNREGISTERED;
+ pthread_cond_broadcast(&listener->cond);
}
/**
@@ -272,7 +255,6 @@ static signal_t listen_(private_bus_t *this, level_t *level, int *thread,
{
active_listener_t *listener;
int oldstate;
- cancel_info_t info;
pthread_mutex_lock(&this->mutex);
listener = get_active_listener(this);
@@ -281,13 +263,13 @@ static signal_t listen_(private_bus_t *this, level_t *level, int *thread,
pthread_cond_broadcast(&listener->cond);
/* wait until it has us delivered a signal, and go back to "registered".
* we allow cancellation here, but must cleanly disable the listener. */
- info.mutex = &this->mutex;
- info.listener = listener;
- pthread_cleanup_push((void*)unregister, &info);
+ pthread_cleanup_push((void*)pthread_mutex_unlock, &this->mutex);
+ pthread_cleanup_push((void*)unregister, listener);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
pthread_cond_wait(&listener->cond, &this->mutex);
pthread_setcancelstate(oldstate, NULL);
pthread_cleanup_pop(0);
+ pthread_cleanup_pop(0);
pthread_mutex_unlock(&this->mutex);
@@ -320,7 +302,7 @@ static void set_listen_state(private_bus_t *this, bool active)
{
listener->state = UNREGISTERED;
/* say hello to signal emitter; we are finished processing the signal */
- pthread_cond_signal(&listener->cond);
+ pthread_cond_broadcast(&listener->cond);
}
pthread_mutex_unlock(&this->mutex);
@@ -390,7 +372,7 @@ static void vsignal(private_bus_t *this, signal_t signal, level_t level,
active_listener->format = format;
va_copy(active_listener->args, args);
active_listener->state = REGISTERED;
- pthread_cond_signal(&active_listener->cond);
+ pthread_cond_broadcast(&active_listener->cond);
}
}
diff --git a/src/charon/bus/bus.h b/src/charon/bus/bus.h
index 4b46c7e82..e54fb1b1b 100644
--- a/src/charon/bus/bus.h
+++ b/src/charon/bus/bus.h
@@ -39,14 +39,18 @@ typedef struct bus_t bus_t;
*
* Signaling is for different purporses. First, it allows debugging via
* "debugging signal messages", sencondly, it allows to follow certain
- * mechanisms currently going on in the daemon. As we are multithreaded,
- * and of multiple transactions are involved, it's not possible to follow
+ * mechanisms currently going on in the daemon. As we are multithreaded,
+ * and multiple transactions are involved, it's not possible to follow
* one connection setup without further infrastructure. These infrastructure
* is provided by the bus and the signals the daemon emits to the bus.
*
* There are different scenarios to follow these signals, but all have
* the same scheme. First, a START signal is emitted to indicate the daemon
- * has started to
+ * has started to do something. After a start signal, a SUCCESS or a FAILED
+ * signal of the same type follows. This allows to track the operation. Any
+ * Debug signal betwee a START and a SUCCESS/FAILED belongs to that operation
+ * if the IKE_SA is the same. The thread may change, as multiple threads
+ * may be involved in a complex scenario.
*
* @ingroup bus
*/
@@ -247,7 +251,9 @@ struct bus_listener_t {
* in receiving event signals registers at the bus. Any signals sent to
* are delivered to all registered listeners.
* To deliver signals to threads, the blocking listen() call may be used
- * to wait for a signal.
+ * to wait for a signal. However, passive listeners should be preferred,
+ * as listening actively requires some synchronization overhead as data
+ * must be passed from the raising thread to the listening thread.
*
* @ingroup bus
*/
@@ -283,7 +289,7 @@ struct bus_t {
* it processes a signal, registration is required. This is done through
* the set_listen_state() method, see below.
*
- * The listen() function is (has) a thread cancellation point, so might
+ * The listen() function is (has) a thread cancellation point, so you might
* want to register cleanup handlers.
*
* @param this bus
diff --git a/src/charon/config/credentials/local_credential_store.c b/src/charon/config/credentials/local_credential_store.c
index 6964345b3..649fcbcfb 100644
--- a/src/charon/config/credentials/local_credential_store.c
+++ b/src/charon/config/credentials/local_credential_store.c
@@ -456,7 +456,10 @@ static void add_uris(ca_info_t *issuer, x509_t *cert)
while (iterator->iterate(iterator, (void**)&uri))
{
- issuer->add_crluri(issuer, uri->get_encoding(uri));
+ if (uri->get_type(uri) == ID_DER_ASN1_GN_URI)
+ {
+ issuer->add_crluri(issuer, uri->get_encoding(uri));
+ }
}
iterator->destroy(iterator);
@@ -465,7 +468,10 @@ static void add_uris(ca_info_t *issuer, x509_t *cert)
while (iterator->iterate(iterator, (void**)&uri))
{
- issuer->add_ocspuri(issuer, uri->get_encoding(uri));
+ if (uri->get_type(uri) == ID_DER_ASN1_GN_URI)
+ {
+ issuer->add_ocspuri(issuer, uri->get_encoding(uri));
+ }
}
iterator->destroy(iterator);
}
diff --git a/src/charon/config/traffic_selector.c b/src/charon/config/traffic_selector.c
index b399074d1..da39c434d 100644
--- a/src/charon/config/traffic_selector.c
+++ b/src/charon/config/traffic_selector.c
@@ -175,6 +175,7 @@ static int print(FILE *stream, const struct printf_info *info,
bool has_proto;
bool has_ports;
size_t written = 0;
+ u_int32_t from[4], to[4];
if (this == NULL)
{
@@ -193,7 +194,11 @@ static int print(FILE *stream, const struct printf_info *info,
return written;
}
- if (this->dynamic)
+ memset(from, 0, sizeof(from));
+ memset(to, 0xFF, sizeof(to));
+ if (this->dynamic &&
+ memeq(this->from, from, this->type == TS_IPV4_ADDR_RANGE ? 4 : 16) &&
+ memeq(this->to, to, this->type == TS_IPV4_ADDR_RANGE ? 4 : 16))
{
return fprintf(stream, "dynamic/%d",
this->type == TS_IPV4_ADDR_RANGE ? 32 : 128);
@@ -341,6 +346,7 @@ static traffic_selector_t *get_subset(private_traffic_selector_t *this, private_
/* we have a match in protocol, port, and address: return it... */
new_ts = traffic_selector_create(protocol, this->type, from_port, to_port);
new_ts->type = this->type;
+ new_ts->dynamic = this->dynamic || other->dynamic;
memcpy(new_ts->from, from, size);
memcpy(new_ts->to, to, size);
@@ -475,11 +481,6 @@ static u_int8_t get_protocol(private_traffic_selector_t *this)
*/
static bool is_host(private_traffic_selector_t *this, host_t *host)
{
- if (this->dynamic)
- {
- return TRUE;
- }
-
if (host)
{
chunk_t addr;
@@ -498,7 +499,12 @@ static bool is_host(private_traffic_selector_t *this, host_t *host)
}
else
{
- size_t length = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
+ size_t length = (this->type == TS_IPV4_ADDR_RANGE) ? 4 : 16;
+
+ if (this->dynamic)
+ {
+ return TRUE;
+ }
if (memeq(this->from, this->to, length))
{
diff --git a/src/charon/control/interfaces/dbus_interface.c b/src/charon/control/interfaces/dbus_interface.c
index 443df635c..d93a5d048 100644
--- a/src/charon/control/interfaces/dbus_interface.c
+++ b/src/charon/control/interfaces/dbus_interface.c
@@ -30,6 +30,7 @@
#include <library.h>
#include <daemon.h>
+#include <processing/jobs/callback_job.h>
#define NM_DBUS_SERVICE_STRONG "org.freedesktop.NetworkManager.strongswan"
@@ -64,9 +65,9 @@ struct private_dbus_interface_t {
NMVPNState state;
/**
- * dispatcher thread for DBUS messages
+ * job accepting stroke messages
*/
- pthread_t thread;
+ callback_job_t *job;
/**
* name of the currently active connection
@@ -392,14 +393,13 @@ static DBusHandlerResult signal_handler(DBusConnection *con, DBusMessage *msg,
/**
* dispatcher function processed by a seperate thread
*/
-static void dispatch(private_dbus_interface_t *this)
+static job_requeue_t dispatch(private_dbus_interface_t *this)
{
- charon->drop_capabilities(charon, TRUE);
-
- while (dbus_connection_read_write_dispatch(this->conn, -1))
+ if (dbus_connection_read_write_dispatch(this->conn, -1))
{
- /* nothing */
+ return JOB_REQUEUE_DIRECT;
}
+ return JOB_REQUEUE_NONE;
}
/**
@@ -407,8 +407,7 @@ static void dispatch(private_dbus_interface_t *this)
*/
static void destroy(private_dbus_interface_t *this)
{
- pthread_cancel(this->thread);
- pthread_join(this->thread, NULL);
+ this->job->cancel(this->job);
dbus_connection_close(this->conn);
dbus_error_free(&this->err);
dbus_shutdown();
@@ -469,10 +468,8 @@ interface_t *interface_create()
this->state = NM_VPN_STATE_INIT;
set_state(this, NM_VPN_STATE_STOPPED);
- if (pthread_create(&this->thread, NULL, (void*(*)(void*))dispatch, this) != 0)
- {
- charon->kill(charon, "unable to create stroke thread");
- }
+ this->job = callback_job_create((callback_job_cb_t)dispatch, this, NULL, NULL);
+ charon->processor->queue_job(charon->processor, (job_t*)this->job);
return &this->public.interface;
}
diff --git a/src/charon/control/interfaces/stroke_interface.c b/src/charon/control/interfaces/stroke_interface.c
index 6e3427e8e..7885fc2e6 100755
--- a/src/charon/control/interfaces/stroke_interface.c
+++ b/src/charon/control/interfaces/stroke_interface.c
@@ -43,6 +43,7 @@
#include <control/interface_manager.h>
#include <control/interfaces/interface.h>
#include <utils/leak_detective.h>
+#include <processing/jobs/callback_job.h>
#define IKE_PORT 500
#define PATH_BUF 256
@@ -69,9 +70,9 @@ struct private_stroke_interface_t {
int socket;
/**
- * Thread which reads from the Socket
+ * job accepting stroke messages
*/
- pthread_t threads[STROKE_THREADS];
+ callback_job_t *job;
};
typedef struct stroke_log_info_t stroke_log_info_t;
@@ -224,8 +225,7 @@ static void pop_end(stroke_msg_t *msg, const char* label, stroke_end_t *end)
/**
* Add a connection to the configuration list
*/
-static void stroke_add_conn(private_stroke_interface_t *this,
- stroke_msg_t *msg, FILE *out)
+static void stroke_add_conn(stroke_msg_t *msg, FILE *out)
{
ike_cfg_t *ike_cfg;
peer_cfg_t *peer_cfg;
@@ -288,16 +288,18 @@ static void stroke_add_conn(private_stroke_interface_t *this,
msg->add_conn.other = tmp_end;
free(interface);
}
- if (!interface)
+ else
{
interface = charon->kernel_interface->get_interface(
charon->kernel_interface, my_host);
if (!interface)
{
- DBG1(DBG_CFG, "left nor right host is our side, aborting\n");
- goto destroy_hosts;
+ DBG1(DBG_CFG, "left nor right host is our side, assuming left=local");
+ }
+ else
+ {
+ free(interface);
}
- free(interface);
}
my_id = identification_create_from_string(msg->add_conn.me.id ?
@@ -628,8 +630,7 @@ destroy_hosts:
/**
* Delete a connection from the list
*/
-static void stroke_del_conn(private_stroke_interface_t *this,
- stroke_msg_t *msg, FILE *out)
+static void stroke_del_conn(stroke_msg_t *msg, FILE *out)
{
iterator_t *peer_iter, *child_iter;
peer_cfg_t *peer, *child;
@@ -747,8 +748,7 @@ static peer_cfg_t *get_peer_cfg_by_name(char *name)
/**
* initiate a connection by name
*/
-static void stroke_initiate(private_stroke_interface_t *this,
- stroke_msg_t *msg, FILE *out)
+static void stroke_initiate(stroke_msg_t *msg, FILE *out)
{
peer_cfg_t *peer_cfg;
child_cfg_t *child_cfg;
@@ -781,7 +781,6 @@ static void stroke_initiate(private_stroke_interface_t *this,
info.out = out;
info.level = msg->output_verbosity;
-
charon->interfaces->initiate(charon->interfaces, peer_cfg, child_cfg,
(interface_manager_cb_t)stroke_log, &info);
}
@@ -789,8 +788,7 @@ static void stroke_initiate(private_stroke_interface_t *this,
/**
* route a policy (install SPD entries)
*/
-static void stroke_route(private_stroke_interface_t *this,
- stroke_msg_t *msg, FILE *out)
+static void stroke_route(stroke_msg_t *msg, FILE *out)
{
peer_cfg_t *peer_cfg;
child_cfg_t *child_cfg;
@@ -830,8 +828,7 @@ static void stroke_route(private_stroke_interface_t *this,
/**
* unroute a policy
*/
-static void stroke_unroute(private_stroke_interface_t *this,
- stroke_msg_t *msg, FILE *out)
+static void stroke_unroute(stroke_msg_t *msg, FILE *out)
{
char *name;
ike_sa_t *ike_sa;
@@ -874,8 +871,7 @@ static void stroke_unroute(private_stroke_interface_t *this,
/**
* terminate a connection by name
*/
-static void stroke_terminate(private_stroke_interface_t *this,
- stroke_msg_t *msg, FILE *out)
+static void stroke_terminate(stroke_msg_t *msg, FILE *out)
{
char *string, *pos = NULL, *name = NULL;
u_int32_t id = 0;
@@ -979,8 +975,7 @@ static void stroke_terminate(private_stroke_interface_t *this,
/**
* Add a ca information record to the cainfo list
*/
-static void stroke_add_ca(private_stroke_interface_t *this,
- stroke_msg_t *msg, FILE *out)
+static void stroke_add_ca(stroke_msg_t *msg, FILE *out)
{
x509_t *cacert;
ca_info_t *ca_info;
@@ -1047,8 +1042,7 @@ static void stroke_add_ca(private_stroke_interface_t *this,
/**
* Delete a ca information record from the cainfo list
*/
-static void stroke_del_ca(private_stroke_interface_t *this,
- stroke_msg_t *msg, FILE *out)
+static void stroke_del_ca(stroke_msg_t *msg, FILE *out)
{
status_t status;
@@ -1194,11 +1188,9 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all)
/**
* show status of daemon
*/
-static void stroke_status(private_stroke_interface_t *this,
- stroke_msg_t *msg, FILE *out, bool all)
+static void stroke_status(stroke_msg_t *msg, FILE *out, bool all)
{
iterator_t *iterator, *children;
- linked_list_t *list;
host_t *host;
peer_cfg_t *peer_cfg;
ike_cfg_t *ike_cfg;
@@ -1218,21 +1210,20 @@ static void stroke_status(private_stroke_interface_t *this,
fprintf(out, "Performance:\n");
fprintf(out, " worker threads: %d idle of %d,",
- charon->thread_pool->get_idle_threads(charon->thread_pool),
- charon->thread_pool->get_pool_size(charon->thread_pool));
+ charon->processor->get_idle_threads(charon->processor),
+ charon->processor->get_total_threads(charon->processor));
fprintf(out, " job queue load: %d,",
- charon->job_queue->get_count(charon->job_queue));
+ charon->processor->get_job_load(charon->processor));
fprintf(out, " scheduled events: %d\n",
- charon->event_queue->get_count(charon->event_queue));
- list = charon->kernel_interface->create_address_list(charon->kernel_interface);
-
- fprintf(out, "Listening on %d IP addresses:\n", list->get_count(list));
- while (list->remove_first(list, (void**)&host) == SUCCESS)
+ charon->scheduler->get_job_load(charon->scheduler));
+ iterator = charon->kernel_interface->create_address_iterator(
+ charon->kernel_interface);
+ fprintf(out, "Listening IP addresses:\n");
+ while (iterator->iterate(iterator, (void**)&host))
{
fprintf(out, " %H\n", host);
- host->destroy(host);
}
- list->destroy(list);
+ iterator->destroy(iterator);
fprintf(out, "Connections:\n");
iterator = charon->backends->create_iterator(charon->backends);
@@ -1312,8 +1303,8 @@ static void stroke_status(private_stroke_interface_t *this,
/**
* list all authority certificates matching a specified flag
*/
-static void list_auth_certificates(private_stroke_interface_t *this, u_int flag,
- const char *label, bool utc, FILE *out)
+static void list_auth_certificates(u_int flag, const char *label,
+ bool utc, FILE *out)
{
bool first = TRUE;
x509_t *cert;
@@ -1341,8 +1332,7 @@ static void list_auth_certificates(private_stroke_interface_t *this, u_int flag
/**
* list various information
*/
-static void stroke_list(private_stroke_interface_t *this,
- stroke_msg_t *msg, FILE *out)
+static void stroke_list(stroke_msg_t *msg, FILE *out)
{
iterator_t *iterator;
@@ -1372,15 +1362,15 @@ static void stroke_list(private_stroke_interface_t *this,
}
if (msg->list.flags & LIST_CACERTS)
{
- list_auth_certificates(this, AUTH_CA, "CA", msg->list.utc, out);
+ list_auth_certificates(AUTH_CA, "CA", msg->list.utc, out);
}
if (msg->list.flags & LIST_OCSPCERTS)
{
- list_auth_certificates(this, AUTH_OCSP, "OCSP", msg->list.utc, out);
+ list_auth_certificates(AUTH_OCSP, "OCSP", msg->list.utc, out);
}
if (msg->list.flags & LIST_AACERTS)
{
- list_auth_certificates(this, AUTH_AA, "AA", msg->list.utc, out);
+ list_auth_certificates(AUTH_AA, "AA", msg->list.utc, out);
}
if (msg->list.flags & LIST_CAINFOS)
{
@@ -1453,8 +1443,7 @@ static void stroke_list(private_stroke_interface_t *this,
/**
* reread various information
*/
-static void stroke_reread(private_stroke_interface_t *this,
- stroke_msg_t *msg, FILE *out)
+static void stroke_reread(stroke_msg_t *msg, FILE *out)
{
if (msg->reread.flags & REREAD_CACERTS)
{
@@ -1473,8 +1462,7 @@ static void stroke_reread(private_stroke_interface_t *this,
/**
* purge various information
*/
-static void stroke_purge(private_stroke_interface_t *this,
- stroke_msg_t *msg, FILE *out)
+static void stroke_purge(stroke_msg_t *msg, FILE *out)
{
if (msg->purge.flags & PURGE_OCSP)
{
@@ -1510,8 +1498,7 @@ signal_t get_signal_from_logtype(char *type)
/**
* set the verbosity debug output
*/
-static void stroke_loglevel(private_stroke_interface_t *this,
- stroke_msg_t *msg, FILE *out)
+static void stroke_loglevel(stroke_msg_t *msg, FILE *out)
{
signal_t signal;
@@ -1533,20 +1520,22 @@ static void stroke_loglevel(private_stroke_interface_t *this,
/**
* process a stroke request from the socket pointed by "fd"
*/
-static void stroke_process(private_stroke_interface_t *this, int strokefd)
+static job_requeue_t stroke_process(int *fdp)
{
stroke_msg_t *msg;
u_int16_t msg_length;
ssize_t bytes_read;
FILE *out;
+ int strokefd = *fdp;
/* peek the length */
bytes_read = recv(strokefd, &msg_length, sizeof(msg_length), MSG_PEEK);
if (bytes_read != sizeof(msg_length))
{
- DBG1(DBG_CFG, "reading length of stroke message failed");
+ DBG1(DBG_CFG, "reading length of stroke message failed: %s",
+ strerror(errno));
close(strokefd);
- return;
+ return JOB_REQUEUE_NONE;
}
/* read message */
@@ -1556,105 +1545,107 @@ static void stroke_process(private_stroke_interface_t *this, int strokefd)
{
DBG1(DBG_CFG, "reading stroke message failed: %s", strerror(errno));
close(strokefd);
- return;
+ return JOB_REQUEUE_NONE;
}
- out = fdopen(dup(strokefd), "w");
+ out = fdopen(strokefd, "w");
if (out == NULL)
{
DBG1(DBG_CFG, "opening stroke output channel failed: %s", strerror(errno));
close(strokefd);
free(msg);
- return;
+ return JOB_REQUEUE_NONE;
}
DBG3(DBG_CFG, "stroke message %b", (void*)msg, msg_length);
+ /* the stroke_* functions are blocking, as they listen on the bus. Add
+ * cancellation handlers. */
+ pthread_cleanup_push((void*)fclose, out);
+ pthread_cleanup_push(free, msg);
+
switch (msg->type)
{
case STR_INITIATE:
- stroke_initiate(this, msg, out);
+ stroke_initiate(msg, out);
break;
case STR_ROUTE:
- stroke_route(this, msg, out);
+ stroke_route(msg, out);
break;
case STR_UNROUTE:
- stroke_unroute(this, msg, out);
+ stroke_unroute(msg, out);
break;
case STR_TERMINATE:
- stroke_terminate(this, msg, out);
+ stroke_terminate(msg, out);
break;
case STR_STATUS:
- stroke_status(this, msg, out, FALSE);
+ stroke_status(msg, out, FALSE);
break;
case STR_STATUS_ALL:
- stroke_status(this, msg, out, TRUE);
+ stroke_status(msg, out, TRUE);
break;
case STR_ADD_CONN:
- stroke_add_conn(this, msg, out);
+ stroke_add_conn(msg, out);
break;
case STR_DEL_CONN:
- stroke_del_conn(this, msg, out);
+ stroke_del_conn(msg, out);
break;
case STR_ADD_CA:
- stroke_add_ca(this, msg, out);
+ stroke_add_ca(msg, out);
break;
case STR_DEL_CA:
- stroke_del_ca(this, msg, out);
+ stroke_del_ca(msg, out);
break;
case STR_LOGLEVEL:
- stroke_loglevel(this, msg, out);
+ stroke_loglevel(msg, out);
break;
case STR_LIST:
- stroke_list(this, msg, out);
+ stroke_list(msg, out);
break;
case STR_REREAD:
- stroke_reread(this, msg, out);
+ stroke_reread(msg, out);
break;
case STR_PURGE:
- stroke_purge(this, msg, out);
+ stroke_purge(msg, out);
break;
default:
DBG1(DBG_CFG, "received unknown stroke");
}
- fclose(out);
- close(strokefd);
- free(msg);
+ /* remove and execute cancellation handlers */
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
+
+ return JOB_REQUEUE_NONE;
}
+
/**
* Implementation of private_stroke_interface_t.stroke_receive.
*/
-static void stroke_receive(private_stroke_interface_t *this)
+static job_requeue_t stroke_receive(private_stroke_interface_t *this)
{
struct sockaddr_un strokeaddr;
int strokeaddrlen = sizeof(strokeaddr);
+ int strokefd, *fdp;
int oldstate;
- int strokefd;
-
- charon->drop_capabilities(charon, TRUE);
+ callback_job_t *job;
- /* ignore sigpipe. writing over the pipe back to the console
- * only fails if SIGPIPE is ignored. */
- signal(SIGPIPE, SIG_IGN);
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+ strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
+ pthread_setcancelstate(oldstate, NULL);
- /* disable cancellation by default */
- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
-
- while (TRUE)
+ if (strokefd < 0)
{
- /* wait for connections, but allow thread to terminate */
- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
- strokefd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
- pthread_setcancelstate(oldstate, NULL);
-
- if (strokefd < 0)
- {
- DBG1(DBG_CFG, "accepting stroke connection failed: %s", strerror(errno));
- continue;
- }
- stroke_process(this, strokefd);
+ DBG1(DBG_CFG, "accepting stroke connection failed: %s", strerror(errno));
+ return JOB_REQUEUE_FAIR;
}
+
+ fdp = malloc_thing(int);
+ *fdp = strokefd;
+ job = callback_job_create((callback_job_cb_t)stroke_process, fdp, free, this->job);
+ charon->processor->queue_job(charon->processor, (job_t*)job);
+
+ return JOB_REQUEUE_FAIR;
}
/**
@@ -1662,17 +1653,9 @@ static void stroke_receive(private_stroke_interface_t *this)
*/
static void destroy(private_stroke_interface_t *this)
{
- int i;
-
- for (i = 0; i < STROKE_THREADS; i++)
- {
- pthread_cancel(this->threads[i]);
- pthread_join(this->threads[i], NULL);
- }
-
- close(this->socket);
- unlink(socket_addr.sun_path);
+ this->job->cancel(this->job);
free(this);
+ unlink(socket_addr.sun_path);
}
/*
@@ -1682,7 +1665,6 @@ interface_t *interface_create()
{
private_stroke_interface_t *this = malloc_thing(private_stroke_interface_t);
mode_t old;
- int i;
/* public functions */
this->public.interface.destroy = (void (*)(interface_t*))destroy;
@@ -1715,14 +1697,10 @@ interface_t *interface_create()
return NULL;
}
- /* start threads reading from the socket */
- for (i = 0; i < STROKE_THREADS; i++)
- {
- if (pthread_create(&this->threads[i], NULL, (void*(*)(void*))stroke_receive, this) != 0)
- {
- charon->kill(charon, "unable to create stroke thread");
- }
- }
+ this->job = callback_job_create((callback_job_cb_t)stroke_receive,
+ this, NULL, NULL);
+ charon->processor->queue_job(charon->processor, (job_t*)this->job);
return &this->public.interface;
}
+
diff --git a/src/charon/control/interfaces/xml_interface.c b/src/charon/control/interfaces/xml_interface.c
index e570f2543..992377436 100644
--- a/src/charon/control/interfaces/xml_interface.c
+++ b/src/charon/control/interfaces/xml_interface.c
@@ -24,8 +24,22 @@
#include "xml_interface.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <libxml/xmlreader.h>
+#include <libxml/xmlwriter.h>
+
#include <library.h>
#include <daemon.h>
+#include <processing/jobs/callback_job.h>
+
+static struct sockaddr_un socket_addr = { AF_UNIX, "/var/run/charon.xml"};
typedef struct private_xml_interface_t private_xml_interface_t;
@@ -39,14 +53,166 @@ struct private_xml_interface_t {
* Public part of xml_t object.
*/
xml_interface_t public;
+
+ /**
+ * XML unix socket fd
+ */
+ int socket;
+
+ /**
+ * job accepting stroke messages
+ */
+ callback_job_t *job;
};
+/**
+ * process a getRequest message
+ */
+static void process_get(xmlTextReaderPtr reader, xmlTextWriterPtr writer)
+{
+ if (/* <GetResponse> */
+ xmlTextWriterStartElement(writer, "GetResponse") < 0 ||
+ /* <Status Code="200"><Message/></Status> */
+ xmlTextWriterStartElement(writer, "Status") < 0 ||
+ xmlTextWriterWriteAttribute(writer, "Code", "200") < 0 ||
+ xmlTextWriterStartElement(writer, "Message") < 0 ||
+ xmlTextWriterEndElement(writer) < 0 ||
+ xmlTextWriterEndElement(writer) < 0 ||
+ /* <ConnectionList/> */
+ xmlTextWriterStartElement(writer, "ConnectionList") < 0 ||
+ xmlTextWriterEndElement(writer) < 0 ||
+ /* </GetResponse> */
+ xmlTextWriterEndElement(writer) < 0)
+ {
+ DBG1(DBG_CFG, "error writing XML document (GetResponse)");
+ }
+}
+
+/**
+ * read from a opened connection and process it
+ */
+static job_requeue_t process(int *fdp)
+{
+ int oldstate, fd = *fdp;
+ char buffer[4096];
+ size_t len;
+ xmlTextReaderPtr reader;
+ xmlTextWriterPtr writer;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+ len = read(fd, buffer, sizeof(buffer));
+ pthread_setcancelstate(oldstate, NULL);
+ if (len <= 0)
+ {
+ close(fd);
+ DBG2(DBG_CFG, "SMP XML connection closed");
+ return JOB_REQUEUE_NONE;
+ }
+
+ reader = xmlReaderForMemory(buffer, len, NULL, NULL, 0);
+ if (reader == NULL)
+ {
+ DBG1(DBG_CFG, "opening SMP XML reader failed");
+ return JOB_REQUEUE_FAIR;;
+ }
+
+ writer = xmlNewTextWriter(xmlOutputBufferCreateFd(fd, NULL));
+ if (writer == NULL)
+ {
+ xmlFreeTextReader(reader);
+ DBG1(DBG_CFG, "opening SMP XML writer failed");
+ return JOB_REQUEUE_FAIR;;
+ }
+
+ /* create the standard message parts */
+ if (xmlTextWriterStartDocument(writer, NULL, NULL, NULL) < 0 ||
+ /* <SMPMessage xmlns="http://www.strongswan.org/smp/1.0"> */
+ xmlTextWriterStartElement(writer, "SMPMessage") < 0 ||
+ xmlTextWriterWriteAttribute(writer, "xmlns",
+ "http://www.strongswan.org/smp/1.0") < 0 ||
+ /* <Body> */
+ xmlTextWriterStartElement(writer, "Body") < 0)
+ {
+ xmlFreeTextReader(reader);
+ xmlFreeTextWriter(writer);
+ DBG1(DBG_CFG, "creating SMP XML message failed");
+ return JOB_REQUEUE_FAIR;;
+ }
+
+ while (TRUE)
+ {
+ switch (xmlTextReaderRead(reader))
+ {
+ case 1:
+ {
+ if (xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT)
+ {
+ if (streq(xmlTextReaderConstName(reader), "GetRequest"))
+ {
+ process_get(reader, writer);
+ break;
+ }
+ }
+ continue;
+ }
+ case 0:
+ /* end of XML */
+ break;
+ default:
+ DBG1(DBG_CFG, "parsing SMP XML message failed");
+ break;
+ }
+ xmlFreeTextReader(reader);
+ break;
+ }
+ /* write </Body></SMPMessage> and close document */
+ if (xmlTextWriterEndDocument(writer) < 0)
+ {
+ DBG1(DBG_CFG, "completing SMP XML message failed");
+ }
+ xmlFreeTextWriter(writer);
+
+ /* write a newline to indicate end of xml */
+ write(fd, "\n", 1);
+ return JOB_REQUEUE_FAIR;;
+}
+
+/**
+ * accept from XML socket and create jobs to process connections
+ */
+static job_requeue_t dispatch(private_xml_interface_t *this)
+{
+ struct sockaddr_un strokeaddr;
+ int oldstate, fd, *fdp, strokeaddrlen = sizeof(strokeaddr);
+ callback_job_t *job;
+
+ /* wait for connections, but allow thread to terminate */
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+ fd = accept(this->socket, (struct sockaddr *)&strokeaddr, &strokeaddrlen);
+ pthread_setcancelstate(oldstate, NULL);
+
+ if (fd < 0)
+ {
+ DBG1(DBG_CFG, "accepting SMP XML socket failed: %s", strerror(errno));
+ sleep(1);
+ return JOB_REQUEUE_FAIR;;
+ }
+
+ fdp = malloc_thing(int);
+ *fdp = fd;
+ job = callback_job_create((callback_job_cb_t)process, fdp, free, this->job);
+ charon->processor->queue_job(charon->processor, (job_t*)job);
+
+ return JOB_REQUEUE_DIRECT;
+}
/**
* Implementation of itnerface_t.destroy.
*/
static void destroy(private_xml_interface_t *this)
{
+ this->job->cancel(this->job);
+ unlink(socket_addr.sun_path);
free(this);
}
@@ -56,8 +222,40 @@ static void destroy(private_xml_interface_t *this)
interface_t *interface_create()
{
private_xml_interface_t *this = malloc_thing(private_xml_interface_t);
+ mode_t old;
- this->public.interface.destroy = (void (*)(xml_interface_t*))destroy;
+ this->public.interface.destroy = (void (*)(interface_t*))destroy;
+
+ /* set up unix socket */
+ this->socket = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (this->socket == -1)
+ {
+ DBG1(DBG_CFG, "could not create XML socket");
+ free(this);
+ return NULL;
+ }
+
+ old = umask(~S_IRWXU);
+ if (bind(this->socket, (struct sockaddr *)&socket_addr, sizeof(socket_addr)) < 0)
+ {
+ DBG1(DBG_CFG, "could not bind XML socket: %s", strerror(errno));
+ close(this->socket);
+ free(this);
+ return NULL;
+ }
+ umask(old);
+
+ if (listen(this->socket, 0) < 0)
+ {
+ DBG1(DBG_CFG, "could not listen on XML socket: %s", strerror(errno));
+ close(this->socket);
+ free(this);
+ return NULL;
+ }
+
+ this->job = callback_job_create((callback_job_cb_t)dispatch, this, NULL, NULL);
+ charon->processor->queue_job(charon->processor, (job_t*)this->job);
return &this->public.interface;
}
+
diff --git a/src/charon/daemon.c b/src/charon/daemon.c
index 62e29b365..37699f83f 100644
--- a/src/charon/daemon.c
+++ b/src/charon/daemon.c
@@ -115,25 +115,26 @@ static void dbg_stderr(int level, char *fmt, ...)
*/
static void run(private_daemon_t *this)
{
- /* reselect signals for this thread */
- sigemptyset(&(this->signal_set));
- sigaddset(&(this->signal_set), SIGINT);
- sigaddset(&(this->signal_set), SIGHUP);
- sigaddset(&(this->signal_set), SIGTERM);
- pthread_sigmask(SIG_BLOCK, &(this->signal_set), 0);
-
- while(TRUE)
+ sigset_t set;
+
+ /* handle SIGINT, SIGHUP ans SIGTERM in this handler */
+ sigemptyset(&set);
+ sigaddset(&set, SIGINT);
+ sigaddset(&set, SIGHUP);
+ sigaddset(&set, SIGTERM);
+
+ while (TRUE)
{
- int signal_number;
+ int sig;
int error;
- error = sigwait(&(this->signal_set), &signal_number);
- if(error)
+ error = sigwait(&set, &sig);
+ if (error)
{
DBG1(DBG_DMN, "error %d while waiting for a signal", error);
return;
}
- switch (signal_number)
+ switch (sig)
{
case SIGHUP:
{
@@ -146,11 +147,13 @@ static void run(private_daemon_t *this)
return;
}
case SIGTERM:
+ {
DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down");
return;
+ }
default:
{
- DBG1(DBG_DMN, "unknown signal %d received. Ignored", signal_number);
+ DBG1(DBG_DMN, "unknown signal %d received. Ignored", sig);
break;
}
}
@@ -162,33 +165,22 @@ static void run(private_daemon_t *this)
*/
static void destroy(private_daemon_t *this)
{
- /* destruction is a non trivial task, we need to follow
- * a strict order to prevent threading issues!
- * Kill active threads first, except the sender, as
- * the killed IKE_SA want to send delete messages.
- */
- /* we don't want to receive anything anymore... */
- DESTROY_IF(this->public.receiver);
- /* ignore all incoming user requests */
- DESTROY_IF(this->public.interfaces);
- /* stop scheduing jobs */
- DESTROY_IF(this->public.scheduler);
- /* stop processing jobs */
- DESTROY_IF(this->public.thread_pool);
- /* shut down manager with all IKE SAs */
+ /* terminate all idle threads */
+ this->public.processor->set_threads(this->public.processor, 0);
+ /* close all IKE_SAs */
DESTROY_IF(this->public.ike_sa_manager);
- /* all child SAs should be down now, so kill kernel interface */
- DESTROY_IF(this->public.kernel_interface);
- /* destroy other infrastructure */
- DESTROY_IF(this->public.job_queue);
- DESTROY_IF(this->public.event_queue);
- DESTROY_IF(this->public.credentials);
+ DESTROY_IF(this->public.scheduler);
+ DESTROY_IF(this->public.interfaces);
DESTROY_IF(this->public.backends);
- /* we hope the sender could send the outstanding deletes, but
- * we shut down here at any cost */
+ DESTROY_IF(this->public.credentials);
+ DESTROY_IF(this->public.kernel_interface);
DESTROY_IF(this->public.sender);
+ DESTROY_IF(this->public.receiver);
DESTROY_IF(this->public.socket);
- /* before destroying bus with its listeners, rehook library logs */
+ /* wait until all threads are gone */
+ DESTROY_IF(this->public.processor);
+
+ /* rehook library logging, shutdown logging */
dbg = dbg_stderr;
DESTROY_IF(this->public.bus);
DESTROY_IF(this->public.outlog);
@@ -197,7 +189,6 @@ static void destroy(private_daemon_t *this)
free(this);
}
-
/**
* Enforce daemon shutdown, with a given reason to do so.
*/
@@ -228,6 +219,7 @@ static void drop_capabilities(private_daemon_t *this, bool full)
{
struct __user_cap_header_struct hdr;
struct __user_cap_data_struct data;
+
/* CAP_NET_ADMIN is needed to use netlink */
u_int32_t keep = (1<<CAP_NET_ADMIN);
@@ -242,11 +234,11 @@ static void drop_capabilities(private_daemon_t *this, bool full)
}
else
{
- /* CAP_NET_BIND_SERVICE to bind services below port 1024,
- * CAP_NET_RAW to create RAW sockets.
- * CAP_DAC_READ_SEARCH is needed to read ipsec.secrets */
+ /* CAP_NET_BIND_SERVICE to bind services below port 1024 */
keep |= (1<<CAP_NET_BIND_SERVICE);
+ /* CAP_NET_RAW to create RAW sockets */
keep |= (1<<CAP_NET_RAW);
+ /* CAP_DAC_READ_SEARCH to read ipsec.secrets */
keep |= (1<<CAP_DAC_READ_SEARCH);
}
@@ -257,7 +249,7 @@ static void drop_capabilities(private_daemon_t *this, bool full)
if (capset(&hdr, &data))
{
- kill_daemon(this, "unable to drop threads capabilities");
+ kill_daemon(this, "unable to drop daemon capabilities");
}
}
@@ -266,7 +258,6 @@ static void drop_capabilities(private_daemon_t *this, bool full)
*/
static void initialize(private_daemon_t *this, bool syslog, level_t levels[])
{
- credential_store_t* credentials;
signal_t signal;
/* for uncritical pseudo random numbers */
@@ -298,38 +289,32 @@ static void initialize(private_daemon_t *this, bool syslog, level_t levels[])
DBG1(DBG_DMN, "starting charon (strongSwan Version %s)", VERSION);
- this->public.socket = socket_create(IKEV2_UDP_PORT, IKEV2_NATT_PORT);
this->public.ike_sa_manager = ike_sa_manager_create();
- this->public.job_queue = job_queue_create();
- this->public.event_queue = event_queue_create();
- this->public.credentials = (credential_store_t*)local_credential_store_create();
- this->public.backends = backend_manager_create();
-
- /* initialize fetcher_t class */
- fetcher_initialize();
+ this->public.processor = processor_create();
+ this->public.scheduler = scheduler_create();
/* load secrets, ca certificates and crls */
- credentials = this->public.credentials;
- credentials->load_ca_certificates(credentials);
- credentials->load_aa_certificates(credentials);
- credentials->load_attr_certificates(credentials);
- credentials->load_ocsp_certificates(credentials);
- credentials->load_crls(credentials);
- credentials->load_secrets(credentials);
-
- /* start building threads, we are multi-threaded NOW */
+ this->public.credentials = (credential_store_t*)local_credential_store_create();
+ this->public.credentials->load_ca_certificates(this->public.credentials);
+ this->public.credentials->load_aa_certificates(this->public.credentials);
+ this->public.credentials->load_attr_certificates(this->public.credentials);
+ this->public.credentials->load_ocsp_certificates(this->public.credentials);
+ this->public.credentials->load_crls(this->public.credentials);
+ this->public.credentials->load_secrets(this->public.credentials);
+
this->public.interfaces = interface_manager_create();
+ this->public.backends = backend_manager_create();
+ this->public.kernel_interface = kernel_interface_create();
+ this->public.socket = socket_create(IKEV2_UDP_PORT, IKEV2_NATT_PORT);
this->public.sender = sender_create();
this->public.receiver = receiver_create();
- this->public.scheduler = scheduler_create();
- this->public.kernel_interface = kernel_interface_create();
- this->public.thread_pool = thread_pool_create(NUMBER_OF_WORKING_THREADS);
+
}
/**
* Handle SIGSEGV/SIGILL signals raised by threads
*/
-void signal_handler(int signal)
+static void segv_handler(int signal)
{
#ifdef HAVE_BACKTRACE
void *array[20];
@@ -340,7 +325,7 @@ void signal_handler(int signal)
size = backtrace(array, 20);
strings = backtrace_symbols(array, size);
- DBG1(DBG_DMN, "thread %u received %s. Dumping %d frames from stack:",
+ DBG1(DBG_JOB, "thread %u received %s. Dumping %d frames from stack:",
pthread_self(), signal == SIGSEGV ? "SIGSEGV" : "SIGILL", size);
for (i = 0; i < size; i++)
@@ -352,7 +337,7 @@ void signal_handler(int signal)
DBG1(DBG_DMN, "thread %u received %s",
pthread_self(), signal == SIGSEGV ? "SIGSEGV" : "SIGILL");
#endif /* HAVE_BACKTRACE */
- DBG1(DBG_DMN, "killing ourself hard after SIGSEGV");
+ DBG1(DBG_DMN, "killing ourself, received critical signal");
raise(SIGKILL);
}
@@ -361,25 +346,22 @@ void signal_handler(int signal)
*/
private_daemon_t *daemon_create(void)
{
- private_daemon_t *this = malloc_thing(private_daemon_t);
struct sigaction action;
+ private_daemon_t *this = malloc_thing(private_daemon_t);
/* assign methods */
this->public.kill = (void (*) (daemon_t*,char*))kill_daemon;
- this->public.drop_capabilities = (void(*)(daemon_t*,bool))drop_capabilities;
/* NULL members for clean destruction */
this->public.socket = NULL;
this->public.ike_sa_manager = NULL;
- this->public.job_queue = NULL;
- this->public.event_queue = NULL;
this->public.credentials = NULL;
this->public.backends = NULL;
this->public.sender= NULL;
this->public.receiver = NULL;
this->public.scheduler = NULL;
this->public.kernel_interface = NULL;
- this->public.thread_pool = NULL;
+ this->public.processor = NULL;
this->public.interfaces = NULL;
this->public.bus = NULL;
this->public.outlog = NULL;
@@ -388,20 +370,22 @@ private_daemon_t *daemon_create(void)
this->main_thread_id = pthread_self();
- /* setup signal handling for all threads */
- sigemptyset(&(this->signal_set));
- sigaddset(&(this->signal_set), SIGSEGV);
- sigaddset(&(this->signal_set), SIGINT);
- sigaddset(&(this->signal_set), SIGHUP);
- sigaddset(&(this->signal_set), SIGTERM);
- pthread_sigmask(SIG_BLOCK, &(this->signal_set), 0);
-
- /* setup SIGSEGV handler for all threads */
- action.sa_handler = signal_handler;
- action.sa_mask = this->signal_set;
+ /* add handler for SEGV and ILL,
+ * add handler for USR1 (cancellation).
+ * INT, TERM and HUP are handled by sigwait() in run() */
+ action.sa_handler = segv_handler;
action.sa_flags = 0;
+ sigemptyset(&action.sa_mask);
+ sigaddset(&action.sa_mask, SIGINT);
+ sigaddset(&action.sa_mask, SIGTERM);
+ sigaddset(&action.sa_mask, SIGHUP);
sigaction(SIGSEGV, &action, NULL);
sigaction(SIGILL, &action, NULL);
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+
+ pthread_sigmask(SIG_SETMASK, &action.sa_mask, 0);
+
return this;
}
@@ -445,15 +429,15 @@ int main(int argc, char *argv[])
private_daemon_t *private_charon;
FILE *pid_file;
struct stat stb;
- linked_list_t *list;
- host_t *host;
level_t levels[DBG_MAX];
int signal;
- prctl(PR_SET_KEEPCAPS, 1);
+ private_charon = daemon_create();
+ charon = (daemon_t*)private_charon;
- /* drop the capabilities we won't need at all */
- drop_capabilities(NULL, FALSE);
+ /* drop the capabilities we won't need for initialization */
+ prctl(PR_SET_KEEPCAPS, 1);
+ drop_capabilities(private_charon, FALSE);
/* use CTRL loglevel for default */
for (signal = 0; signal < DBG_MAX; signal++)
@@ -522,13 +506,11 @@ int main(int argc, char *argv[])
}
break;
}
-
- private_charon = daemon_create();
- charon = (daemon_t*)private_charon;
/* initialize daemon */
initialize(private_charon, use_syslog, levels);
-
+ /* initialize fetcher_t class */
+ fetcher_initialize();
/* load pluggable EAP modules */
eap_method_load(eapdir);
@@ -549,19 +531,12 @@ int main(int argc, char *argv[])
fclose(pid_file);
}
- /* log socket info */
- list = charon->kernel_interface->create_address_list(charon->kernel_interface);
- DBG1(DBG_NET, "listening on %d addresses:", list->get_count(list));
- while (list->remove_first(list, (void**)&host) == SUCCESS)
- {
- DBG1(DBG_NET, " %H", host);
- host->destroy(host);
- }
- list->destroy(list);
-
/* drop additional capabilites (bind & root) */
drop_capabilities(private_charon, TRUE);
+ /* start the engine, go multithreaded */
+ charon->processor->set_threads(charon->processor, WORKER_THREADS);
+
/* run daemon */
run(private_charon);
diff --git a/src/charon/daemon.h b/src/charon/daemon.h
index 640bc6a09..0b5205ce7 100644
--- a/src/charon/daemon.h
+++ b/src/charon/daemon.h
@@ -33,9 +33,7 @@ typedef struct daemon_t daemon_t;
#include <network/receiver.h>
#include <network/socket.h>
#include <processing/scheduler.h>
-#include <processing/thread_pool.h>
-#include <processing/job_queue.h>
-#include <processing/event_queue.h>
+#include <processing/processor.h>
#include <kernel/kernel_interface.h>
#include <control/interface_manager.h>
#include <bus/bus.h>
@@ -49,50 +47,73 @@ typedef struct daemon_t daemon_t;
*
* @brief IKEv2 keying daemon.
*
- * @section Architecture
- *
* All IKEv2 stuff is handled in charon. It uses a newer and more flexible
- * architecture than pluto. Charon uses a thread-pool, which allows parallel
- * execution SA-management. Beside the thread-pool, there are some special purpose
- * threads which do their job for the common health of the daemon.
- @verbatim
- +------+
- | E Q |
- | v u |---+ +------+ +------+
- | e e | | | | | IKE- |
- | n u | +-----------+ | |--| SA |
- | t e | | | | I M | +------+
- +------------+ | - | | Scheduler | | K a |
- | receiver | +------+ | | | E n | +------+
- +----+-------+ +-----------+ | - a | | IKE- |
- | | +------+ | | S g |--| SA |
- +-------+--+ +-----| J Q |---+ +------------+ | A e | +------+
- -| socket | | o u | | | | - r |
- +-------+--+ | b e | | Thread- | | |
- | | - u | | Pool | | |
- +----+-------+ | e |------| |---| |
- | sender | +------+ +------------+ +------+
- +------------+
+ * architecture than pluto. Charon uses a thread-pool (called processor),
+ * which allows parallel execution SA-management. All threads originate
+ * from the processor. Work is delegated to the processor by queueing jobs
+ * to it.
+ @verbatim
+
+ +--------+ +-------+ +--------+ +-----------+ +-----------+
+ | Stroke | | XML | | DBUS | | Local | | SQLite |
+ +--------+ +-------+ +--------+ +-----------+ +-----------+
+ | | | | |
+ +---------------------------------+ +----------------------------+
+ | Interfaces | | Backends |
+ +---------------------------------+ +----------------------------+
+
+
+ +------------+ +-----------+ +------+ +----------+
+ | receiver | | | | | +------+ | CHILD_SA |
+ +----+-------+ | Scheduler | | IKE- | | IKE- |--+----------+
+ | | | | SA |--| SA | | CHILD_SA |
+ +-------+--+ +-----------+ | | +------+ +----------+
+ <->| socket | | | Man- |
+ +-------+--+ +-----------+ | ager | +------+ +----------+
+ | | | | | | IKE- |--| CHILD_SA |
+ +----+-------+ | Processor |--------| |--| SA | +----------+
+ | sender | | | | | +------+
+ +------------+ +-----------+ +------+
+
+
+ +---------------------------------+ +----------------------------+
+ | Bus | | Kernel Interface |
+ +---------------------------------+ +----------------------------+
+ | | |
+ +-------------+ +-------------+ V
+ | File-Logger | | Sys-Logger | //////
+ +-------------+ +-------------+
+
@endverbatim
- * The thread-pool is the heart of the architecture. It processes jobs from a
- * (fully synchronized) job-queue. Mostly, a job is associated with a specific
- * IKE SA. These IKE SAs are synchronized, only one thread can work one an IKE SA.
- * This makes it unnecesary to use further synchronisation methods once a IKE SA
- * is checked out. The (rather complex) synchronization of IKE SAs is completely
- * done in the IKE SA manager.
- * The sceduler is responsible for event firing. It waits until a event in the
- * (fully synchronized) event-queue is ready for processing and pushes the event
- * down to the job-queue. A thread form the pool will pick it up as quick as
- * possible. Every thread can queue events or jobs. Furter, an event can place a
- * packet in the sender. The sender thread waits for those packets and sends
- * them over the wire, via the socket. The receiver does exactly the opposite of
- * the sender. It waits on the socket, reads in packets an places them on the
- * job-queue for further processing by a thread from the pool.
- * There are even more threads, not drawn in the upper scheme. The stroke thread
- * is responsible for reading and processessing commands from another process. The
- * kernel interface thread handles communication from and to the kernel via a
- * netlink socket. It waits for kernel events and processes them appropriately.
+ * The scheduler is responsible to execute timed events. Jobs may be queued to
+ * the scheduler to get executed at a defined time (e.g. rekeying). The scheduler
+ * does not execute the jobs itself, it queues them to the processor.
+ *
+ * The IKE_SA manager managers all IKE_SA. It further handles the synchronization:
+ * Each IKE_SA must be checked out strictly and checked in again after use. The
+ * manager guarantees that only one thread may check out a single IKE_SA. This allows
+ * us to write the (complex) IKE_SAs routines non-threadsave.
+ * The IKE_SA contain the state and the logic of each IKE_SA and handle the messages.
+ *
+ * The CHILD_SA contains state about a IPsec security association and manages them.
+ * An IKE_SA may have multiple CHILD_SAs. Communication to the kernel takes place
+ * here through the kernel interface.
+ *
+ * The kernel interface installs IPsec security associations, policies routes and
+ * virtual addresses. It further provides methods to enumerate interfaces and may notify
+ * the daemon about state changes at lower layers.
+ *
+ * The bus receives signals from the different threads and relais them to interested
+ * listeners. Debugging signals, but also important state changes or error messages are
+ * sent over the bus.
+ * It's listeners are not only for logging, but also to track the state of an IKE_SA.
+ *
+ * The interface manager loads pluggable controlling interfaces. These are written to control
+ * the daemon from external inputs (e.g. initiate IKE_SA, close IKE_SA, ...). The interface
+ * manager further provides a simple API to establish these tasks.
+ * Backends are pluggable modules which provide configuration. They have to implement an API
+ * which the daemon core uses to get configuration.
*/
/**
@@ -234,12 +255,9 @@ typedef struct daemon_t daemon_t;
/**
* @brief Number of threads in the thread pool.
*
- * There are several other threads, this defines
- * only the number of threads in thread_pool_t.
- *
* @ingroup charon
*/
-#define NUMBER_OF_WORKING_THREADS 4
+#define WORKER_THREADS 16
/**
* UDP Port on which the daemon will listen for incoming traffic.
@@ -338,20 +356,11 @@ typedef struct daemon_t daemon_t;
* @ingroup charon
*/
struct daemon_t {
+
/**
* A socket_t instance.
*/
socket_t *socket;
-
- /**
- * A job_queue_t instance.
- */
- job_queue_t *job_queue;
-
- /**
- * A event_queue_t instance.
- */
- event_queue_t *event_queue;
/**
* A ike_sa_manager_t instance.
@@ -384,9 +393,9 @@ struct daemon_t {
scheduler_t *scheduler;
/**
- * The Thread pool managing the worker threads.
+ * Job processing using a thread pool.
*/
- thread_pool_t *thread_pool;
+ processor_t *processor;
/**
* The signaling bus.
@@ -419,14 +428,6 @@ struct daemon_t {
interface_manager_t *interfaces;
/**
- * @brief Let the calling thread drop its capabilities.
- *
- * @param this calling daemon
- * @param full TRUE to drop as many as possible
- */
- void (*drop_capabilities) (daemon_t *this, bool full);
-
- /**
* @brief Shut down the daemon.
*
* @param this the daemon to kill
diff --git a/src/charon/encoding/message.c b/src/charon/encoding/message.c
index b31b21afa..980ff12b5 100644
--- a/src/charon/encoding/message.c
+++ b/src/charon/encoding/message.c
@@ -611,9 +611,13 @@ static char* get_string(private_message_t *this, char *buf, int len)
int written;
char *pos = buf;
- written = snprintf(pos, len, "%N %s [",
- exchange_type_names, this->exchange_type,
- this->is_request ? "request" : "response");
+ memset(buf, 0, len);
+ len--;
+
+ written = snprintf(pos, len, "%N %s %d [",
+ exchange_type_names, this->exchange_type,
+ this->is_request ? "request" : "response",
+ this->message_id);
if (written >= len || written < 0)
{
return "";
@@ -621,16 +625,10 @@ static char* get_string(private_message_t *this, char *buf, int len)
pos += written;
len -= written;
- if (this->payloads->get_count(this->payloads) == 0)
- {
- snprintf(pos, len, "]");
- return buf;
- }
-
iterator = this->payloads->create_iterator(this->payloads, TRUE);
while (iterator->iterate(iterator, (void**)&payload))
{
- written = snprintf(pos, len, "%N ", payload_type_short_names,
+ written = snprintf(pos, len, " %N", payload_type_short_names,
payload->get_type(payload));
if (written >= len || written < 0)
{
@@ -638,13 +636,23 @@ static char* get_string(private_message_t *this, char *buf, int len)
}
pos += written;
len -= written;
+ if (payload->get_type(payload) == NOTIFY)
+ {
+ notify_payload_t *notify = (notify_payload_t*)payload;
+ written = snprintf(pos, len, "(%N)", notify_type_short_names,
+ notify->get_notify_type(notify));
+ if (written >= len || written < 0)
+ {
+ return buf;
+ }
+ pos += written;
+ len -= written;
+ }
}
iterator->destroy(iterator);
/* remove last space */
- pos--;
- len++;
- snprintf(pos, len, "]");
+ snprintf(pos, len, " ]");
return buf;
}
@@ -734,7 +742,7 @@ static status_t generate(private_message_t *this, crypter_t *crypter, signer_t*
iterator_t *iterator;
status_t status;
chunk_t packet_data;
- char str[128];
+ char str[256];
if (is_encoded(this))
{
@@ -1140,7 +1148,7 @@ static status_t parse_body(private_message_t *this, crypter_t *crypter, signer_t
{
status_t status = SUCCESS;
payload_type_t current_payload_type;
- char str[128];
+ char str[256];
current_payload_type = this->first_payload;
diff --git a/src/charon/encoding/payloads/notify_payload.c b/src/charon/encoding/payloads/notify_payload.c
index a04901a90..e27d3c68f 100644
--- a/src/charon/encoding/payloads/notify_payload.c
+++ b/src/charon/encoding/payloads/notify_payload.c
@@ -47,14 +47,16 @@ ENUM_NEXT(notify_type_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL
"INVALID_KE_PAYLOAD");
ENUM_NEXT(notify_type_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD,
"AUTHENTICATION_FAILED");
-ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, INVALID_SELECTORS, AUTHENTICATION_FAILED,
+ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, UNEXPECTED_NAT_DETECTED, AUTHENTICATION_FAILED,
"SINGLE_PAIR_REQUIRED",
"NO_ADDITIONAL_SAS",
"INTERNAL_ADDRESS_FAILURE",
"FAILED_CP_REQUIRED",
"TS_UNACCEPTABLE",
- "INVALID_SELECTORS");
-ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, INVALID_SELECTORS,
+ "INVALID_SELECTORS",
+ "UNACCEPTABLE_ADDRESSES",
+ "UNEXPECTED_NAT_DETECTED");
+ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NAT_DETECTED,
"INITIAL_CONTACT",
"SET_WINDOW_SIZE",
"ADDITIONAL_TS_POSSIBLE",
@@ -79,6 +81,59 @@ ENUM_NEXT(notify_type_names, EAP_ONLY_AUTHENTICATION, EAP_ONLY_AUTHENTICATION, A
"EAP_ONLY_AUTHENTICATION");
ENUM_END(notify_type_names, EAP_ONLY_AUTHENTICATION);
+
+ENUM_BEGIN(notify_type_short_names, UNSUPPORTED_CRITICAL_PAYLOAD, UNSUPPORTED_CRITICAL_PAYLOAD,
+ "CRIT");
+ENUM_NEXT(notify_type_short_names, INVALID_IKE_SPI, INVALID_MAJOR_VERSION, UNSUPPORTED_CRITICAL_PAYLOAD,
+ "INVAL_IKE_SPI",
+ "INVAL_MAJOR");
+ENUM_NEXT(notify_type_short_names, INVALID_SYNTAX, INVALID_SYNTAX, INVALID_MAJOR_VERSION,
+ "INVAL_SYN");
+ENUM_NEXT(notify_type_short_names, INVALID_MESSAGE_ID, INVALID_MESSAGE_ID, INVALID_SYNTAX,
+ "INVAL_MID");
+ENUM_NEXT(notify_type_short_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID,
+ "INVAL_SPI");
+ENUM_NEXT(notify_type_short_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI,
+ "NO_PROP");
+ENUM_NEXT(notify_type_short_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN,
+ "INVAL_KE");
+ENUM_NEXT(notify_type_short_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD,
+ "AUTH_FAILED");
+ENUM_NEXT(notify_type_short_names, SINGLE_PAIR_REQUIRED, UNEXPECTED_NAT_DETECTED, AUTHENTICATION_FAILED,
+ "SINGLE_PAIR",
+ "NO_ADD_SAS",
+ "INT_ADDR_FAIL",
+ "FAIL_CP_REQ",
+ "TS_UNACCEPT",
+ "INVAL_SEL",
+ "UNACCEPT_ADDR",
+ "UNEXPECT_NAT");
+ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NAT_DETECTED,
+ "INIT_CONTACT",
+ "SET_WINSIZE",
+ "ADD_TS_POSS",
+ "IPCOMP_SUPP",
+ "NATD_S_IP",
+ "NATD_D_IP",
+ "COOKIE",
+ "USE_TRANSP",
+ "HTTP_CERT_LOOK",
+ "REKEY_SA",
+ "ESP_TFC_PAD_N",
+ "NON_FIRST_FRAG",
+ "MOBIKE_SUP",
+ "ADD_4_ADDR",
+ "ADD_6_ADDR",
+ "NO_ADD_ADDR",
+ "UPD_SA_ADDR",
+ "COOKIE2",
+ "NO_NATS",
+ "AUTH_LFT");
+ENUM_NEXT(notify_type_short_names, EAP_ONLY_AUTHENTICATION, EAP_ONLY_AUTHENTICATION, AUTH_LIFETIME,
+ "EAP_ONLY");
+ENUM_END(notify_type_short_names, EAP_ONLY_AUTHENTICATION);
+
+
typedef struct private_notify_payload_t private_notify_payload_t;
/**
@@ -189,6 +244,8 @@ encoding_rule_t notify_payload_encodings[] = {
*/
static status_t verify(private_notify_payload_t *this)
{
+ bool bad_length = FALSE;
+
switch (this->protocol_id)
{
case PROTO_NONE:
@@ -205,30 +262,9 @@ static status_t verify(private_notify_payload_t *this)
{
case INVALID_KE_PAYLOAD:
{
- /* check notification data */
- diffie_hellman_group_t dh_group;
if (this->notification_data.len != 2)
{
- DBG1(DBG_ENC, "invalid notify data length for %N (%d)",
- notify_type_names, this->notify_type,
- this->notification_data.len);
- return FAILED;
- }
- dh_group = ntohs(*((u_int16_t*)this->notification_data.ptr));
- switch (dh_group)
- {
- case MODP_768_BIT:
- case MODP_1024_BIT:
- case MODP_1536_BIT:
- case MODP_2048_BIT:
- case MODP_3072_BIT:
- case MODP_4096_BIT:
- case MODP_6144_BIT:
- case MODP_8192_BIT:
- break;
- default:
- DBG1(DBG_ENC, "Bad DH group (%d)", dh_group);
- return FAILED;
+ bad_length = TRUE;
}
break;
}
@@ -237,9 +273,7 @@ static status_t verify(private_notify_payload_t *this)
{
if (this->notification_data.len != HASH_SIZE_SHA1)
{
- DBG1(DBG_ENC, "invalid %N notify length",
- notify_type_names, this->notify_type);
- return FAILED;
+ bad_length = TRUE;
}
break;
}
@@ -249,9 +283,23 @@ static status_t verify(private_notify_payload_t *this)
{
if (this->notification_data.len != 0)
{
- DBG1(DBG_ENC, "invalid %N notify",
- notify_type_names, this->notify_type);
- return FAILED;
+ bad_length = TRUE;
+ }
+ break;
+ }
+ case ADDITIONAL_IP4_ADDRESS:
+ {
+ if (this->notification_data.len != 4)
+ {
+ bad_length = TRUE;
+ }
+ break;
+ }
+ case ADDITIONAL_IP6_ADDRESS:
+ {
+ if (this->notification_data.len != 16)
+ {
+ bad_length = TRUE;
}
break;
}
@@ -259,6 +307,13 @@ static status_t verify(private_notify_payload_t *this)
/* TODO: verify */
break;
}
+ if (bad_length)
+ {
+ DBG1(DBG_ENC, "invalid notify data length for %N (%d)",
+ notify_type_names, this->notify_type,
+ this->notification_data.len);
+ return FAILED;
+ }
return SUCCESS;
}
diff --git a/src/charon/encoding/payloads/notify_payload.h b/src/charon/encoding/payloads/notify_payload.h
index 431932631..231d0408d 100644
--- a/src/charon/encoding/payloads/notify_payload.h
+++ b/src/charon/encoding/payloads/notify_payload.h
@@ -65,6 +65,8 @@ enum notify_type_t {
FAILED_CP_REQUIRED = 37,
TS_UNACCEPTABLE = 38,
INVALID_SELECTORS = 39,
+ UNACCEPTABLE_ADDRESSES = 40,
+ UNEXPECTED_NAT_DETECTED = 41,
/* notify status messages */
INITIAL_CONTACT = 16384,
SET_WINDOW_SIZE = 16385,
@@ -102,6 +104,13 @@ enum notify_type_t {
extern enum_name_t *notify_type_names;
/**
+ * enum name for notify_type_t (shorter strings).
+ *
+ * @ingroup payloads
+ */
+extern enum_name_t *notify_type_short_names;
+
+/**
* @brief Class representing an IKEv2-Notify Payload.
*
* The Notify Payload format is described in Draft section 3.10.
diff --git a/src/charon/kernel/kernel_interface.c b/src/charon/kernel/kernel_interface.c
index d82783b03..4770c7538 100644
--- a/src/charon/kernel/kernel_interface.c
+++ b/src/charon/kernel/kernel_interface.c
@@ -48,6 +48,8 @@
#include <processing/jobs/delete_child_sa_job.h>
#include <processing/jobs/rekey_child_sa_job.h>
#include <processing/jobs/acquire_job.h>
+#include <processing/jobs/callback_job.h>
+#include <processing/jobs/roam_job.h>
/** kernel level protocol identifiers */
#define KERNEL_ESP 50
@@ -156,7 +158,7 @@ char* lookup_algorithm(kernel_algorithm_t *kernel_algo,
}
kernel_algo++;
}
- return NULL;
+ return NULL;
}
typedef struct route_entry_t route_entry_t;
@@ -216,54 +218,61 @@ struct policy_entry_t {
u_int refcount;
};
-typedef struct vip_entry_t vip_entry_t;
+typedef struct addr_entry_t addr_entry_t;
/**
- * Installed virtual ip
+ * IP address in an inface_entry_t
*/
-struct vip_entry_t {
- /** Index of the interface the ip is bound to */
- u_int8_t if_index;
+struct addr_entry_t {
/** The ip address */
host_t *ip;
- /** Number of times this IP is used */
+ /** virtual IP managed by us */
+ bool virtual;
+
+ /** scope of the address */
+ u_char scope;
+
+ /** Number of times this IP is used, if virtual */
u_int refcount;
};
/**
- * destroy a vip_entry_t object
+ * destroy a addr_entry_t object
*/
-static void vip_entry_destroy(vip_entry_t *this)
+static void addr_entry_destroy(addr_entry_t *this)
{
this->ip->destroy(this->ip);
free(this);
}
-typedef struct address_entry_t address_entry_t;
+typedef struct iface_entry_t iface_entry_t;
/**
- * an address found on the system, containg address and interface info
+ * A network interface on this system, containing addr_entry_t's
*/
-struct address_entry_t {
-
- /** address of this entry */
- host_t *host;
+struct iface_entry_t {
/** interface index */
int ifindex;
- /** name of the index */
+ /** name of the interface */
char ifname[IFNAMSIZ];
+
+ /** interface flags, as in netdevice(7) SIOCGIFFLAGS */
+ u_int flags;
+
+ /** list of addresses as host_t */
+ linked_list_t *addrs;
};
/**
- * destroy an address entry
+ * destroy an interface entry
*/
-static void address_entry_destroy(address_entry_t *this)
+static void iface_entry_destroy(iface_entry_t *this)
{
- this->host->destroy(this->host);
+ this->addrs->destroy_function(this->addrs, (void*)addr_entry_destroy);
free(this);
}
@@ -279,29 +288,34 @@ struct private_kernel_interface_t {
kernel_interface_t public;
/**
- * List of installed policies (kernel_entry_t)
+ * mutex to lock access to the various lists
*/
- linked_list_t *policies;
+ pthread_mutex_t mutex;
/**
- * Mutex locks access to policies
+ * List of installed policies (policy_entry_t)
*/
- pthread_mutex_t policies_mutex;
+ linked_list_t *policies;
/**
- * List of installed virtual IPs. (vip_entry_t)
+ * Cached list of interfaces and its adresses (iface_entry_t)
*/
- linked_list_t *vips;
+ linked_list_t *ifaces;
/**
- * Mutex to lock access to vips.
+ * iterator used in hook()
+ */
+ iterator_t *hiter;
+
+ /**
+ * job receiving netlink events
*/
- pthread_mutex_t vips_mutex;
+ callback_job_t *job;
/**
- * netlink xfrm socket to receive acquire and expire events
+ * current sequence number for netlink request
*/
- int socket_xfrm_events;
+ int seq;
/**
* Netlink xfrm socket (IPsec)
@@ -309,14 +323,19 @@ struct private_kernel_interface_t {
int socket_xfrm;
/**
+ * netlink xfrm socket to receive acquire and expire events
+ */
+ int socket_xfrm_events;
+
+ /**
* Netlink rt socket (routing)
*/
int socket_rt;
/**
- * Thread receiving events from kernel
+ * Netlink rt socket to receive address change events
*/
- pthread_t event_thread;
+ int socket_rt_events;
};
/**
@@ -442,107 +461,382 @@ static void add_attribute(struct nlmsghdr *hdr, int rta_type, chunk_t data,
}
/**
- * Receives events from kernel
+ * process a XFRM_MSG_ACQUIRE from kernel
*/
-static void receive_events(private_kernel_interface_t *this)
+static void process_acquire(private_kernel_interface_t *this, struct nlmsghdr *hdr)
{
- charon->drop_capabilities(charon, TRUE);
+ u_int32_t reqid = 0;
+ job_t *job;
+ struct rtattr *rtattr = XFRM_RTA(hdr, struct xfrm_user_acquire);
+ size_t rtsize = XFRM_PAYLOAD(hdr, struct xfrm_user_tmpl);
+
+ if (RTA_OK(rtattr, rtsize))
+ {
+ if (rtattr->rta_type == XFRMA_TMPL)
+ {
+ struct xfrm_user_tmpl* tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rtattr);
+ reqid = tmpl->reqid;
+ }
+ }
+ if (reqid == 0)
+ {
+ DBG1(DBG_KNL, "received a XFRM_MSG_ACQUIRE, but no reqid found");
+ return;
+ }
+ DBG2(DBG_KNL, "received a XFRM_MSG_ACQUIRE");
+ DBG1(DBG_KNL, "creating acquire job for CHILD_SA with reqid %d", reqid);
+ job = (job_t*)acquire_job_create(reqid);
+ charon->processor->queue_job(charon->processor, job);
+}
- while(TRUE)
+/**
+ * process a XFRM_MSG_EXPIRE from kernel
+ */
+static void process_expire(private_kernel_interface_t *this, struct nlmsghdr *hdr)
+{
+ job_t *job;
+ protocol_id_t protocol;
+ u_int32_t spi, reqid;
+ struct xfrm_user_expire *expire;
+
+ expire = (struct xfrm_user_expire*)NLMSG_DATA(hdr);
+ protocol = expire->state.id.proto == KERNEL_ESP ? PROTO_ESP : PROTO_AH;
+ spi = expire->state.id.spi;
+ reqid = expire->state.reqid;
+
+ DBG2(DBG_KNL, "received a XFRM_MSG_EXPIRE");
+ DBG1(DBG_KNL, "creating %s job for %N CHILD_SA 0x%x (reqid %d)",
+ expire->hard ? "delete" : "rekey", protocol_id_names,
+ protocol, ntohl(spi), reqid);
+ if (expire->hard)
{
- unsigned char response[512];
- struct nlmsghdr *hdr;
- struct sockaddr_nl addr;
- socklen_t addr_len = sizeof(addr);
- int len;
-
- hdr = (struct nlmsghdr*)response;
- len = recvfrom(this->socket_xfrm_events, response, sizeof(response),
- 0, (struct sockaddr*)&addr, &addr_len);
- if (len < 0)
+ job = (job_t*)delete_child_sa_job_create(reqid, protocol, spi);
+ }
+ else
+ {
+ job = (job_t*)rekey_child_sa_job_create(reqid, protocol, spi);
+ }
+ charon->processor->queue_job(charon->processor, job);
+}
+
+/**
+ * process RTM_NEWLINK/RTM_DELLINK from kernel
+ */
+static void process_link(private_kernel_interface_t *this,
+ struct nlmsghdr *hdr, bool event)
+{
+ struct ifinfomsg* msg = (struct ifinfomsg*)(NLMSG_DATA(hdr));
+ struct rtattr *rta = IFLA_RTA(msg);
+ size_t rtasize = IFLA_PAYLOAD (hdr);
+ iterator_t *iterator;
+ iface_entry_t *current, *entry = NULL;
+ char *name = NULL;
+ bool update = FALSE;
+
+ while(RTA_OK(rta, rtasize))
+ {
+ switch (rta->rta_type)
{
- if (errno == EINTR)
+ case IFLA_IFNAME:
+ name = RTA_DATA(rta);
+ break;
+ }
+ rta = RTA_NEXT(rta, rtasize);
+ }
+ if (!name)
+ {
+ name = "(unknown)";
+ }
+
+ switch (hdr->nlmsg_type)
+ {
+ case RTM_NEWLINK:
+ {
+ if (msg->ifi_flags & IFF_LOOPBACK)
+ { /* ignore loopback interfaces */
+ break;
+ }
+ iterator = this->ifaces->create_iterator_locked(this->ifaces,
+ &this->mutex);
+ while (iterator->iterate(iterator, (void**)&current))
{
- /* interrupted, try again */
- continue;
+ if (current->ifindex == msg->ifi_index)
+ {
+ entry = current;
+ break;
+ }
+ }
+ if (!entry)
+ {
+ entry = malloc_thing(iface_entry_t);
+ entry->ifindex = msg->ifi_index;
+ entry->flags = 0;
+ entry->addrs = linked_list_create();
+ this->ifaces->insert_last(this->ifaces, entry);
+ }
+ memcpy(entry->ifname, name, IFNAMSIZ);
+ entry->ifname[IFNAMSIZ-1] = '\0';
+ if (event)
+ {
+ if (!(entry->flags & IFF_UP) && (msg->ifi_flags & IFF_UP))
+ {
+ update = TRUE;
+ DBG1(DBG_KNL, "interface %s activated", name);
+ }
+ if ((entry->flags & IFF_UP) && !(msg->ifi_flags & IFF_UP))
+ {
+ update = TRUE;
+ DBG1(DBG_KNL, "interface %s deactivated", name);
+ }
}
- charon->kill(charon, "unable to receive netlink events");
+ entry->flags = msg->ifi_flags;
+ iterator->destroy(iterator);
+ break;
}
-
- if (!NLMSG_OK(hdr, len))
+ case RTM_DELLINK:
{
- /* bad netlink message */
- continue;
+ iterator = this->ifaces->create_iterator_locked(this->ifaces,
+ &this->mutex);
+ while (iterator->iterate(iterator, (void**)&current))
+ {
+ if (current->ifindex == msg->ifi_index)
+ {
+ /* we do not remove it, as an address may be added to a
+ * "down" interface and we wan't to know that. */
+ current->flags = msg->ifi_flags;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ break;
}
+ }
+
+ /* send an update to all IKE_SAs */
+ if (update && event)
+ {
+ charon->processor->queue_job(charon->processor,
+ (job_t*)roam_job_create(TRUE));
+ }
+}
- if (addr.nl_pid != 0)
+/**
+ * process RTM_NEWADDR/RTM_DELADDR from kernel
+ */
+static void process_addr(private_kernel_interface_t *this,
+ struct nlmsghdr *hdr, bool event)
+{
+ struct ifaddrmsg* msg = (struct ifaddrmsg*)(NLMSG_DATA(hdr));
+ struct rtattr *rta = IFA_RTA(msg);
+ size_t rtasize = IFA_PAYLOAD (hdr);
+ host_t *host = NULL;
+ iterator_t *ifaces, *addrs;
+ iface_entry_t *iface;
+ addr_entry_t *addr;
+ chunk_t local = chunk_empty, address = chunk_empty;
+ bool update = FALSE, found = FALSE, changed = FALSE;
+
+ while(RTA_OK(rta, rtasize))
+ {
+ switch (rta->rta_type)
{
- /* not from kernel. not interested, try another one */
- continue;
+ case IFA_LOCAL:
+ local.ptr = RTA_DATA(rta);
+ local.len = RTA_PAYLOAD(rta);
+ break;
+ case IFA_ADDRESS:
+ address.ptr = RTA_DATA(rta);
+ address.len = RTA_PAYLOAD(rta);
+ break;
}
-
- /* we handle ACQUIRE and EXPIRE messages directly */
- if (hdr->nlmsg_type == XFRM_MSG_ACQUIRE)
+ rta = RTA_NEXT(rta, rtasize);
+ }
+
+ /* For PPP interfaces, we need the IFA_LOCAL address,
+ * IFA_ADDRESS is the peers address. But IFA_LOCAL is
+ * not included in all cases (IPv6?), so fallback to IFA_ADDRESS. */
+ if (local.ptr)
+ {
+ host = host_create_from_chunk(msg->ifa_family, local, 0);
+ }
+ else if (address.ptr)
+ {
+ host = host_create_from_chunk(msg->ifa_family, address, 0);
+ }
+
+ if (host == NULL)
+ { /* bad family? */
+ return;
+ }
+
+ ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex);
+ while (ifaces->iterate(ifaces, (void**)&iface))
+ {
+ if (iface->ifindex == msg->ifa_index)
{
- u_int32_t reqid = 0;
- job_t *job;
- struct rtattr *rtattr = XFRM_RTA(hdr, struct xfrm_user_acquire);
- size_t rtsize = XFRM_PAYLOAD(hdr, struct xfrm_user_tmpl);
- if (RTA_OK(rtattr, rtsize))
+ addrs = iface->addrs->create_iterator(iface->addrs, TRUE);
+ while (addrs->iterate(addrs, (void**)&addr))
{
- if (rtattr->rta_type == XFRMA_TMPL)
+ if (host->ip_equals(host, addr->ip))
{
- struct xfrm_user_tmpl* tmpl = (struct xfrm_user_tmpl*)RTA_DATA(rtattr);
- reqid = tmpl->reqid;
+ found = TRUE;
+ if (hdr->nlmsg_type == RTM_DELADDR)
+ {
+ changed = TRUE;
+ addrs->remove(addrs);
+ addr_entry_destroy(addr);
+ DBG1(DBG_KNL, "%H disappeared from %s", host, iface->ifname);
+ }
}
}
- if (reqid == 0)
+ addrs->destroy(addrs);
+
+ if (hdr->nlmsg_type == RTM_NEWADDR)
{
- DBG1(DBG_KNL, "received a XFRM_MSG_ACQUIRE, but no reqid found");
+ if (!found)
+ {
+ found = TRUE;
+ changed = TRUE;
+ addr = malloc_thing(addr_entry_t);
+ addr->ip = host->clone(host);
+ addr->virtual = FALSE;
+ addr->refcount = 1;
+ addr->scope = msg->ifa_scope;
+
+ iface->addrs->insert_last(iface->addrs, addr);
+ if (event)
+ {
+ DBG1(DBG_KNL, "%H appeared on %s", host, iface->ifname);
+ }
+ }
}
- else
+ if (found && (iface->flags & IFF_UP))
{
- DBG2(DBG_KNL, "received a XFRM_MSG_ACQUIRE");
- DBG1(DBG_KNL, "creating acquire job for CHILD_SA with reqid %d",
- reqid);
- job = (job_t*)acquire_job_create(reqid);
- charon->job_queue->add(charon->job_queue, job);
+ update = TRUE;
}
+ break;
+ }
+ }
+ ifaces->destroy(ifaces);
+ host->destroy(host);
+
+ /* send an update to all IKE_SAs */
+ if (update && event && changed)
+ {
+ charon->processor->queue_job(charon->processor,
+ (job_t*)roam_job_create(TRUE));
+ }
+}
+
+/**
+ * Receives events from kernel
+ */
+static job_requeue_t receive_events(private_kernel_interface_t *this)
+{
+ char response[1024];
+ struct nlmsghdr *hdr = (struct nlmsghdr*)response;
+ struct sockaddr_nl addr;
+ socklen_t addr_len = sizeof(addr);
+ int len, oldstate, maxfd, selected;
+ fd_set rfds;
+
+ FD_ZERO(&rfds);
+ FD_SET(this->socket_xfrm_events, &rfds);
+ FD_SET(this->socket_rt_events, &rfds);
+ maxfd = max(this->socket_xfrm_events, this->socket_rt_events);
+
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+ selected = select(maxfd + 1, &rfds, NULL, NULL, NULL);
+ pthread_setcancelstate(oldstate, NULL);
+ if (selected <= 0)
+ {
+ DBG1(DBG_KNL, "selecting on sockets failed: %s", strerror(errno));
+ return JOB_REQUEUE_FAIR;
+ }
+ if (FD_ISSET(this->socket_xfrm_events, &rfds))
+ {
+ selected = this->socket_xfrm_events;
+ }
+ else if (FD_ISSET(this->socket_rt_events, &rfds))
+ {
+ selected = this->socket_rt_events;
+ }
+ else
+ {
+ return JOB_REQUEUE_DIRECT;
+ }
+
+ len = recvfrom(selected, response, sizeof(response), MSG_DONTWAIT,
+ (struct sockaddr*)&addr, &addr_len);
+ if (len < 0)
+ {
+ switch (errno)
+ {
+ case EINTR:
+ /* interrupted, try again */
+ return JOB_REQUEUE_DIRECT;
+ case EAGAIN:
+ /* no data ready, select again */
+ return JOB_REQUEUE_DIRECT;
+ default:
+ DBG1(DBG_KNL, "unable to receive from xfrm event socket");
+ sleep(1);
+ return JOB_REQUEUE_FAIR;
}
- else if (hdr->nlmsg_type == XFRM_MSG_EXPIRE)
+ }
+ if (addr.nl_pid != 0)
+ { /* not from kernel. not interested, try another one */
+ return JOB_REQUEUE_DIRECT;
+ }
+
+ while (NLMSG_OK(hdr, len))
+ {
+ /* looks good so far, dispatch netlink message */
+ if (selected == this->socket_xfrm_events)
{
- job_t *job;
- protocol_id_t protocol;
- u_int32_t spi, reqid;
- struct xfrm_user_expire *expire;
-
- expire = (struct xfrm_user_expire*)NLMSG_DATA(hdr);
- protocol = expire->state.id.proto == KERNEL_ESP ?
- PROTO_ESP : PROTO_AH;
- spi = expire->state.id.spi;
- reqid = expire->state.reqid;
-
- DBG2(DBG_KNL, "received a XFRM_MSG_EXPIRE");
- DBG1(DBG_KNL, "creating %s job for %N CHILD_SA 0x%x (reqid %d)",
- expire->hard ? "delete" : "rekey", protocol_id_names,
- protocol, ntohl(spi), reqid);
- if (expire->hard)
+ switch (hdr->nlmsg_type)
{
- job = (job_t*)delete_child_sa_job_create(reqid, protocol, spi);
+ case XFRM_MSG_ACQUIRE:
+ process_acquire(this, hdr);
+ break;
+ case XFRM_MSG_EXPIRE:
+ process_expire(this, hdr);
+ break;
+ default:
+ break;
}
- else
+ }
+ else if (selected == this->socket_rt_events)
+ {
+ switch (hdr->nlmsg_type)
{
- job = (job_t*)rekey_child_sa_job_create(reqid, protocol, spi);
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ process_addr(this, hdr, TRUE);
+ break;
+ case RTM_NEWLINK:
+ case RTM_DELLINK:
+ process_link(this, hdr, TRUE);
+ break;
+ case RTM_NEWROUTE:
+ case RTM_DELROUTE:
+ charon->processor->queue_job(charon->processor,
+ (job_t*)roam_job_create(FALSE));
+ break;
+ default:
+ break;
}
- charon->job_queue->add(charon->job_queue, job);
}
+ hdr = NLMSG_NEXT(hdr, len);
}
+ return JOB_REQUEUE_DIRECT;
}
/**
* send a netlink message and wait for a reply
*/
-static status_t netlink_send(int socket, struct nlmsghdr *in,
+static status_t netlink_send(private_kernel_interface_t *this,
+ int socket, struct nlmsghdr *in,
struct nlmsghdr **out, size_t *out_len)
{
int len, addr_len;
@@ -550,13 +844,9 @@ static status_t netlink_send(int socket, struct nlmsghdr *in,
chunk_t result = chunk_empty, tmp;
struct nlmsghdr *msg, peek;
- static int seq = 200;
- static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-
+ pthread_mutex_lock(&this->mutex);
- pthread_mutex_lock(&mutex);
-
- in->nlmsg_seq = ++seq;
+ in->nlmsg_seq = ++this->seq;
in->nlmsg_pid = getpid();
memset(&addr, 0, sizeof(addr));
@@ -576,7 +866,7 @@ static status_t netlink_send(int socket, struct nlmsghdr *in,
/* interrupted, try again */
continue;
}
- pthread_mutex_unlock(&mutex);
+ pthread_mutex_unlock(&this->mutex);
DBG1(DBG_KNL, "error sending to netlink socket: %s", strerror(errno));
return FAILED;
}
@@ -585,7 +875,7 @@ static status_t netlink_send(int socket, struct nlmsghdr *in,
while (TRUE)
{
- char buf[1024];
+ char buf[4096];
tmp.len = sizeof(buf);
tmp.ptr = buf;
msg = (struct nlmsghdr*)tmp.ptr;
@@ -603,28 +893,28 @@ static status_t netlink_send(int socket, struct nlmsghdr *in,
{
if (errno == EINTR)
{
- DBG1(DBG_IKE, "got interrupted");
+ DBG1(DBG_KNL, "got interrupted");
/* interrupted, try again */
continue;
}
- DBG1(DBG_IKE, "error reading from netlink socket: %s", strerror(errno));
- pthread_mutex_unlock(&mutex);
+ DBG1(DBG_KNL, "error reading from netlink socket: %s", strerror(errno));
+ pthread_mutex_unlock(&this->mutex);
return FAILED;
}
if (!NLMSG_OK(msg, len))
{
- DBG1(DBG_IKE, "received corrupted netlink message");
- pthread_mutex_unlock(&mutex);
+ DBG1(DBG_KNL, "received corrupted netlink message");
+ pthread_mutex_unlock(&this->mutex);
return FAILED;
}
- if (msg->nlmsg_seq != seq)
+ if (msg->nlmsg_seq != this->seq)
{
- DBG1(DBG_IKE, "received invalid netlink sequence number");
- if (msg->nlmsg_seq < seq)
+ DBG1(DBG_KNL, "received invalid netlink sequence number");
+ if (msg->nlmsg_seq < this->seq)
{
continue;
}
- pthread_mutex_unlock(&mutex);
+ pthread_mutex_unlock(&this->mutex);
return FAILED;
}
@@ -636,7 +926,7 @@ static status_t netlink_send(int socket, struct nlmsghdr *in,
len = recvfrom(socket, &peek, sizeof(peek), MSG_PEEK | MSG_DONTWAIT,
(struct sockaddr*)&addr, &addr_len);
- if (len == sizeof(peek) && peek.nlmsg_seq == seq)
+ if (len == sizeof(peek) && peek.nlmsg_seq == this->seq)
{
/* seems to be multipart */
continue;
@@ -647,7 +937,7 @@ static status_t netlink_send(int socket, struct nlmsghdr *in,
*out_len = result.len;
*out = (struct nlmsghdr*)clalloc(result.ptr, result.len);
- pthread_mutex_unlock(&mutex);
+ pthread_mutex_unlock(&this->mutex);
return SUCCESS;
}
@@ -655,12 +945,13 @@ static status_t netlink_send(int socket, struct nlmsghdr *in,
/**
* send a netlink message and wait for its acknowlegde
*/
-static status_t netlink_send_ack(int socket, struct nlmsghdr *in)
+static status_t netlink_send_ack(private_kernel_interface_t *this,
+ int socket, struct nlmsghdr *in)
{
struct nlmsghdr *out, *hdr;
size_t len;
- if (netlink_send(socket, in, &out, &len) != SUCCESS)
+ if (netlink_send(this, socket, in, &out, &len) != SUCCESS)
{
return FAILED;
}
@@ -697,132 +988,153 @@ static status_t netlink_send_ack(int socket, struct nlmsghdr *in)
}
/**
- * Create a list of local addresses.
+ * Initialize a list of local addresses.
*/
-static linked_list_t *create_address_list(private_kernel_interface_t *this)
+static status_t init_address_list(private_kernel_interface_t *this)
{
char request[BUFFER_SIZE];
- struct nlmsghdr *out, *hdr;
+ struct nlmsghdr *out, *current, *in;
struct rtgenmsg *msg;
size_t len;
- linked_list_t *list;
-
- DBG2(DBG_IKE, "getting local address list");
+ iterator_t *ifaces, *addrs;
+ iface_entry_t *iface;
+ addr_entry_t *addr;
- list = linked_list_create();
+ DBG1(DBG_KNL, "listening on interfaces:");
memset(&request, 0, sizeof(request));
- hdr = (struct nlmsghdr*)&request;
- hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
- hdr->nlmsg_type = RTM_GETADDR;
- hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT;
- msg = (struct rtgenmsg*)NLMSG_DATA(hdr);
+ in = (struct nlmsghdr*)&request;
+ in->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
+ in->nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH | NLM_F_ROOT;
+ msg = (struct rtgenmsg*)NLMSG_DATA(in);
msg->rtgen_family = AF_UNSPEC;
-
- if (netlink_send(this->socket_rt, hdr, &out, &len) == SUCCESS)
+
+ /* get all links */
+ in->nlmsg_type = RTM_GETLINK;
+ if (netlink_send(this, this->socket_rt, in, &out, &len) != SUCCESS)
{
- hdr = out;
- while (NLMSG_OK(hdr, len))
+ return FAILED;
+ }
+ current = out;
+ while (NLMSG_OK(current, len))
+ {
+ switch (current->nlmsg_type)
{
- switch (hdr->nlmsg_type)
+ case NLMSG_DONE:
+ break;
+ case RTM_NEWLINK:
+ process_link(this, current, FALSE);
+ /* fall through */
+ default:
+ current = NLMSG_NEXT(current, len);
+ continue;
+ }
+ break;
+ }
+ free(out);
+
+ /* get all interface addresses */
+ in->nlmsg_type = RTM_GETADDR;
+ if (netlink_send(this, this->socket_rt, in, &out, &len) != SUCCESS)
+ {
+ return FAILED;
+ }
+ current = out;
+ while (NLMSG_OK(current, len))
+ {
+ switch (current->nlmsg_type)
+ {
+ case NLMSG_DONE:
+ break;
+ case RTM_NEWADDR:
+ process_addr(this, current, FALSE);
+ /* fall through */
+ default:
+ current = NLMSG_NEXT(current, len);
+ continue;
+ }
+ break;
+ }
+ free(out);
+
+ ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex);
+ while (ifaces->iterate(ifaces, (void**)&iface))
+ {
+ if (iface->flags & IFF_UP)
+ {
+ DBG1(DBG_KNL, " %s", iface->ifname);
+ addrs = iface->addrs->create_iterator(iface->addrs, TRUE);
+ while (addrs->iterate(addrs, (void**)&addr))
{
- case RTM_NEWADDR:
- {
- struct ifaddrmsg* msg = (struct ifaddrmsg*)(NLMSG_DATA(hdr));
- struct rtattr *rta = IFA_RTA(msg);
- size_t rtasize = IFA_PAYLOAD (hdr);
- host_t *host = NULL;
- char *name = NULL;
- chunk_t local = chunk_empty, address = chunk_empty;
-
- while(RTA_OK(rta, rtasize))
- {
- switch (rta->rta_type)
- {
- case IFA_LOCAL:
- local.ptr = RTA_DATA(rta);
- local.len = RTA_PAYLOAD(rta);
- break;
- case IFA_ADDRESS:
- address.ptr = RTA_DATA(rta);
- address.len = RTA_PAYLOAD(rta);
- break;
- case IFA_LABEL:
- name = RTA_DATA(rta);
- break;
- }
- rta = RTA_NEXT(rta, rtasize);
- }
-
- /* For PPP interfaces, we need the IFA_LOCAL address,
- * IFA_ADDRESS is the peers address. But IFA_LOCAL is
- * not included in all cases, so fallback to IFA_ADDRESS. */
- if (local.ptr)
- {
- host = host_create_from_chunk(msg->ifa_family, local, 0);
- }
- else if (address.ptr)
- {
- host = host_create_from_chunk(msg->ifa_family, address, 0);
- }
-
- if (host)
- {
- address_entry_t *entry;
-
- entry = malloc_thing(address_entry_t);
- entry->host = host;
- entry->ifindex = msg->ifa_index;
- if (name)
- {
- memcpy(entry->ifname, name, IFNAMSIZ);
- }
- else
- {
- strcpy(entry->ifname, "(unknown)");
- }
- list->insert_last(list, entry);
- }
- hdr = NLMSG_NEXT(hdr, len);
- continue;
- }
- default:
- hdr = NLMSG_NEXT(hdr, len);
- continue;
- case NLMSG_DONE:
- break;
+ DBG1(DBG_KNL, " %H", addr->ip);
}
- break;
+ addrs->destroy(addrs);
}
- free(out);
}
- else
- {
- DBG1(DBG_IKE, "unable to get local address list");
+ ifaces->destroy(ifaces);
+ return SUCCESS;
+}
+
+/**
+ * iterator hook to iterate over addrs
+ */
+static hook_result_t addr_hook(private_kernel_interface_t *this,
+ addr_entry_t *in, host_t **out)
+{
+ if (in->virtual)
+ { /* skip virtual interfaces added by us */
+ return HOOK_SKIP;
+ }
+ if (in->scope >= RT_SCOPE_LINK)
+ { /* skip addresses with a unusable scope */
+ return HOOK_SKIP;
+ }
+ *out = in->ip;
+ return HOOK_NEXT;
+}
+
+/**
+ * iterator hook to iterate over ifaces
+ */
+static hook_result_t iface_hook(private_kernel_interface_t *this,
+ iface_entry_t *in, host_t **out)
+{
+ if (!(in->flags & IFF_UP))
+ { /* skip interfaces not up */
+ return HOOK_SKIP;
}
- return list;
+ if (this->hiter == NULL)
+ {
+ this->hiter = in->addrs->create_iterator(in->addrs, TRUE);
+ this->hiter->set_iterator_hook(this->hiter,
+ (iterator_hook_t*)addr_hook, this);
+ }
+ while (this->hiter->iterate(this->hiter, (void**)out))
+ {
+ return HOOK_AGAIN;
+ }
+ this->hiter->destroy(this->hiter);
+ this->hiter = NULL;
+ return HOOK_SKIP;
}
/**
- * Implements kernel_interface_t.create_address_list.
+ * Implements kernel_interface_t.create_address_iterator.
*/
-static linked_list_t *create_address_list_public(private_kernel_interface_t *this)
+static iterator_t *create_address_iterator(private_kernel_interface_t *this)
{
- linked_list_t *result, *list;
- address_entry_t *entry;
+ iterator_t *iterator;
- result = linked_list_create();
- list = create_address_list(this);
- while (list->remove_last(list, (void**)&entry) == SUCCESS)
- {
- result->insert_last(result, entry->host);
- free(entry);
- }
- list->destroy(list);
+ /* This iterator is not only hooked, is is double-hooked. As we have stored
+ * our addresses in iface_entry->addr_entry->ip, we need to iterate the
+ * entries in each interface we iterate. This does the iface_hook. The
+ * addr_hook returns the ip instead of the addr_entry. */
- return result;
+ iterator = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex);
+ iterator->set_iterator_hook(iterator, (iterator_hook_t*)iface_hook, this);
+ return iterator;
}
/**
@@ -830,30 +1142,40 @@ static linked_list_t *create_address_list_public(private_kernel_interface_t *thi
*/
static char *get_interface_name(private_kernel_interface_t *this, host_t* ip)
{
- linked_list_t *list;
- address_entry_t *entry;
+ iterator_t *ifaces, *addrs;
+ iface_entry_t *iface;
+ addr_entry_t *addr;
char *name = NULL;
- DBG2(DBG_IKE, "getting interface name for %H", ip);
+ DBG2(DBG_KNL, "getting interface name for %H", ip);
- list = create_address_list(this);
- while (!name && list->remove_last(list, (void**)&entry) == SUCCESS)
+ ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex);
+ while (ifaces->iterate(ifaces, (void**)&iface))
{
- if (ip->ip_equals(ip, entry->host))
+ addrs = iface->addrs->create_iterator(iface->addrs, TRUE);
+ while (addrs->iterate(addrs, (void**)&addr))
+ {
+ if (ip->ip_equals(ip, addr->ip))
+ {
+ name = strdup(iface->ifname);
+ break;
+ }
+ }
+ addrs->destroy(addrs);
+ if (name)
{
- name = strdup(entry->ifname);
+ break;
}
- address_entry_destroy(entry);
}
- list->destroy_function(list, (void*)address_entry_destroy);
+ ifaces->destroy(ifaces);
if (name)
{
- DBG2(DBG_IKE, "%H is on interface %s", ip, name);
+ DBG2(DBG_KNL, "%H is on interface %s", ip, name);
}
else
{
- DBG2(DBG_IKE, "%H is not a local address", ip);
+ DBG2(DBG_KNL, "%H is not a local address", ip);
}
return name;
}
@@ -865,13 +1187,14 @@ static char *get_interface_name(private_kernel_interface_t *this, host_t* ip)
static status_t get_address_by_ts(private_kernel_interface_t *this,
traffic_selector_t *ts, host_t **ip)
{
- address_entry_t *entry;
+ iterator_t *ifaces, *addrs;
+ iface_entry_t *iface;
+ addr_entry_t *addr;
host_t *host;
int family;
- linked_list_t *list;
bool found = FALSE;
- DBG2(DBG_IKE, "getting a local address in traffic selector %R", ts);
+ DBG2(DBG_KNL, "getting a local address in traffic selector %R", ts);
/* if we have a family which includes localhost, we do not
* search for an IP, we use the default */
@@ -890,29 +1213,38 @@ static status_t get_address_by_ts(private_kernel_interface_t *this,
{
*ip = host_create_any(family);
host->destroy(host);
- DBG2(DBG_IKE, "using host %H", *ip);
+ DBG2(DBG_KNL, "using host %H", *ip);
return SUCCESS;
}
host->destroy(host);
- list = create_address_list(this);
- while (!found && list->remove_last(list, (void**)&entry) == SUCCESS)
+ ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex);
+ while (ifaces->iterate(ifaces, (void**)&iface))
{
- if (ts->includes(ts, entry->host))
+ addrs = iface->addrs->create_iterator(iface->addrs, TRUE);
+ while (addrs->iterate(addrs, (void**)&addr))
{
- found = TRUE;
- *ip = entry->host->clone(entry->host);
+ if (ts->includes(ts, addr->ip))
+ {
+ found = TRUE;
+ *ip = addr->ip->clone(addr->ip);
+ break;
+ }
+ }
+ addrs->destroy(addrs);
+ if (found)
+ {
+ break;
}
- address_entry_destroy(entry);
}
- list->destroy_function(list, (void*)address_entry_destroy);
+ ifaces->destroy(ifaces);
if (!found)
{
- DBG1(DBG_IKE, "no local address found in traffic selector %R", ts);
+ DBG1(DBG_KNL, "no local address found in traffic selector %R", ts);
return FAILED;
}
- DBG2(DBG_IKE, "using host %H", *ip);
+ DBG2(DBG_KNL, "using host %H", *ip);
return SUCCESS;
}
@@ -921,26 +1253,36 @@ static status_t get_address_by_ts(private_kernel_interface_t *this,
*/
static int get_interface_index(private_kernel_interface_t *this, host_t* ip)
{
- linked_list_t *list;
- address_entry_t *entry;
+ iterator_t *ifaces, *addrs;
+ iface_entry_t *iface;
+ addr_entry_t *addr;
int ifindex = 0;
- DBG2(DBG_IKE, "getting iface for %H", ip);
+ DBG2(DBG_KNL, "getting iface for %H", ip);
- list = create_address_list(this);
- while (!ifindex && list->remove_last(list, (void**)&entry) == SUCCESS)
+ ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex);
+ while (ifaces->iterate(ifaces, (void**)&iface))
{
- if (ip->ip_equals(ip, entry->host))
+ addrs = iface->addrs->create_iterator(iface->addrs, TRUE);
+ while (addrs->iterate(addrs, (void**)&addr))
+ {
+ if (ip->ip_equals(ip, addr->ip))
+ {
+ ifindex = iface->ifindex;
+ break;
+ }
+ }
+ addrs->destroy(addrs);
+ if (ifindex)
{
- ifindex = entry->ifindex;
+ break;
}
- address_entry_destroy(entry);
}
- list->destroy_function(list, (void*)address_entry_destroy);
-
+ ifaces->destroy(ifaces);
+
if (ifindex == 0)
{
- DBG1(DBG_IKE, "unable to get interface for %H", ip);
+ DBG1(DBG_KNL, "unable to get interface for %H", ip);
}
return ifindex;
}
@@ -975,7 +1317,7 @@ static status_t manage_ipaddr(private_kernel_interface_t *this, int nlmsg_type,
add_attribute(hdr, IFA_LOCAL, chunk, sizeof(request));
- return netlink_send_ack(this->socket_rt, hdr);
+ return netlink_send_ack(this, this->socket_rt, hdr);
}
/**
@@ -1036,107 +1378,206 @@ static status_t manage_srcroute(private_kernel_interface_t *this, int nlmsg_type
chunk.len = sizeof(route->if_index);
add_attribute(hdr, RTA_OIF, chunk, sizeof(request));
- return netlink_send_ack(this->socket_rt, hdr);
+ return netlink_send_ack(this, this->socket_rt, hdr);
}
-
/**
- * Implementation of kernel_interface_t.add_ip.
+ * Get the nexthop gateway for dest; or the source addr if gateway = FALSE
*/
-static status_t add_ip(private_kernel_interface_t *this,
- host_t *virtual_ip, host_t *iface_ip)
+static host_t* get_addr(private_kernel_interface_t *this,
+ host_t *dest, bool gateway)
{
- int targetif;
- vip_entry_t *listed;
- iterator_t *iterator;
+ unsigned char request[BUFFER_SIZE];
+ struct nlmsghdr *hdr, *out, *current;
+ struct rtmsg *msg;
+ chunk_t chunk;
+ size_t len;
+ host_t *addr = NULL;
+
+ DBG2(DBG_KNL, "getting address to reach %H", dest);
+
+ memset(&request, 0, sizeof(request));
- DBG2(DBG_KNL, "adding virtual IP %H", virtual_ip);
+ hdr = (struct nlmsghdr*)request;
+ hdr->nlmsg_flags = NLM_F_REQUEST;
+ hdr->nlmsg_type = RTM_GETROUTE;
+ hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
- targetif = get_interface_index(this, iface_ip);
- if (targetif == 0)
+ msg = (struct rtmsg*)NLMSG_DATA(hdr);
+ msg->rtm_family = dest->get_family(dest);
+ msg->rtm_dst_len = msg->rtm_family == AF_INET ? 32 : 128;
+ msg->rtm_table = RT_TABLE_MAIN;
+ msg->rtm_protocol = RTPROT_STATIC;
+ msg->rtm_type = RTN_UNICAST;
+ msg->rtm_scope = RT_SCOPE_UNIVERSE;
+
+ chunk = dest->get_address(dest);
+ add_attribute(hdr, RTA_DST, chunk, sizeof(request));
+
+ if (netlink_send(this, this->socket_rt, hdr, &out, &len) != SUCCESS)
{
- DBG1(DBG_KNL, "unable to add virtual IP %H, no iface found for %H",
- virtual_ip, iface_ip);
- return FAILED;
+ DBG1(DBG_KNL, "getting address to %H failed", dest);
+ return NULL;
}
-
- /* beware of deadlocks (e.g. send/receive packets while holding the lock) */
- iterator = this->vips->create_iterator_locked(this->vips, &(this->vips_mutex));
- while (iterator->iterate(iterator, (void**)&listed))
+ current = out;
+ while (NLMSG_OK(current, len))
{
- if (listed->if_index == targetif &&
- virtual_ip->ip_equals(virtual_ip, listed->ip))
+ switch (current->nlmsg_type)
{
- listed->refcount++;
- iterator->destroy(iterator);
- DBG2(DBG_KNL, "virtual IP %H already added to iface %d reusing it",
- virtual_ip, targetif);
- return SUCCESS;
+ case NLMSG_DONE:
+ break;
+ case RTM_NEWROUTE:
+ {
+ struct rtattr *rta;
+ size_t rtasize;
+
+ msg = (struct rtmsg*)(NLMSG_DATA(current));
+ rta = RTM_RTA(msg);
+ rtasize = RTM_PAYLOAD(current);
+ while(RTA_OK(rta, rtasize))
+ {
+ if ((rta->rta_type == RTA_PREFSRC && !gateway) ||
+ (rta->rta_type == RTA_GATEWAY && gateway))
+ {
+ chunk.ptr = RTA_DATA(rta);
+ chunk.len = RTA_PAYLOAD(rta);
+ addr = host_create_from_chunk(msg->rtm_family,
+ chunk, 0);
+ break;
+ }
+ rta = RTA_NEXT(rta, rtasize);
+ }
+ break;
+ }
+ default:
+ current = NLMSG_NEXT(current, len);
+ continue;
}
+ break;
}
- iterator->destroy(iterator);
+ free(out);
+ if (addr == NULL)
+ {
+ DBG2(DBG_KNL, "no route found to %H", dest);
+ }
+ return addr;
+}
+
+/**
+ * Implementation of kernel_interface_t.get_source_addr.
+ */
+static host_t* get_source_addr(private_kernel_interface_t *this, host_t *dest)
+{
+ return get_addr(this, dest, FALSE);
+}
- if (manage_ipaddr(this, RTM_NEWADDR, NLM_F_CREATE | NLM_F_EXCL,
- targetif, virtual_ip) == SUCCESS)
+/**
+ * Implementation of kernel_interface_t.add_ip.
+ */
+static status_t add_ip(private_kernel_interface_t *this,
+ host_t *virtual_ip, host_t *iface_ip)
+{
+ iface_entry_t *iface;
+ addr_entry_t *addr;
+ iterator_t *addrs, *ifaces;
+
+ DBG2(DBG_KNL, "adding virtual IP %H", virtual_ip);
+
+ ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex);
+ while (ifaces->iterate(ifaces, (void**)&iface))
{
- listed = malloc_thing(vip_entry_t);
- listed->ip = virtual_ip->clone(virtual_ip);
- listed->if_index = targetif;
- listed->refcount = 1;
- this->vips->insert_last(this->vips, listed);
- DBG2(DBG_KNL, "virtual IP %H added to iface %d",
- virtual_ip, targetif);
- return SUCCESS;
+ bool iface_found = FALSE;
+
+ addrs = iface->addrs->create_iterator(iface->addrs, TRUE);
+ while (addrs->iterate(addrs, (void**)&addr))
+ {
+ if (iface_ip->ip_equals(iface_ip, addr->ip))
+ {
+ iface_found = TRUE;
+ }
+ else if (virtual_ip->ip_equals(virtual_ip, addr->ip))
+ {
+ addr->refcount++;
+ DBG2(DBG_KNL, "virtual IP %H already installed on %s",
+ virtual_ip, iface->ifname);
+ addrs->destroy(addrs);
+ ifaces->destroy(ifaces);
+ return SUCCESS;
+ }
+ }
+ addrs->destroy(addrs);
+
+ if (iface_found)
+ {
+ int ifindex = iface->ifindex;
+ ifaces->destroy(ifaces);
+ if (manage_ipaddr(this, RTM_NEWADDR, NLM_F_CREATE | NLM_F_EXCL,
+ ifindex, virtual_ip) == SUCCESS)
+ {
+ addr = malloc_thing(addr_entry_t);
+ addr->ip = virtual_ip->clone(virtual_ip);
+ addr->refcount = 1;
+ addr->virtual = TRUE;
+ addr->scope = RT_SCOPE_UNIVERSE;
+ pthread_mutex_lock(&this->mutex);
+ iface->addrs->insert_last(iface->addrs, addr);
+ pthread_mutex_unlock(&this->mutex);
+ return SUCCESS;
+ }
+ DBG2(DBG_KNL, "adding virtual IP %H failed", virtual_ip);
+ return FAILED;
+
+ }
+
}
+ ifaces->destroy(ifaces);
- DBG2(DBG_KNL, "unable to add virtual IP %H to iface %d",
- virtual_ip, targetif);
+ DBG2(DBG_KNL, "interface address %H not found, unable to install"
+ "virtual IP %H", iface_ip, virtual_ip);
return FAILED;
}
/**
* Implementation of kernel_interface_t.del_ip.
*/
-static status_t del_ip(private_kernel_interface_t *this,
- host_t *virtual_ip, host_t *iface_ip)
+static status_t del_ip(private_kernel_interface_t *this, host_t *virtual_ip)
{
- int targetif;
- vip_entry_t *listed;
- iterator_t *iterator;
+ iface_entry_t *iface;
+ addr_entry_t *addr;
+ iterator_t *addrs, *ifaces;
DBG2(DBG_KNL, "deleting virtual IP %H", virtual_ip);
-
- targetif = get_interface_index(this, iface_ip);
- if (targetif == 0)
- {
- DBG1(DBG_KNL, "unable to delete virtual IP %H, no iface found for %H",
- virtual_ip, iface_ip);
- return FAILED;
- }
-
- /* beware of deadlocks (e.g. send/receive packets while holding the lock) */
- iterator = this->vips->create_iterator_locked(this->vips, &(this->vips_mutex));
- while (iterator->iterate(iterator, (void**)&listed))
+
+ ifaces = this->ifaces->create_iterator_locked(this->ifaces, &this->mutex);
+ while (ifaces->iterate(ifaces, (void**)&iface))
{
- if (listed->if_index == targetif &&
- virtual_ip->ip_equals(virtual_ip, listed->ip))
+ addrs = iface->addrs->create_iterator(iface->addrs, TRUE);
+ while (addrs->iterate(addrs, (void**)&addr))
{
- listed->refcount--;
- if (listed->refcount == 0)
+ if (virtual_ip->ip_equals(virtual_ip, addr->ip))
{
- iterator->remove(iterator);
- vip_entry_destroy(listed);
- iterator->destroy(iterator);
- return manage_ipaddr(this, RTM_DELADDR, 0, targetif, virtual_ip);
+ int ifindex = iface->ifindex;
+ addr->refcount--;
+ if (addr->refcount == 0)
+ {
+ addrs->remove(addrs);
+ addrs->destroy(addrs);
+ ifaces->destroy(ifaces);
+ addr_entry_destroy(addr);
+ return manage_ipaddr(this, RTM_DELADDR, 0,
+ ifindex, virtual_ip);
+ }
+ DBG2(DBG_KNL, "virtual IP %H used by other SAs, not deleting",
+ virtual_ip);
+ addrs->destroy(addrs);
+ ifaces->destroy(ifaces);
+ return SUCCESS;
}
- iterator->destroy(iterator);
- DBG2(DBG_KNL, "virtual IP %H used by other SAs, not deleting",
- virtual_ip);
- return SUCCESS;
}
+ addrs->destroy(addrs);
}
- iterator->destroy(iterator);
-
+ ifaces->destroy(ifaces);
+
DBG2(DBG_KNL, "virtual IP %H not cached, unable to delete", virtual_ip);
return FAILED;
}
@@ -1174,7 +1615,7 @@ static status_t get_spi(private_kernel_interface_t *this,
userspi->min = 0xc0000000;
userspi->max = 0xcFFFFFFF;
- if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
+ if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS)
{
hdr = out;
while (NLMSG_OK(hdr, len))
@@ -1226,7 +1667,7 @@ static status_t add_sa(private_kernel_interface_t *this,
protocol_id_t protocol, u_int32_t reqid,
u_int64_t expire_soft, u_int64_t expire_hard,
algorithm_t *enc_alg, algorithm_t *int_alg,
- prf_plus_t *prf_plus, natt_conf_t *natt, mode_t mode,
+ prf_plus_t *prf_plus, mode_t mode, bool encap,
bool replace)
{
unsigned char request[BUFFER_SIZE];
@@ -1324,7 +1765,7 @@ static status_t add_sa(private_kernel_interface_t *this,
/* TODO: add IPComp here */
- if (natt)
+ if (encap)
{
rthdr->rta_type = XFRMA_ENCAP;
rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl));
@@ -1335,11 +1776,11 @@ static status_t add_sa(private_kernel_interface_t *this,
return FAILED;
}
- struct xfrm_encap_tmpl* encap = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr);
- encap->encap_type = UDP_ENCAP_ESPINUDP;
- encap->encap_sport = htons(natt->sport);
- encap->encap_dport = htons(natt->dport);
- memset(&encap->encap_oa, 0, sizeof (xfrm_address_t));
+ struct xfrm_encap_tmpl* tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rthdr);
+ tmpl->encap_type = UDP_ENCAP_ESPINUDP;
+ tmpl->encap_sport = htons(src->get_port(src));
+ tmpl->encap_dport = htons(dst->get_port(dst));
+ memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t));
/* encap_oa could probably be derived from the
* traffic selectors [rfc4306, p39]. In the netlink kernel implementation
* pluto does the same as we do here but it uses encap_oa in the
@@ -1352,9 +1793,9 @@ static status_t add_sa(private_kernel_interface_t *this,
rthdr = XFRM_RTA_NEXT(rthdr);
}
- if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS)
+ if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS)
{
- DBG1(DBG_KNL, "unalbe to add SAD entry with SPI 0x%x", spi);
+ DBG1(DBG_KNL, "unable to add SAD entry with SPI 0x%x", spi);
return FAILED;
}
return SUCCESS;
@@ -1364,21 +1805,24 @@ static status_t add_sa(private_kernel_interface_t *this,
* Implementation of kernel_interface_t.update_sa.
*/
static status_t update_sa(private_kernel_interface_t *this,
- host_t *src, host_t *dst,
- host_t *new_src, host_t *new_dst,
- host_diff_t src_changes, host_diff_t dst_changes,
- u_int32_t spi, protocol_id_t protocol)
+ u_int32_t spi, protocol_id_t protocol,
+ host_t *src, host_t *dst,
+ host_t *new_src, host_t *new_dst, bool encap)
{
- unsigned char request[BUFFER_SIZE];
+ unsigned char request[BUFFER_SIZE], *pos;
struct nlmsghdr *hdr, *out = NULL;
struct xfrm_usersa_id *sa_id;
- struct xfrm_usersa_info *sa = NULL;
+ struct xfrm_usersa_info *out_sa = NULL, *sa;
size_t len;
+ struct rtattr *rta;
+ size_t rtasize;
+ struct xfrm_encap_tmpl* tmpl = NULL;
memset(&request, 0, sizeof(request));
- DBG2(DBG_KNL, "querying SAD entry with SPI 0x%x", spi);
+ DBG2(DBG_KNL, "querying SAD entry with SPI 0x%x for update", spi);
+ /* query the exisiting SA first */
hdr = (struct nlmsghdr*)request;
hdr->nlmsg_flags = NLM_F_REQUEST;
hdr->nlmsg_type = XFRM_MSG_GETSA;
@@ -1390,7 +1834,7 @@ static status_t update_sa(private_kernel_interface_t *this,
sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
sa_id->family = dst->get_family(dst);
- if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
+ if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS)
{
hdr = out;
while (NLMSG_OK(hdr, len))
@@ -1399,7 +1843,7 @@ static status_t update_sa(private_kernel_interface_t *this,
{
case XFRM_MSG_NEWSA:
{
- sa = NLMSG_DATA(hdr);
+ out_sa = NLMSG_DATA(hdr);
break;
}
case NLMSG_ERROR:
@@ -1418,59 +1862,76 @@ static status_t update_sa(private_kernel_interface_t *this,
break;
}
}
- if (sa == NULL)
+ if (out_sa == NULL ||
+ this->public.del_sa(&this->public, dst, spi, protocol) != SUCCESS)
{
DBG1(DBG_KNL, "unable to update SAD entry with SPI 0x%x", spi);
free(out);
return FAILED;
}
- DBG2(DBG_KNL, "updating SAD entry with SPI 0x%x", spi);
+ DBG2(DBG_KNL, "updating SAD entry with SPI 0x%x from %#H..%#H to %#H..%#H",
+ spi, src, dst, new_src, new_dst);
- hdr = out;
+ /* copy over the SA from out to request */
+ hdr = (struct nlmsghdr*)request;
+ memcpy(hdr, out, min(out->nlmsg_len, sizeof(request)));
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
- hdr->nlmsg_type = XFRM_MSG_UPDSA;
+ hdr->nlmsg_type = XFRM_MSG_NEWSA;
+ hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_usersa_info));
+ sa = NLMSG_DATA(hdr);
+ sa->family = new_dst->get_family(new_dst);
- if (src_changes & HOST_DIFF_ADDR)
+ if (!src->ip_equals(src, new_src))
{
host2xfrm(new_src, &sa->saddr);
}
-
- if (dst_changes & HOST_DIFF_ADDR)
+ if (!dst->ip_equals(dst, new_dst))
{
- hdr->nlmsg_type = XFRM_MSG_NEWSA;
host2xfrm(new_dst, &sa->id.daddr);
}
- if (src_changes & HOST_DIFF_PORT || dst_changes & HOST_DIFF_PORT)
+ rta = XFRM_RTA(out, struct xfrm_usersa_info);
+ rtasize = XFRM_PAYLOAD(out, struct xfrm_usersa_info);
+ pos = (u_char*)XFRM_RTA(hdr, struct xfrm_usersa_info);
+ while(RTA_OK(rta, rtasize))
{
- struct rtattr *rtattr = XFRM_RTA(hdr, struct xfrm_usersa_info);
- size_t rtsize = XFRM_PAYLOAD(hdr, struct xfrm_usersa_info);
- while (RTA_OK(rtattr, rtsize))
+ /* copy all attributes, but not XFRMA_ENCAP if we are disabling it */
+ if (rta->rta_type != XFRMA_ENCAP || encap)
{
- if (rtattr->rta_type == XFRMA_ENCAP)
- {
- struct xfrm_encap_tmpl* encap;
- encap = (struct xfrm_encap_tmpl*)RTA_DATA(rtattr);
- encap->encap_sport = ntohs(new_src->get_port(new_src));
- encap->encap_dport = ntohs(new_dst->get_port(new_dst));
- break;
- }
- rtattr = RTA_NEXT(rtattr, rtsize);
+ if (rta->rta_type == XFRMA_ENCAP)
+ { /* update encap tmpl */
+ tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rta);
+ tmpl->encap_sport = ntohs(new_src->get_port(new_src));
+ tmpl->encap_dport = ntohs(new_dst->get_port(new_dst));
+ }
+ memcpy(pos, rta, rta->rta_len);
+ pos += rta->rta_len;
+ hdr->nlmsg_len += rta->rta_len;
}
+ rta = RTA_NEXT(rta, rtasize);
+ }
+ if (tmpl == NULL && encap)
+ { /* add tmpl if we are enabling it */
+ rta = (struct rtattr*)pos;
+ rta->rta_type = XFRMA_ENCAP;
+ rta->rta_len = RTA_LENGTH(sizeof(struct xfrm_encap_tmpl));
+ hdr->nlmsg_len += rta->rta_len;
+ tmpl = (struct xfrm_encap_tmpl*)RTA_DATA(rta);
+ tmpl->encap_type = UDP_ENCAP_ESPINUDP;
+ tmpl->encap_sport = ntohs(new_src->get_port(new_src));
+ tmpl->encap_dport = ntohs(new_dst->get_port(new_dst));
+ memset(&tmpl->encap_oa, 0, sizeof (xfrm_address_t));
}
- if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS)
+
+ if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS)
{
- DBG1(DBG_KNL, "unalbe to update SAD entry with SPI 0x%x", spi);
+ DBG1(DBG_KNL, "unable to update SAD entry with SPI 0x%x", spi);
free(out);
return FAILED;
}
free(out);
- if (dst_changes & HOST_DIFF_ADDR)
- {
- return this->public.del_sa(&this->public, dst, spi, protocol);
- }
return SUCCESS;
}
@@ -1501,7 +1962,7 @@ static status_t query_sa(private_kernel_interface_t *this, host_t *dst,
sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
sa_id->family = dst->get_family(dst);
- if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
+ if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS)
{
hdr = out;
while (NLMSG_OK(hdr, len))
@@ -1567,9 +2028,9 @@ static status_t del_sa(private_kernel_interface_t *this, host_t *dst,
sa_id->proto = (protocol == PROTO_ESP) ? KERNEL_ESP : KERNEL_AH;
sa_id->family = dst->get_family(dst);
- if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS)
+ if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS)
{
- DBG1(DBG_KNL, "unalbe to delete SAD entry with SPI 0x%x", spi);
+ DBG1(DBG_KNL, "unable to delete SAD entry with SPI 0x%x", spi);
return FAILED;
}
DBG2(DBG_KNL, "deleted SAD entry with SPI 0x%x", spi);
@@ -1584,8 +2045,7 @@ static status_t add_policy(private_kernel_interface_t *this,
traffic_selector_t *src_ts,
traffic_selector_t *dst_ts,
policy_dir_t direction, protocol_id_t protocol,
- u_int32_t reqid, bool high_prio, mode_t mode,
- bool update)
+ u_int32_t reqid, bool high_prio, mode_t mode)
{
iterator_t *iterator;
policy_entry_t *current, *policy;
@@ -1601,7 +2061,7 @@ static status_t add_policy(private_kernel_interface_t *this,
policy->direction = direction;
/* find the policy, which matches EXACTLY */
- pthread_mutex_lock(&this->policies_mutex);
+ pthread_mutex_lock(&this->mutex);
iterator = this->policies->create_iterator(this->policies, TRUE);
while (iterator->iterate(iterator, (void**)&current))
{
@@ -1609,12 +2069,9 @@ static status_t add_policy(private_kernel_interface_t *this,
policy->direction == current->direction)
{
/* use existing policy */
- if (!update)
- {
- current->refcount++;
- DBG2(DBG_KNL, "policy %R===%R already exists, increasing ",
- "refcount", src_ts, dst_ts);
- }
+ current->refcount++;
+ DBG2(DBG_KNL, "policy %R===%R already exists, increasing ",
+ "refcount", src_ts, dst_ts);
free(policy);
policy = current;
found = TRUE;
@@ -1646,7 +2103,7 @@ static status_t add_policy(private_kernel_interface_t *this,
policy_info->priority -= policy->sel.sport_mask ? 1 : 0;
policy_info->action = XFRM_POLICY_ALLOW;
policy_info->share = XFRM_SHARE_ANY;
- pthread_mutex_unlock(&this->policies_mutex);
+ pthread_mutex_unlock(&this->mutex);
/* policies don't expire */
policy_info->lft.soft_byte_limit = XFRM_INF;
@@ -1680,7 +2137,7 @@ static status_t add_policy(private_kernel_interface_t *this,
host2xfrm(src, &tmpl->saddr);
host2xfrm(dst, &tmpl->id.daddr);
- if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS)
+ if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS)
{
DBG1(DBG_KNL, "unable to add policy %R===%R", src_ts, dst_ts);
return FAILED;
@@ -1698,7 +2155,13 @@ static status_t add_policy(private_kernel_interface_t *this,
policy->route = malloc_thing(route_entry_t);
if (get_address_by_ts(this, dst_ts, &policy->route->src_ip) == SUCCESS)
{
- policy->route->gateway = dst->clone(dst);
+ /* if we have a gateway (via), we use it. If it's direct, we
+ * use the peers address (which is src, as we are in POLICY_FWD).*/
+ policy->route->gateway = get_addr(this, src, TRUE);
+ if (policy->route->gateway == NULL)
+ {
+ policy->route->gateway = src->clone(src);
+ }
policy->route->if_index = get_interface_index(this, dst);
policy->route->dst_net = chunk_alloc(policy->sel.family == AF_INET ? 4 : 16);
memcpy(policy->route->dst_net.ptr, &policy->sel.saddr, policy->route->dst_net.len);
@@ -1750,7 +2213,7 @@ static status_t query_policy(private_kernel_interface_t *this,
policy_id->sel = ts2selector(src_ts, dst_ts);
policy_id->dir = direction;
- if (netlink_send(this->socket_xfrm, hdr, &out, &len) == SUCCESS)
+ if (netlink_send(this, this->socket_xfrm, hdr, &out, &len) == SUCCESS)
{
hdr = out;
while (NLMSG_OK(hdr, len))
@@ -1814,8 +2277,7 @@ static status_t del_policy(private_kernel_interface_t *this,
policy.direction = direction;
/* find the policy */
- pthread_mutex_lock(&this->policies_mutex);
- iterator = this->policies->create_iterator(this->policies, TRUE);
+ iterator = this->policies->create_iterator_locked(this->policies, &this->mutex);
while (iterator->iterate(iterator, (void**)&current))
{
if (memcmp(&current->sel, &policy.sel, sizeof(struct xfrm_selector)) == 0 &&
@@ -1827,7 +2289,6 @@ static status_t del_policy(private_kernel_interface_t *this,
/* is used by more SAs, keep in kernel */
DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed");
iterator->destroy(iterator);
- pthread_mutex_unlock(&this->policies_mutex);
return SUCCESS;
}
/* remove if last reference */
@@ -1836,7 +2297,6 @@ static status_t del_policy(private_kernel_interface_t *this,
}
}
iterator->destroy(iterator);
- pthread_mutex_unlock(&this->policies_mutex);
if (!to_delete)
{
DBG1(DBG_KNL, "deleting policy %R===%R failed, not found", src_ts, dst_ts);
@@ -1857,7 +2317,7 @@ static status_t del_policy(private_kernel_interface_t *this,
route = to_delete->route;
free(to_delete);
- if (netlink_send_ack(this->socket_xfrm, hdr) != SUCCESS)
+ if (netlink_send_ack(this, this->socket_xfrm, hdr) != SUCCESS)
{
DBG1(DBG_KNL, "unable to delete policy %R===%R", src_ts, dst_ts);
return FAILED;
@@ -1880,13 +2340,13 @@ static status_t del_policy(private_kernel_interface_t *this,
*/
static void destroy(private_kernel_interface_t *this)
{
- pthread_cancel(this->event_thread);
- pthread_join(this->event_thread, NULL);
+ this->job->cancel(this->job);
close(this->socket_xfrm_events);
close(this->socket_xfrm);
+ close(this->socket_rt_events);
close(this->socket_rt);
- this->vips->destroy(this->vips);
this->policies->destroy(this->policies);
+ this->ifaces->destroy_function(this->ifaces, (void*)iface_entry_destroy);
free(this);
}
@@ -1900,41 +2360,29 @@ kernel_interface_t *kernel_interface_create()
/* public functions */
this->public.get_spi = (status_t(*)(kernel_interface_t*,host_t*,host_t*,protocol_id_t,u_int32_t,u_int32_t*))get_spi;
- this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,algorithm_t*,algorithm_t*,prf_plus_t*,natt_conf_t*,mode_t,bool))add_sa;
- this->public.update_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_diff_t,host_diff_t))update_sa;
+ this->public.add_sa = (status_t(*)(kernel_interface_t *,host_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t,u_int64_t,u_int64_t,algorithm_t*,algorithm_t*,prf_plus_t*,mode_t,bool,bool))add_sa;
+ this->public.update_sa = (status_t(*)(kernel_interface_t*,u_int32_t,protocol_id_t,host_t*,host_t*,host_t*,host_t*,bool))update_sa;
this->public.query_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t,u_int32_t*))query_sa;
this->public.del_sa = (status_t(*)(kernel_interface_t*,host_t*,u_int32_t,protocol_id_t))del_sa;
- this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,mode_t,bool))add_policy;
+ this->public.add_policy = (status_t(*)(kernel_interface_t*,host_t*,host_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,protocol_id_t,u_int32_t,bool,mode_t))add_policy;
this->public.query_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t,u_int32_t*))query_policy;
this->public.del_policy = (status_t(*)(kernel_interface_t*,traffic_selector_t*,traffic_selector_t*,policy_dir_t))del_policy;
-
this->public.get_interface = (char*(*)(kernel_interface_t*,host_t*))get_interface_name;
- this->public.create_address_list = (linked_list_t*(*)(kernel_interface_t*))create_address_list_public;
+ this->public.create_address_iterator = (iterator_t*(*)(kernel_interface_t*))create_address_iterator;
+ this->public.get_source_addr = (host_t*(*)(kernel_interface_t*, host_t *dest))get_source_addr;
this->public.add_ip = (status_t(*)(kernel_interface_t*,host_t*,host_t*)) add_ip;
- this->public.del_ip = (status_t(*)(kernel_interface_t*,host_t*,host_t*)) del_ip;
+ this->public.del_ip = (status_t(*)(kernel_interface_t*,host_t*)) del_ip;
this->public.destroy = (void(*)(kernel_interface_t*)) destroy;
/* private members */
- this->vips = linked_list_create();
this->policies = linked_list_create();
- pthread_mutex_init(&this->policies_mutex,NULL);
- pthread_mutex_init(&this->vips_mutex,NULL);
+ this->ifaces = linked_list_create();
+ this->hiter = NULL;
+ this->seq = 200;
+ pthread_mutex_init(&this->mutex,NULL);
+ memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
- addr.nl_pid = 0;
- addr.nl_groups = 0;
-
- /* create and bind XFRM socket */
- this->socket_xfrm = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM);
- if (this->socket_xfrm <= 0)
- {
- charon->kill(charon, "unable to create XFRM netlink socket");
- }
-
- if (bind(this->socket_xfrm, (struct sockaddr*)&addr, sizeof(addr)))
- {
- charon->kill(charon, "unable to bind XFRM netlink socket");
- }
/* create and bind RT socket */
this->socket_rt = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
@@ -1942,33 +2390,58 @@ kernel_interface_t *kernel_interface_create()
{
charon->kill(charon, "unable to create RT netlink socket");
}
-
+ addr.nl_groups = 0;
if (bind(this->socket_rt, (struct sockaddr*)&addr, sizeof(addr)))
{
charon->kill(charon, "unable to bind RT netlink socket");
}
+ /* create and bind RT socket for events (address/interface/route changes) */
+ this->socket_rt_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (this->socket_rt_events <= 0)
+ {
+ charon->kill(charon, "unable to create RT event socket");
+ }
+ addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR |
+ RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_ROUTE | RTMGRP_LINK;
+ if (bind(this->socket_rt_events, (struct sockaddr*)&addr, sizeof(addr)))
+ {
+ charon->kill(charon, "unable to bind RT event socket");
+ }
+
+ /* create and bind XFRM socket */
+ this->socket_xfrm = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM);
+ if (this->socket_xfrm <= 0)
+ {
+ charon->kill(charon, "unable to create XFRM netlink socket");
+ }
+ addr.nl_groups = 0;
+ if (bind(this->socket_xfrm, (struct sockaddr*)&addr, sizeof(addr)))
+ {
+ charon->kill(charon, "unable to bind XFRM netlink socket");
+ }
+
/* create and bind XFRM socket for ACQUIRE & EXPIRE */
- addr.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE;
this->socket_xfrm_events = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM);
if (this->socket_xfrm_events <= 0)
{
charon->kill(charon, "unable to create XFRM event socket");
}
-
+ addr.nl_groups = XFRMGRP_ACQUIRE | XFRMGRP_EXPIRE;
if (bind(this->socket_xfrm_events, (struct sockaddr*)&addr, sizeof(addr)))
{
charon->kill(charon, "unable to bind XFRM event socket");
}
- /* create a thread receiving ACQUIRE & EXPIRE events */
- if (pthread_create(&this->event_thread, NULL,
- (void*(*)(void*))receive_events, this))
+ this->job = callback_job_create((callback_job_cb_t)receive_events,
+ this, NULL, NULL);
+ charon->processor->queue_job(charon->processor, (job_t*)this->job);
+
+ if (init_address_list(this) != SUCCESS)
{
- charon->kill(charon, "unable to create xfrm event dispatcher thread");
+ charon->kill(charon, "unable to get interface list");
}
return &this->public;
}
-/* vim: set ts=4 sw=4 noet: */
diff --git a/src/charon/kernel/kernel_interface.h b/src/charon/kernel/kernel_interface.h
index 2a3eaff7a..256c20797 100644
--- a/src/charon/kernel/kernel_interface.h
+++ b/src/charon/kernel/kernel_interface.h
@@ -25,7 +25,6 @@
#ifndef KERNEL_INTERFACE_H_
#define KERNEL_INTERFACE_H_
-typedef struct natt_conf_t natt_conf_t;
typedef enum policy_dir_t policy_dir_t;
typedef struct kernel_interface_t kernel_interface_t;
@@ -33,17 +32,6 @@ typedef struct kernel_interface_t kernel_interface_t;
#include <crypto/prf_plus.h>
#include <encoding/payloads/proposal_substructure.h>
-/**
- * Configuration for NAT-T
- *
- * @ingroup kernel
- */
-struct natt_conf_t {
- /** source port to use for UDP-encapsulated packets */
- u_int16_t sport;
- /** dest port to use for UDP-encapsulated packets */
- u_int16_t dport;
-};
/**
* Direction of a policy. These are equal to those
@@ -121,8 +109,8 @@ struct kernel_interface_t {
* @param enc_alg Algorithm to use for encryption (ESP only)
* @param int_alg Algorithm to use for integrity protection
* @param prf_plus PRF to derive keys from
- * @param natt NAT-T Configuration, or NULL of no NAT-T used
* @param mode mode of the SA (tunnel, transport)
+ * @param encap enable UDP encapsulation for NAT traversal
* @param replace Should an already installed SA be updated?
* @return
* - SUCCESS
@@ -133,8 +121,8 @@ struct kernel_interface_t {
protocol_id_t protocol, u_int32_t reqid,
u_int64_t expire_soft, u_int64_t expire_hard,
algorithm_t *enc_alg, algorithm_t *int_alg,
- prf_plus_t *prf_plus, natt_conf_t *natt,
- mode_t mode, bool update);
+ prf_plus_t *prf_plus, mode_t mode, bool encap,
+ bool update);
/**
* @brief Update the hosts on an installed SA.
@@ -145,21 +133,21 @@ struct kernel_interface_t {
* create a new SA and delete the old one.
*
* @param this calling object
- * @param dst destination address for this SA
* @param spi SPI of the SA
* @param protocol protocol for this SA (ESP/AH)
- * @param new_src new source address for this SA
- * @param new_dst new destination address for this SA
- * @param src_changes changes in src
- * @param dst_changes changes in dst
+ * @param src current source address
+ * @param dst current destination address
+ * @param new_src new source address
+ * @param new_dst new destination address
+ * @param encap use UDP encapsulation
* @return
* - SUCCESS
* - FAILED if kernel comm failed
*/
- status_t (*update_sa)(kernel_interface_t *this, host_t *dst, u_int32_t spi,
- protocol_id_t protocol,
- host_t *new_src, host_t *new_dst,
- host_diff_t src_changes, host_diff_t dst_changes);
+ status_t (*update_sa)(kernel_interface_t *this,
+ u_int32_t spi, protocol_id_t protocol,
+ host_t *src, host_t *dst,
+ host_t *new_src, host_t *new_dst, bool encap);
/**
* @brief Query the use time of an SA.
@@ -198,10 +186,6 @@ struct kernel_interface_t {
*
* A policy is always associated to an SA. Traffic which matches a
* policy is handled by the SA with the same reqid.
- * If the update flag is set, the policy is updated with the new
- * src/dst addresses.
- * If the update flag is not set, but a such policy is already in the
- * kernel, the reference count to this policy is increased.
*
* @param this calling object
* @param src source address of SA
@@ -213,7 +197,6 @@ struct kernel_interface_t {
* @param reqid uniqe ID of an SA to use to enforce policy
* @param high_prio if TRUE, uses a higher priority than any with FALSE
* @param mode mode of SA (tunnel, transport)
- * @param update update an existing policy, if TRUE
* @return
* - SUCCESS
* - FAILED if kernel comm failed
@@ -223,8 +206,7 @@ struct kernel_interface_t {
traffic_selector_t *src_ts,
traffic_selector_t *dst_ts,
policy_dir_t direction, protocol_id_t protocol,
- u_int32_t reqid, bool high_prio,
- mode_t mode, bool update);
+ u_int32_t reqid, bool high_prio, mode_t mode);
/**
* @brief Query the use time of a policy.
@@ -268,6 +250,18 @@ struct kernel_interface_t {
policy_dir_t direction);
/**
+ * @brief Get our outgoing source address for a destination.
+ *
+ * Does a route lookup to get the source address used to reach dest.
+ * The returned host is allocated and must be destroyed.
+ *
+ * @param this calling object
+ * @param dest target destination address
+ * @return outgoing source address, NULL if unreachable
+ */
+ host_t* (*get_source_addr)(kernel_interface_t *this, host_t *dest);
+
+ /**
* @brief Get the interface name of a local address.
*
* @param this calling object
@@ -277,12 +271,16 @@ struct kernel_interface_t {
char* (*get_interface) (kernel_interface_t *this, host_t *host);
/**
- * @brief Creates a list of all local addresses.
+ * @brief Creates an iterator over all local addresses.
+ *
+ * This function blocks an internal cached address list until the
+ * iterator gets destroyed.
+ * These hosts are read-only, do not modify or free.
*
* @param this calling object
- * @return allocated list with host_t objects
+ * @return iterator over host_t's
*/
- linked_list_t *(*create_address_list) (kernel_interface_t *this);
+ iterator_t *(*create_address_iterator) (kernel_interface_t *this);
/**
* @brief Add a virtual IP to an interface.
@@ -309,13 +307,11 @@ struct kernel_interface_t {
*
* @param this calling object
* @param virtual_ip virtual ip address to assign
- * @param iface_ip IP of an interface to remove virtual IP from
* @return
* - SUCCESS
* - FAILED if kernel comm failed
*/
- status_t (*del_ip) (kernel_interface_t *this, host_t *virtual_ip,
- host_t *iface_ip);
+ status_t (*del_ip) (kernel_interface_t *this, host_t *virtual_ip);
/**
* @brief Destroys a kernel_interface object.
diff --git a/src/charon/network/receiver.c b/src/charon/network/receiver.c
index 9b4bf71ac..1de1dd3d2 100644
--- a/src/charon/network/receiver.c
+++ b/src/charon/network/receiver.c
@@ -30,9 +30,9 @@
#include <daemon.h>
#include <network/socket.h>
#include <network/packet.h>
-#include <processing/job_queue.h>
#include <processing/jobs/job.h>
#include <processing/jobs/process_message_job.h>
+#include <processing/jobs/callback_job.h>
/** length of the full cookie, including time (u_int32_t + SHA1()) */
#define COOKIE_LENGTH 24
@@ -56,12 +56,17 @@ struct private_receiver_t {
/**
* Public part of a receiver_t object.
*/
- receiver_t public;
+ receiver_t public;
+
+ /**
+ * Threads job receiving packets
+ */
+ callback_job_t *job;
- /**
- * Assigned thread.
- */
- pthread_t assigned_thread;
+ /**
+ * Assigned thread.
+ */
+ pthread_t assigned_thread;
/**
* current secret to use for cookie calculation
@@ -245,94 +250,84 @@ static bool peer_to_aggressive(private_receiver_t *this, message_t *message)
/**
* Implementation of receiver_t.receive_packets.
*/
-static void receive_packets(private_receiver_t *this)
+static job_requeue_t receive_packets(private_receiver_t *this)
{
packet_t *packet;
message_t *message;
job_t *job;
- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
- DBG1(DBG_NET, "receiver thread running, thread_ID: %06u",
- (int)pthread_self());
+ /* read in a packet */
+ if (charon->socket->receive(charon->socket, &packet) != SUCCESS)
+ {
+ DBG2(DBG_NET, "receiving from socket failed!");
+ return JOB_REQUEUE_FAIR;
+ }
- charon->drop_capabilities(charon, TRUE);
+ /* parse message header */
+ message = message_create_from_packet(packet);
+ if (message->parse_header(message) != SUCCESS)
+ {
+ DBG1(DBG_NET, "received invalid IKE header from %H - ignored",
+ packet->get_source(packet));
+ message->destroy(message);
+ return JOB_REQUEUE_DIRECT;
+ }
- while (TRUE)
+ /* check IKE major version */
+ if (message->get_major_version(message) != IKE_MAJOR_VERSION)
{
- /* read in a packet */
- if (charon->socket->receive(charon->socket, &packet) != SUCCESS)
- {
- DBG2(DBG_NET, "receiving from socket failed!");
- /* try again after a delay */
- sleep(1);
- continue;
- }
-
- /* parse message header */
- message = message_create_from_packet(packet);
- if (message->parse_header(message) != SUCCESS)
+ DBG1(DBG_NET, "received unsupported IKE version %d.%d from %H, "
+ "sending INVALID_MAJOR_VERSION", message->get_major_version(message),
+ message->get_minor_version(message), packet->get_source(packet));
+ send_notify(message, INVALID_MAJOR_VERSION, chunk_empty);
+ message->destroy(message);
+ return JOB_REQUEUE_DIRECT;
+ }
+
+ if (message->get_request(message) &&
+ message->get_exchange_type(message) == IKE_SA_INIT)
+ {
+ /* check for cookies */
+ if (cookie_required(this, message))
{
- DBG1(DBG_NET, "received invalid IKE header from %H - ignored",
- packet->get_source(packet));
+ u_int32_t now = time(NULL);
+ chunk_t cookie = cookie_build(this, message, now - this->secret_offset,
+ chunk_from_thing(this->secret));
+
+ DBG2(DBG_NET, "received packet from: %#H to %#H",
+ message->get_source(message),
+ message->get_destination(message));
+ DBG2(DBG_NET, "sending COOKIE notify to %H",
+ message->get_source(message));
+ send_notify(message, COOKIE, cookie);
+ chunk_free(&cookie);
+ if (++this->secret_used > COOKIE_REUSE)
+ {
+ /* create new cookie */
+ DBG1(DBG_NET, "generating new cookie secret after %d uses",
+ this->secret_used);
+ memcpy(this->secret_old, this->secret, SECRET_LENGTH);
+ this->randomizer->get_pseudo_random_bytes(this->randomizer,
+ SECRET_LENGTH, this->secret);
+ this->secret_switch = now;
+ this->secret_used = 0;
+ }
message->destroy(message);
- continue;
+ return JOB_REQUEUE_DIRECT;
}
- /* check IKE major version */
- if (message->get_major_version(message) != IKE_MAJOR_VERSION)
+ /* check if peer has not too many IKE_SAs half open */
+ if (peer_to_aggressive(this, message))
{
- DBG1(DBG_NET, "received unsupported IKE version %d.%d from %H, "
- "sending INVALID_MAJOR_VERSION", message->get_major_version(message),
- message->get_minor_version(message), packet->get_source(packet));
- send_notify(message, INVALID_MAJOR_VERSION, chunk_empty);
+ DBG1(DBG_NET, "ignoring IKE_SA setup from %H, "
+ "peer to aggressive", message->get_source(message));
message->destroy(message);
- continue;
- }
-
- if (message->get_request(message) &&
- message->get_exchange_type(message) == IKE_SA_INIT)
- {
- /* check for cookies */
- if (cookie_required(this, message))
- {
- u_int32_t now = time(NULL);
- chunk_t cookie = cookie_build(this, message, now - this->secret_offset,
- chunk_from_thing(this->secret));
-
- DBG2(DBG_NET, "received packet from: %#H to %#H",
- message->get_source(message),
- message->get_destination(message));
- DBG2(DBG_NET, "sending COOKIE notify to %H",
- message->get_source(message));
- send_notify(message, COOKIE, cookie);
- chunk_free(&cookie);
- if (++this->secret_used > COOKIE_REUSE)
- {
- /* create new cookie */
- DBG1(DBG_NET, "generating new cookie secret after %d uses",
- this->secret_used);
- memcpy(this->secret_old, this->secret, SECRET_LENGTH);
- this->randomizer->get_pseudo_random_bytes(this->randomizer,
- SECRET_LENGTH, this->secret);
- this->secret_switch = now;
- this->secret_used = 0;
- }
- message->destroy(message);
- continue;
- }
-
- /* check if peer has not too many IKE_SAs half open */
- if (peer_to_aggressive(this, message))
- {
- DBG1(DBG_NET, "ignoring IKE_SA setup from %H, "
- "peer to aggressive", message->get_source(message));
- message->destroy(message);
- continue;
- }
+ return JOB_REQUEUE_DIRECT;
}
- job = (job_t *)process_message_job_create(message);
- charon->job_queue->add(charon->job_queue, job);
}
+ job = (job_t*)process_message_job_create(message);
+ charon->processor->queue_job(charon->processor, job);
+ return JOB_REQUEUE_DIRECT;
}
/**
@@ -340,8 +335,7 @@ static void receive_packets(private_receiver_t *this)
*/
static void destroy(private_receiver_t *this)
{
- pthread_cancel(this->assigned_thread);
- pthread_join(this->assigned_thread, NULL);
+ this->job->cancel(this->job);
this->randomizer->destroy(this->randomizer);
this->hasher->destroy(this->hasher);
free(this);
@@ -366,12 +360,10 @@ receiver_t *receiver_create()
this->secret);
memcpy(this->secret_old, this->secret, SECRET_LENGTH);
- if (pthread_create(&this->assigned_thread, NULL,
- (void*)receive_packets, this) != 0)
- {
- free(this);
- charon->kill(charon, "unable to create receiver thread");
- }
+ this->job = callback_job_create((callback_job_cb_t)receive_packets,
+ this, NULL, NULL);
+ charon->processor->queue_job(charon->processor, (job_t*)this->job);
return &this->public;
}
+
diff --git a/src/charon/network/sender.c b/src/charon/network/sender.c
index 933b8c192..f934dc509 100644
--- a/src/charon/network/sender.c
+++ b/src/charon/network/sender.c
@@ -28,6 +28,7 @@
#include <daemon.h>
#include <network/socket.h>
+#include <processing/jobs/callback_job.h>
typedef struct private_sender_t private_sender_t;
@@ -39,12 +40,12 @@ struct private_sender_t {
/**
* Public part of a sender_t object.
*/
- sender_t public;
+ sender_t public;
- /**
- * Assigned thread.
- */
- pthread_t assigned_thread;
+ /**
+ * Sender threads job.
+ */
+ callback_job_t *job;
/**
* The packets are stored in a linked list
@@ -82,37 +83,29 @@ static void send_(private_sender_t *this, packet_t *packet)
/**
* Implementation of private_sender_t.send_packets.
*/
-static void send_packets(private_sender_t * this)
+static job_requeue_t send_packets(private_sender_t * this)
{
- /* cancellation disabled by default */
- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
- DBG1(DBG_NET, "sender thread running, thread_ID: %06u", (int)pthread_self());
+ packet_t *packet;
+ int oldstate;
- charon->drop_capabilities(charon, TRUE);
-
- while (TRUE)
+ pthread_mutex_lock(&this->mutex);
+ while (this->list->get_count(this->list) == 0)
{
- packet_t *packet;
- int oldstate;
-
- pthread_mutex_lock(&this->mutex);
- /* go to wait while no packets available */
- while (this->list->get_count(this->list) == 0)
- {
- /* add cleanup handler, wait for packet, remove cleanup handler */
- pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&this->mutex);
- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
- pthread_cond_wait(&this->condvar, &this->mutex);
-
- pthread_setcancelstate(oldstate, NULL);
- pthread_cleanup_pop(0);
- }
- this->list->remove_first(this->list, (void**)&packet);
- pthread_mutex_unlock(&this->mutex);
+ /* add cleanup handler, wait for packet, remove cleanup handler */
+ pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&this->mutex);
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+
+ pthread_cond_wait(&this->condvar, &this->mutex);
- charon->socket->send(charon->socket, packet);
- packet->destroy(packet);
+ pthread_setcancelstate(oldstate, NULL);
+ pthread_cleanup_pop(0);
}
+ this->list->remove_first(this->list, (void**)&packet);
+ pthread_mutex_unlock(&this->mutex);
+
+ charon->socket->send(charon->socket, packet);
+ packet->destroy(packet);
+ return JOB_REQUEUE_DIRECT;
}
/**
@@ -125,8 +118,7 @@ static void destroy(private_sender_t *this)
{
sched_yield();
}
- pthread_cancel(this->assigned_thread);
- pthread_join(this->assigned_thread, NULL);
+ this->job->cancel(this->job);
this->list->destroy(this->list);
free(this);
}
@@ -145,11 +137,10 @@ sender_t * sender_create()
pthread_mutex_init(&this->mutex, NULL);
pthread_cond_init(&this->condvar, NULL);
- if (pthread_create(&this->assigned_thread, NULL,
- (void*)send_packets, this) != 0)
- {
- charon->kill(charon, "unable to create sender thread");
- }
+ this->job = callback_job_create((callback_job_cb_t)send_packets,
+ this, NULL, NULL);
+ charon->processor->queue_job(charon->processor, (job_t*)this->job);
- return &(this->public);
+ return &this->public;
}
+
diff --git a/src/charon/processing/event_queue.c b/src/charon/processing/event_queue.c
deleted file mode 100644
index 40bcb1ed8..000000000
--- a/src/charon/processing/event_queue.c
+++ /dev/null
@@ -1,290 +0,0 @@
-/**
- * @file event_queue.c
- *
- * @brief Implementation of event_queue_t
- *
- */
-
-/*
- * Copyright (C) 2005-2006 Martin Willi
- * Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include <pthread.h>
-#include <stdlib.h>
-
-#include "event_queue.h"
-
-#include <library.h>
-#include <utils/linked_list.h>
-
-
-
-typedef struct event_t event_t;
-
-/**
- * Event containing a job and a schedule time
- */
-struct event_t {
- /**
- * Time to fire the event.
- */
- timeval_t time;
-
- /**
- * Every event has its assigned job.
- */
- job_t * job;
-};
-
-/**
- * destroy an event and its job
- */
-static void event_destroy(event_t *event)
-{
- event->job->destroy(event->job);
- free(event);
-}
-
-typedef struct private_event_queue_t private_event_queue_t;
-
-/**
- * Private Variables and Functions of event_queue_t class.
- */
-struct private_event_queue_t {
- /**
- * Public part.
- */
- event_queue_t public;
-
- /**
- * The events are stored in a linked list of type linked_list_t.
- */
- linked_list_t *list;
-
- /**
- * Access to linked_list is locked through this mutex.
- */
- pthread_mutex_t mutex;
-
- /**
- * If the queue is empty or an event has not to be fired
- * a thread has to wait.
- *
- * This condvar is used to wake up such a thread.
- */
- pthread_cond_t condvar;
-};
-
-/**
- * Returns the difference of to timeval structs in milliseconds
- */
-static long time_difference(struct timeval *end_time, struct timeval *start_time)
-{
- time_t s;
- suseconds_t us;
-
- s = (end_time->tv_sec - start_time->tv_sec);
- us = (end_time->tv_usec - start_time->tv_usec);
- return ((s * 1000) + us/1000);
-}
-
-/**
- * Implements event_queue_t.get_count
- */
-static int get_count(private_event_queue_t *this)
-{
- int count;
- pthread_mutex_lock(&(this->mutex));
- count = this->list->get_count(this->list);
- pthread_mutex_unlock(&(this->mutex));
- return count;
-}
-
-/**
- * Implements event_queue_t.get
- */
-static job_t *get(private_event_queue_t *this)
-{
- timespec_t timeout;
- timeval_t current_time;
- event_t * next_event;
- job_t *job;
- int oldstate;
-
- pthread_mutex_lock(&(this->mutex));
-
- while (TRUE)
- {
- while(this->list->get_count(this->list) == 0)
- {
- /* add mutex unlock handler for cancellation, enable cancellation */
- pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&(this->mutex));
- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
-
- pthread_cond_wait( &(this->condvar), &(this->mutex));
-
- /* reset cancellation, remove mutex-unlock handler (without executing) */
- pthread_setcancelstate(oldstate, NULL);
- pthread_cleanup_pop(0);
- }
-
- this->list->get_first(this->list, (void **)&next_event);
-
- gettimeofday(&current_time, NULL);
- long difference = time_difference(&current_time,&(next_event->time));
- if (difference <= 0)
- {
- timeout.tv_sec = next_event->time.tv_sec;
- timeout.tv_nsec = next_event->time.tv_usec * 1000;
-
- /* add mutex unlock handler for cancellation, enable cancellation */
- pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&(this->mutex));
- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
-
- pthread_cond_timedwait(&(this->condvar), &(this->mutex), &timeout);
-
- /* reset cancellation, remove mutex-unlock handler (without executing) */
- pthread_setcancelstate(oldstate, NULL);
- pthread_cleanup_pop(0);
- }
- else
- {
- /* event available */
- this->list->remove_first(this->list, (void **)&next_event);
- job = next_event->job;
- free(next_event);
- break;
- }
- }
- pthread_cond_signal( &(this->condvar));
- pthread_mutex_unlock(&(this->mutex));
-
- return job;
-}
-
-/**
- * Implements function add_absolute of event_queue_t.
- * See #event_queue_s.add_absolute for description.
- */
-static void add_absolute(private_event_queue_t *this, job_t *job, timeval_t time)
-{
- event_t *event;
- event_t *current_event;
- iterator_t *iterator;
-
- /* create event */
- event = malloc_thing(event_t);
- event->time = time;
- event->job = job;
-
- pthread_mutex_lock(&(this->mutex));
-
- /* while just used to break out */
- while(TRUE)
- {
- if (this->list->get_count(this->list) == 0)
- {
- this->list->insert_first(this->list,event);
- break;
- }
-
- /* check last entry */
- this->list->get_last(this->list,(void **) &current_event);
-
- if (time_difference(&(event->time), &(current_event->time)) >= 0)
- {
- /* my event has to be fired after the last event in list */
- this->list->insert_last(this->list,event);
- break;
- }
-
- /* check first entry */
- this->list->get_first(this->list,(void **) &current_event);
-
- if (time_difference(&(event->time), &(current_event->time)) < 0)
- {
- /* my event has to be fired before the first event in list */
- this->list->insert_first(this->list,event);
- break;
- }
-
- iterator = this->list->create_iterator(this->list,TRUE);
- iterator->iterate(iterator, (void**)&current_event);
- /* first element has not to be checked (already done) */
- while(iterator->iterate(iterator, (void**)&current_event))
- {
- if (time_difference(&(event->time), &(current_event->time)) <= 0)
- {
- /* my event has to be fired before the current event in list */
- iterator->insert_before(iterator,event);
- break;
- }
- }
- iterator->destroy(iterator);
- break;
- }
-
- pthread_cond_signal( &(this->condvar));
- pthread_mutex_unlock(&(this->mutex));
-}
-
-/**
- * Implements event_queue_t.add_relative.
- */
-static void add_relative(event_queue_t *this, job_t *job, u_int32_t ms)
-{
- timeval_t current_time;
- timeval_t time;
-
- time_t s = ms / 1000;
- suseconds_t us = (ms - s * 1000) * 1000;
-
- gettimeofday(&current_time, NULL);
-
- time.tv_usec = (current_time.tv_usec + us) % 1000000;
- time.tv_sec = current_time.tv_sec + (current_time.tv_usec + us)/1000000 + s;
-
- this->add_absolute(this, job, time);
-}
-
-
-/**
- * Implements event_queue_t.destroy.
- */
-static void event_queue_destroy(private_event_queue_t *this)
-{
- this->list->destroy_function(this->list, (void*)event_destroy);
- free(this);
-}
-
-/*
- * Documented in header
- */
-event_queue_t *event_queue_create()
-{
- private_event_queue_t *this = malloc_thing(private_event_queue_t);
-
- this->public.get_count = (int (*) (event_queue_t *event_queue)) get_count;
- this->public.get = (job_t *(*) (event_queue_t *event_queue)) get;
- this->public.add_absolute = (void (*) (event_queue_t *event_queue, job_t *job, timeval_t time)) add_absolute;
- this->public.add_relative = (void (*) (event_queue_t *event_queue, job_t *job, u_int32_t ms)) add_relative;
- this->public.destroy = (void (*) (event_queue_t *event_queue)) event_queue_destroy;
-
- this->list = linked_list_create();
- pthread_mutex_init(&(this->mutex), NULL);
- pthread_cond_init(&(this->condvar), NULL);
-
- return (&this->public);
-}
diff --git a/src/charon/processing/event_queue.h b/src/charon/processing/event_queue.h
deleted file mode 100644
index c85286bf2..000000000
--- a/src/charon/processing/event_queue.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/**
- * @file event_queue.h
- *
- * @brief Interface of job_queue_t.
- *
- */
-
-/*
- * Copyright (C) 2005-2006 Martin Willi
- * Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#ifndef EVENT_QUEUE_H_
-#define EVENT_QUEUE_H_
-
-typedef struct event_queue_t event_queue_t;
-
-#include <sys/time.h>
-
-#include <library.h>
-#include <processing/jobs/job.h>
-
-/**
- * @brief Event-Queue used to store timed events.
- *
- * Added events are sorted. The get method blocks until
- * the time is elapsed to process the next event. The get
- * method is called from the scheduler_t thread, which
- * will add the jobs to to job_queue_t for further processing.
- *
- * Although the event-queue is based on a linked_list_t
- * all access functions are thread-save implemented.
- *
- * @b Constructors:
- * - event_queue_create()
- *
- * @ingroup processing
- */
-struct event_queue_t {
-
- /**
- * @brief Returns number of events in queue.
- *
- * @param event_queue calling object
- * @return number of events in queue
- */
- int (*get_count) (event_queue_t *event_queue);
-
- /**
- * @brief Get the next job from the event-queue.
- *
- * If no event is pending, this function blocks until a job can be returned.
- *
- * @param event_queue calling object
- * @param[out] job pointer to a job pointer where to job is returned to
- * @return next job
- */
- job_t *(*get) (event_queue_t *event_queue);
-
- /**
- * @brief Adds a event to the queue, using a relative time.
- *
- * This function is non blocking and adds a job_t at a specific time to the list.
- * The specific job object has to get destroyed by the thread which
- * removes the job.
- *
- * @param event_queue calling object
- * @param[in] job job to add to the queue (job is not copied)
- * @param[in] time relative time, when the event has to get fired
- */
- void (*add_relative) (event_queue_t *event_queue, job_t *job, u_int32_t ms);
-
- /**
- * @brief Adds a event to the queue, using an absolute time.
- *
- * This function is non blocking and adds a job_t at a specific time to the list.
- * The specific job object has to get destroyed by the thread which
- * removes the job.
- *
- * @param event_queue calling object
- * @param[in] job job to add to the queue (job is not copied)
- * @param[in] time absolute time, when the event has to get fired
- */
- void (*add_absolute) (event_queue_t *event_queue, job_t *job, timeval_t time);
-
- /**
- * @brief Destroys a event_queue object.
- *
- * @warning The caller of this function has to make sure
- * that no thread is going to add or get an event from the event_queue
- * after calling this function.
- *
- * @param event_queue calling object
- */
- void (*destroy) (event_queue_t *event_queue);
-};
-
-/**
- * @brief Creates an empty event_queue.
- *
- * @returns event_queue_t object
- *
- * @ingroup processing
- */
-event_queue_t *event_queue_create(void);
-
-#endif /*EVENT_QUEUE_H_*/
diff --git a/src/charon/processing/job_queue.c b/src/charon/processing/job_queue.c
deleted file mode 100644
index 2310ca6ff..000000000
--- a/src/charon/processing/job_queue.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/**
- * @file job_queue.c
- *
- * @brief Implementation of job_queue_t
- *
- */
-
-/*
- * Copyright (C) 2005-2006 Martin Willi
- * Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include <stdlib.h>
-#include <pthread.h>
-
-#include "job_queue.h"
-
-#include <utils/linked_list.h>
-
-
-typedef struct private_job_queue_t private_job_queue_t;
-
-/**
- * @brief Private Variables and Functions of job_queue class
- *
- */
-struct private_job_queue_t {
-
- /**
- * public members
- */
- job_queue_t public;
-
- /**
- * The jobs are stored in a linked list
- */
- linked_list_t *list;
-
- /**
- * access to linked_list is locked through this mutex
- */
- pthread_mutex_t mutex;
-
- /**
- * If the queue is empty a thread has to wait
- * This condvar is used to wake up such a thread
- */
- pthread_cond_t condvar;
-};
-
-
-/**
- * implements job_queue_t.get_count
- */
-static int get_count(private_job_queue_t *this)
-{
- int count;
- pthread_mutex_lock(&(this->mutex));
- count = this->list->get_count(this->list);
- pthread_mutex_unlock(&(this->mutex));
- return count;
-}
-
-/**
- * implements job_queue_t.get
- */
-static job_t *get(private_job_queue_t *this)
-{
- int oldstate;
- job_t *job;
- pthread_mutex_lock(&(this->mutex));
- /* go to wait while no jobs available */
- while(this->list->get_count(this->list) == 0)
- {
- /* add mutex unlock handler for cancellation, enable cancellation */
- pthread_cleanup_push((void(*)(void*))pthread_mutex_unlock, (void*)&(this->mutex));
- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
-
- pthread_cond_wait( &(this->condvar), &(this->mutex));
-
- /* reset cancellation, remove mutex-unlock handler (without executing) */
- pthread_setcancelstate(oldstate, NULL);
- pthread_cleanup_pop(0);
- }
- this->list->remove_first(this->list, (void **)&job);
- pthread_mutex_unlock(&(this->mutex));
- return job;
-}
-
-/**
- * implements function job_queue_t.add
- */
-static void add(private_job_queue_t *this, job_t *job)
-{
- pthread_mutex_lock(&(this->mutex));
- this->list->insert_last(this->list,job);
- pthread_cond_signal( &(this->condvar));
- pthread_mutex_unlock(&(this->mutex));
-}
-
-/**
- * implements job_queue_t.destroy
- */
-static void job_queue_destroy (private_job_queue_t *this)
-{
- this->list->destroy_offset(this->list, offsetof(job_t, destroy));
- free(this);
-}
-
-/*
- *
- * Documented in header
- */
-job_queue_t *job_queue_create(void)
-{
- private_job_queue_t *this = malloc_thing(private_job_queue_t);
-
- this->public.get_count = (int(*)(job_queue_t*))get_count;
- this->public.get = (job_t*(*)(job_queue_t*))get;
- this->public.add = (void(*)(job_queue_t*, job_t*))add;
- this->public.destroy = (void(*)(job_queue_t*))job_queue_destroy;
-
- this->list = linked_list_create();
- pthread_mutex_init(&(this->mutex), NULL);
- pthread_cond_init(&(this->condvar), NULL);
-
- return (&this->public);
-}
diff --git a/src/charon/processing/job_queue.h b/src/charon/processing/job_queue.h
deleted file mode 100644
index 9b58588ae..000000000
--- a/src/charon/processing/job_queue.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * @file job_queue.h
- *
- * @brief Interface of job_queue_t.
- *
- */
-
-/*
- * Copyright (C) 2005-2006 Martin Willi
- * Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#ifndef JOB_QUEUE_H_
-#define JOB_QUEUE_H_
-
-typedef struct job_queue_t job_queue_t;
-
-#include <library.h>
-#include <processing/jobs/job.h>
-
-/**
- * @brief The job queue stores jobs, which will be processed by the thread_pool_t.
- *
- * Jobs are added from various sources, from the threads and
- * from the event_queue_t.
- * Although the job-queue is based on a linked_list_t
- * all access functions are thread-save implemented.
- *
- * @b Constructors:
- * - job_queue_create()
- *
- * @ingroup processing
- */
-struct job_queue_t {
-
- /**
- * @brief Returns number of jobs in queue.
- *
- * @param job_queue_t calling object
- * @returns number of items in queue
- */
- int (*get_count) (job_queue_t *job_queue);
-
- /**
- * @brief Get the next job from the queue.
- *
- * If the queue is empty, this function blocks until a job can be returned.
- * After using, the returned job has to get destroyed by the caller.
- *
- * @param job_queue_t calling object
- * @param[out] job pointer to a job pointer where to job is returned to
- * @return next job
- */
- job_t *(*get) (job_queue_t *job_queue);
-
- /**
- * @brief Adds a job to the queue.
- *
- * This function is non blocking and adds a job_t to the list.
- * The specific job object has to get destroyed by the thread which
- * removes the job.
- *
- * @param job_queue_t calling object
- * @param job job to add to the queue (job is not copied)
- */
- void (*add) (job_queue_t *job_queue, job_t *job);
-
- /**
- * @brief Destroys a job_queue object.
- *
- * @warning The caller of this function has to make sure
- * that no thread is going to add or get a job from the job_queue
- * after calling this function.
- *
- * @param job_queue_t calling object
- */
- void (*destroy) (job_queue_t *job_queue);
-};
-
-/**
- * @brief Creates an empty job_queue.
- *
- * @return job_queue_t object
- *
- * @ingroup processing
- */
-job_queue_t *job_queue_create(void);
-
-#endif /*JOB_QUEUE_H_*/
diff --git a/src/charon/processing/jobs/acquire_job.c b/src/charon/processing/jobs/acquire_job.c
index b4ffb258d..48a77f558 100644
--- a/src/charon/processing/jobs/acquire_job.c
+++ b/src/charon/processing/jobs/acquire_job.c
@@ -43,17 +43,17 @@ struct private_acquire_job_t {
};
/**
- * Implementation of job_t.get_type.
+ * Implementation of job_t.destroy.
*/
-static job_type_t get_type(private_acquire_job_t *this)
+static void destroy(private_acquire_job_t *this)
{
- return ACQUIRE;
+ free(this);
}
/**
* Implementation of job_t.execute.
*/
-static status_t execute(private_acquire_job_t *this)
+static void execute(private_acquire_job_t *this)
{
ike_sa_t *ike_sa;
@@ -63,20 +63,14 @@ static status_t execute(private_acquire_job_t *this)
{
DBG2(DBG_JOB, "CHILD_SA with reqid %d not found for acquiring",
this->reqid);
- return DESTROY_ME;
}
- ike_sa->acquire(ike_sa, this->reqid);
-
- charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
- return DESTROY_ME;
-}
-
-/**
- * Implementation of job_t.destroy.
- */
-static void destroy(private_acquire_job_t *this)
-{
- free(this);
+ else
+ {
+ ike_sa->acquire(ike_sa, this->reqid);
+
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+ destroy(this);
}
/*
@@ -87,12 +81,11 @@ acquire_job_t *acquire_job_create(u_int32_t reqid)
private_acquire_job_t *this = malloc_thing(private_acquire_job_t);
/* interface functions */
- this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
- this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+ this->public.job_interface.execute = (void (*) (job_t *)) execute;
this->public.job_interface.destroy = (void (*)(job_t*)) destroy;
/* private variables */
this->reqid = reqid;
- return &(this->public);
+ return &this->public;
}
diff --git a/src/charon/processing/jobs/callback_job.c b/src/charon/processing/jobs/callback_job.c
new file mode 100644
index 000000000..53e7caa95
--- /dev/null
+++ b/src/charon/processing/jobs/callback_job.c
@@ -0,0 +1,213 @@
+/**
+ * @file callback_job.c
+ *
+ * @brief Implementation of callback_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "callback_job.h"
+
+#include <daemon.h>
+
+typedef struct private_callback_job_t private_callback_job_t;
+
+/**
+ * Private data of an callback_job_t Object.
+ */
+struct private_callback_job_t {
+ /**
+ * Public callback_job_t interface.
+ */
+ callback_job_t public;
+
+ /**
+ * Callback to call on execution
+ */
+ callback_job_cb_t callback;
+
+ /**
+ * parameter to supply to callback
+ */
+ void *data;
+
+ /**
+ * cleanup function for data
+ */
+ callback_job_cleanup_t cleanup;
+
+ /**
+ * thread ID of the job, if running
+ */
+ pthread_t thread;
+
+ /**
+ * mutex to access jobs interna
+ */
+ pthread_mutex_t mutex;
+
+ /**
+ * condvar to synchronize thread startup/cancellation
+ */
+ pthread_cond_t condvar;
+
+ /**
+ * list of asociated child jobs
+ */
+ linked_list_t *children;
+
+ /**
+ * parent of this job, or NULL
+ */
+ private_callback_job_t *parent;
+};
+
+/**
+ * Implements job_t.destroy.
+ */
+static void destroy(private_callback_job_t *this)
+{
+ if (this->cleanup)
+ {
+ this->cleanup(this->data);
+ }
+ this->children->destroy(this->children);
+ free(this);
+}
+
+/**
+ * unregister a child from its parent, if any.
+ */
+static void unregister(private_callback_job_t *this)
+{
+ if (this->parent)
+ {
+ iterator_t *iterator;
+ private_callback_job_t *child;
+
+ pthread_mutex_lock(&this->parent->mutex);
+ iterator = this->parent->children->create_iterator(this->parent->children, TRUE);
+ while (iterator->iterate(iterator, (void**)&child))
+ {
+ if (child == this)
+ {
+ iterator->remove(iterator);
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ pthread_mutex_unlock(&this->parent->mutex);
+ }
+}
+
+/**
+ * Implementation of callback_job_t.cancel.
+ */
+static void cancel(private_callback_job_t *this)
+{
+ pthread_t thread;
+
+ /* wait until thread has started */
+ pthread_mutex_lock(&this->mutex);
+ while (this->thread == 0)
+ {
+ pthread_cond_wait(&this->condvar, &this->mutex);
+ }
+ thread = this->thread;
+
+ /* terminate its children */
+ this->children->invoke(this->children, offsetof(callback_job_t, cancel));
+ pthread_mutex_unlock(&this->mutex);
+
+ /* terminate thread */
+ pthread_cancel(thread);
+ pthread_join(thread, NULL);
+}
+
+/**
+ * Implementation of job_t.execute.
+ */
+static void execute(private_callback_job_t *this)
+{
+ bool cleanup = FALSE;
+
+ pthread_mutex_lock(&this->mutex);
+ this->thread = pthread_self();
+ pthread_cond_signal(&this->condvar);
+ pthread_mutex_unlock(&this->mutex);
+
+ pthread_cleanup_push((void*)destroy, this);
+ while (TRUE)
+ {
+ switch (this->callback(this->data))
+ {
+ case JOB_REQUEUE_DIRECT:
+ continue;
+ case JOB_REQUEUE_FAIR:
+ {
+ charon->processor->queue_job(charon->processor,
+ &this->public.job_interface);
+ break;
+ }
+ case JOB_REQUEUE_NONE:
+ default:
+ {
+ cleanup = TRUE;
+ break;
+ }
+ }
+ break;
+ }
+ unregister(this);
+ pthread_cleanup_pop(cleanup);
+}
+
+/*
+ * Described in header.
+ */
+callback_job_t *callback_job_create(callback_job_cb_t cb, void *data,
+ callback_job_cleanup_t cleanup,
+ callback_job_t *parent)
+{
+ private_callback_job_t *this = malloc_thing(private_callback_job_t);
+
+ /* interface functions */
+ this->public.job_interface.execute = (void (*) (job_t *)) execute;
+ this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
+ this->public.cancel = (void(*)(callback_job_t*))cancel;
+
+ /* private variables */
+ pthread_mutex_init(&this->mutex, NULL);
+ pthread_cond_init(&this->condvar, NULL);
+ this->callback = cb;
+ this->data = data;
+ this->cleanup = cleanup;
+ this->thread = 0;
+ this->children = linked_list_create();
+ this->parent = (private_callback_job_t*)parent;
+
+ /* register us at parent */
+ if (parent)
+ {
+ pthread_mutex_lock(&this->parent->mutex);
+ this->parent->children->insert_last(this->parent->children, this);
+ pthread_mutex_unlock(&this->parent->mutex);
+ }
+
+ return &this->public;
+}
+
diff --git a/src/charon/processing/jobs/callback_job.h b/src/charon/processing/jobs/callback_job.h
new file mode 100644
index 000000000..169f2d207
--- /dev/null
+++ b/src/charon/processing/jobs/callback_job.h
@@ -0,0 +1,135 @@
+/**
+ * @file callback_job.h
+ *
+ * @brief Interface of callback_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef CALLBACK_JOB_H_
+#define CALLBACK_JOB_H_
+
+typedef struct callback_job_t callback_job_t;
+
+#include <library.h>
+#include <processing/jobs/job.h>
+
+
+typedef enum job_requeue_t job_requeue_t;
+
+/**
+ * @brief Job requeueing policy
+ *
+ * The job requeueing policy defines how a job is handled when the callback
+ * function returns.
+ *
+ * @ingroup jobs
+ */
+enum job_requeue_t {
+
+ /**
+ * Do not requeue job, destroy it
+ */
+ JOB_REQUEUE_NONE,
+
+ /**
+ * Reque the job fairly, meaning it has to requeue as any other job
+ */
+ JOB_REQUEUE_FAIR,
+
+ /**
+ * Reexecute the job directly, without the need of requeueing it
+ */
+ JOB_REQUEUE_DIRECT,
+};
+
+/**
+ * @brief The callback function to use for the callback job.
+ *
+ * This is the function to use as callback for a callback job. It receives
+ * a parameter supplied to the callback jobs constructor.
+ *
+ * @param data param supplied to job
+ * @return requeing policy how to requeue the job
+ *
+ * @ingroup jobs
+ */
+typedef job_requeue_t (*callback_job_cb_t)(void *data);
+
+/**
+ * @brief Cleanup function to use for data cleanup.
+ *
+ * The callback has an optional user argument which receives data. However,
+ * this data may be cleaned up if it is allocated. This is the function
+ * to supply to the constructor.
+ *
+ * @param data param supplied to job
+ * @return requeing policy how to requeue the job
+ *
+ * @ingroup jobs
+ */
+typedef void (*callback_job_cleanup_t)(void *data);
+
+/**
+ * @brief Class representing an callback Job.
+ *
+ * This is a special job which allows a simple callback function to
+ * be executed by a thread of the thread pool. This allows simple execution
+ * of asynchronous methods, without to manage threads.
+ *
+ * @b Constructors:
+ * - callback_job_create()
+ *
+ * @ingroup jobs
+ */
+struct callback_job_t {
+ /**
+ * The job_t interface.
+ */
+ job_t job_interface;
+
+ /**
+ * @brief Cancel the jobs thread and wait for its termination.
+ *
+ * @param this calling object
+ */
+ void (*cancel)(callback_job_t *this);
+};
+
+/**
+ * @brief Creates a callback job.
+ *
+ * The cleanup function is called when the job gets destroyed to destroy
+ * the associated data.
+ * If parent is not NULL, the specified job gets an association. Whenever
+ * the parent gets cancelled (or runs out), all of its children are cancelled,
+ * too.
+ *
+ * @param cb callback to call from the processor
+ * @param data user data to supply to callback
+ * @param cleanup destructor for data on destruction, or NULL
+ * @param parent parent of this job
+ * @return callback_job_t object
+ *
+ * @ingroup jobs
+ */
+callback_job_t *callback_job_create(callback_job_cb_t cb, void *data,
+ callback_job_cleanup_t cleanup,
+ callback_job_t *parent);
+
+#endif /* CALLBACK_JOB_H_ */
+
diff --git a/src/charon/processing/jobs/delete_child_sa_job.c b/src/charon/processing/jobs/delete_child_sa_job.c
index f694696b0..23f330293 100644
--- a/src/charon/processing/jobs/delete_child_sa_job.c
+++ b/src/charon/processing/jobs/delete_child_sa_job.c
@@ -54,17 +54,17 @@ struct private_delete_child_sa_job_t {
};
/**
- * Implementation of job_t.get_type.
+ * Implementation of job_t.destroy.
*/
-static job_type_t get_type(private_delete_child_sa_job_t *this)
+static void destroy(private_delete_child_sa_job_t *this)
{
- return DELETE_CHILD_SA;
+ free(this);
}
/**
* Implementation of job_t.execute.
*/
-static status_t execute(private_delete_child_sa_job_t *this)
+static void execute(private_delete_child_sa_job_t *this)
{
ike_sa_t *ike_sa;
@@ -74,20 +74,14 @@ static status_t execute(private_delete_child_sa_job_t *this)
{
DBG1(DBG_JOB, "CHILD_SA with reqid %d not found for delete",
this->reqid);
- return DESTROY_ME;
}
- ike_sa->delete_child_sa(ike_sa, this->protocol, this->spi);
-
- charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
- return DESTROY_ME;
-}
-
-/**
- * Implementation of job_t.destroy.
- */
-static void destroy(private_delete_child_sa_job_t *this)
-{
- free(this);
+ else
+ {
+ ike_sa->delete_child_sa(ike_sa, this->protocol, this->spi);
+
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+ destroy(this);
}
/*
@@ -100,8 +94,7 @@ delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid,
private_delete_child_sa_job_t *this = malloc_thing(private_delete_child_sa_job_t);
/* interface functions */
- this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
- this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+ this->public.job_interface.execute = (void (*) (job_t *)) execute;
this->public.job_interface.destroy = (void (*)(job_t*)) destroy;
/* private variables */
@@ -109,5 +102,6 @@ delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid,
this->protocol = protocol;
this->spi = spi;
- return &(this->public);
+ return &this->public;
}
+
diff --git a/src/charon/processing/jobs/delete_ike_sa_job.c b/src/charon/processing/jobs/delete_ike_sa_job.c
index 706155aa6..8d8c0cf36 100644
--- a/src/charon/processing/jobs/delete_ike_sa_job.c
+++ b/src/charon/processing/jobs/delete_ike_sa_job.c
@@ -47,18 +47,20 @@ struct private_delete_ike_sa_job_t {
bool delete_if_established;
};
+
/**
- * Implements job_t.get_type.
+ * Implements job_t.destroy.
*/
-static job_type_t get_type(private_delete_ike_sa_job_t *this)
+static void destroy(private_delete_ike_sa_job_t *this)
{
- return DELETE_IKE_SA;
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ free(this);
}
/**
* Implementation of job_t.execute.
*/
-static status_t execute(private_delete_ike_sa_job_t *this)
+static void execute(private_delete_ike_sa_job_t *this)
{
ike_sa_t *ike_sa;
@@ -93,16 +95,7 @@ static status_t execute(private_delete_ike_sa_job_t *this)
}
}
}
- return DESTROY_ME;
-}
-
-/**
- * Implements job_t.destroy.
- */
-static void destroy(private_delete_ike_sa_job_t *this)
-{
- this->ike_sa_id->destroy(this->ike_sa_id);
- free(this);
+ destroy(this);
}
/*
@@ -114,8 +107,7 @@ delete_ike_sa_job_t *delete_ike_sa_job_create(ike_sa_id_t *ike_sa_id,
private_delete_ike_sa_job_t *this = malloc_thing(private_delete_ike_sa_job_t);
/* interface functions */
- this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
- this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+ this->public.job_interface.execute = (void (*) (job_t *)) execute;
this->public.job_interface.destroy = (void (*)(job_t *)) destroy;;
/* private variables */
diff --git a/src/charon/processing/jobs/job.c b/src/charon/processing/jobs/job.c
deleted file mode 100644
index d32d1bc61..000000000
--- a/src/charon/processing/jobs/job.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * @file job.c
- *
- * @brief Interface additions to job_t.
- *
- */
-
-/*
- * Copyright (C) 2005-2006 Martin Willi
- * Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-
-#include "job.h"
-
-ENUM(job_type_names, PROCESS_MESSAGE, SEND_DPD,
- "PROCESS_MESSAGE",
- "RETRANSMIT",
- "INITIATE",
- "ROUTE",
- "ACQUIRE",
- "DELETE_IKE_SA",
- "DELETE_CHILD_SA",
- "REKEY_CHILD_SA",
- "REKEY_IKE_SA",
- "SEND_KEEPALIVE",
- "SEND_DPD",
-);
diff --git a/src/charon/processing/jobs/job.h b/src/charon/processing/jobs/job.h
index 28632672d..1826c53b4 100644
--- a/src/charon/processing/jobs/job.h
+++ b/src/charon/processing/jobs/job.h
@@ -24,108 +24,14 @@
#ifndef JOB_H_
#define JOB_H_
-typedef enum job_type_t job_type_t;
typedef struct job_t job_t;
#include <library.h>
-/**
- * @brief Definition of the various job types.
- *
- * @ingroup jobs
- */
-enum job_type_t {
- /**
- * Process an incoming IKEv2-Message.
- *
- * Job is implemented in class process_message_job_t
- */
- PROCESS_MESSAGE,
-
- /**
- * Retransmit an IKEv2-Message.
- *
- * Job is implemented in class retransmit_job_t
- */
- RETRANSMIT,
-
- /**
- * Set up a CHILD_SA, optional with an IKE_SA.
- *
- * Job is implemented in class initiate_job_t
- */
- INITIATE,
-
- /**
- * Install SPD entries.
- *
- * Job is implemented in class route_job_t
- */
- ROUTE,
-
- /**
- * React on a acquire message from the kernel (e.g. setup CHILD_SA)
- *
- * Job is implemented in class acquire_job_t
- */
- ACQUIRE,
-
- /**
- * Delete an IKE_SA.
- *
- * Job is implemented in class delete_ike_sa_job_t
- */
- DELETE_IKE_SA,
-
- /**
- * Delete a CHILD_SA.
- *
- * Job is implemented in class delete_child_sa_job_t
- */
- DELETE_CHILD_SA,
-
- /**
- * Rekey a CHILD_SA.
- *
- * Job is implemented in class rekey_child_sa_job_t
- */
- REKEY_CHILD_SA,
-
- /**
- * Rekey an IKE_SA.
- *
- * Job is implemented in class rekey_ike_sa_job_t
- */
- REKEY_IKE_SA,
-
- /**
- * Send a keepalive packet.
- *
- * Job is implemented in class type send_keepalive_job_t
- */
- SEND_KEEPALIVE,
-
- /**
- * Send a DPD packet.
- *
- * Job is implemented in class type send_dpd_job_t
- */
- SEND_DPD
-};
-
-/**
- * enum name for job_type_t
- *
- * @ingroup jobs
- */
-extern enum_name_t *job_type_names;
-
/**
* @brief Job-Interface as it is stored in the job queue.
*
- * A job consists of a job-type and one or more assigned values.
- *
* @b Constructors:
* - None, use specific implementation of the interface.
*
@@ -134,32 +40,26 @@ extern enum_name_t *job_type_names;
struct job_t {
/**
- * @brief get type of job.
- *
- * @param this calling object
- * @return type of this job
- */
- job_type_t (*get_type) (job_t *this);
-
- /**
* @brief Execute a job.
*
- * Call the internall job routine to process the
- * job. If this method returns DESTROY_ME, the job
- * must be destroyed by the caller.
+ * The processing facility executes a job using this method. Jobs are
+ * one-shot, they destroy themself after execution, so don't use a job
+ * once it has been executed.
*
* @param this calling object
- * @return status of job execution
*/
- status_t (*execute) (job_t *this);
+ void (*execute) (job_t *this);
/**
- * @brief Destroys a job_t object
+ * @brief Destroy a job.
+ *
+ * Is only called whenever a job was not executed (e.g. due daemon shutdown).
+ * After execution, jobs destroy themself.
*
* @param job_t calling object
*/
void (*destroy) (job_t *job);
};
-
#endif /* JOB_H_ */
+
diff --git a/src/charon/processing/jobs/process_message_job.c b/src/charon/processing/jobs/process_message_job.c
index ee7484bbd..6a0921248 100644
--- a/src/charon/processing/jobs/process_message_job.c
+++ b/src/charon/processing/jobs/process_message_job.c
@@ -44,17 +44,18 @@ struct private_process_message_job_t {
};
/**
- * Implements job_t.get_type.
+ * Implements job_t.destroy.
*/
-static job_type_t get_type(private_process_message_job_t *this)
+static void destroy(private_process_message_job_t *this)
{
- return PROCESS_MESSAGE;
+ this->message->destroy(this->message);
+ free(this);
}
/**
* Implementation of job_t.execute.
*/
-static status_t execute(private_process_message_job_t *this)
+static void execute(private_process_message_job_t *this)
{
ike_sa_t *ike_sa;
@@ -75,16 +76,7 @@ static status_t execute(private_process_message_job_t *this)
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
}
- return DESTROY_ME;
-}
-
-/**
- * Implements job_t.destroy.
- */
-static void destroy(private_process_message_job_t *this)
-{
- this->message->destroy(this->message);
- free(this);
+ destroy(this);
}
/*
@@ -95,8 +87,7 @@ process_message_job_t *process_message_job_create(message_t *message)
private_process_message_job_t *this = malloc_thing(private_process_message_job_t);
/* interface functions */
- this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
- this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+ this->public.job_interface.execute = (void (*) (job_t *)) execute;
this->public.job_interface.destroy = (void(*)(job_t*))destroy;
/* private variables */
diff --git a/src/charon/processing/jobs/rekey_child_sa_job.c b/src/charon/processing/jobs/rekey_child_sa_job.c
index 3422b614d..f754e5a1f 100644
--- a/src/charon/processing/jobs/rekey_child_sa_job.c
+++ b/src/charon/processing/jobs/rekey_child_sa_job.c
@@ -53,17 +53,17 @@ struct private_rekey_child_sa_job_t {
};
/**
- * Implementation of job_t.get_type.
+ * Implementation of job_t.destroy.
*/
-static job_type_t get_type(private_rekey_child_sa_job_t *this)
+static void destroy(private_rekey_child_sa_job_t *this)
{
- return REKEY_CHILD_SA;
+ free(this);
}
/**
* Implementation of job_t.execute.
*/
-static status_t execute(private_rekey_child_sa_job_t *this)
+static void execute(private_rekey_child_sa_job_t *this)
{
ike_sa_t *ike_sa;
@@ -73,20 +73,13 @@ static status_t execute(private_rekey_child_sa_job_t *this)
{
DBG2(DBG_JOB, "CHILD_SA with reqid %d not found for rekeying",
this->reqid);
- return DESTROY_ME;
}
- ike_sa->rekey_child_sa(ike_sa, this->protocol, this->spi);
-
- charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
- return DESTROY_ME;
-}
-
-/**
- * Implementation of job_t.destroy.
- */
-static void destroy(private_rekey_child_sa_job_t *this)
-{
- free(this);
+ else
+ {
+ ike_sa->rekey_child_sa(ike_sa, this->protocol, this->spi);
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+ destroy(this);
}
/*
@@ -99,8 +92,7 @@ rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid,
private_rekey_child_sa_job_t *this = malloc_thing(private_rekey_child_sa_job_t);
/* interface functions */
- this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
- this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+ this->public.job_interface.execute = (void (*) (job_t *)) execute;
this->public.job_interface.destroy = (void (*)(job_t*)) destroy;
/* private variables */
@@ -108,5 +100,5 @@ rekey_child_sa_job_t *rekey_child_sa_job_create(u_int32_t reqid,
this->protocol = protocol;
this->spi = spi;
- return &(this->public);
+ return &this->public;
}
diff --git a/src/charon/processing/jobs/rekey_ike_sa_job.c b/src/charon/processing/jobs/rekey_ike_sa_job.c
index f6c058634..020c3cce8 100644
--- a/src/charon/processing/jobs/rekey_ike_sa_job.c
+++ b/src/charon/processing/jobs/rekey_ike_sa_job.c
@@ -48,17 +48,18 @@ struct private_rekey_ike_sa_job_t {
};
/**
- * Implementation of job_t.get_type.
+ * Implementation of job_t.destroy.
*/
-static job_type_t get_type(private_rekey_ike_sa_job_t *this)
+static void destroy(private_rekey_ike_sa_job_t *this)
{
- return REKEY_IKE_SA;
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ free(this);
}
/**
* Implementation of job_t.execute.
*/
-static status_t execute(private_rekey_ike_sa_job_t *this)
+static void execute(private_rekey_ike_sa_job_t *this)
{
ike_sa_t *ike_sa;
status_t status = SUCCESS;
@@ -68,36 +69,28 @@ static status_t execute(private_rekey_ike_sa_job_t *this)
if (ike_sa == NULL)
{
DBG2(DBG_JOB, "IKE_SA to rekey not found");
- return DESTROY_ME;
- }
-
- if (this->reauth)
- {
- ike_sa->reestablish(ike_sa);
}
else
{
- status = ike_sa->rekey(ike_sa);
- }
-
- if (status == DESTROY_ME)
- {
- charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
- }
- else
- {
- charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ if (this->reauth)
+ {
+ status = ike_sa->reestablish(ike_sa);
+ }
+ else
+ {
+ status = ike_sa->rekey(ike_sa);
+ }
+
+ if (status == DESTROY_ME)
+ {
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
+ }
+ else
+ {
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
}
- return DESTROY_ME;
-}
-
-/**
- * Implementation of job_t.destroy.
- */
-static void destroy(private_rekey_ike_sa_job_t *this)
-{
- this->ike_sa_id->destroy(this->ike_sa_id);
- free(this);
+ destroy(this);
}
/*
@@ -108,8 +101,7 @@ rekey_ike_sa_job_t *rekey_ike_sa_job_create(ike_sa_id_t *ike_sa_id, bool reauth)
private_rekey_ike_sa_job_t *this = malloc_thing(private_rekey_ike_sa_job_t);
/* interface functions */
- this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
- this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+ this->public.job_interface.execute = (void (*) (job_t *)) execute;
this->public.job_interface.destroy = (void (*)(job_t*)) destroy;
/* private variables */
diff --git a/src/charon/processing/jobs/retransmit_job.c b/src/charon/processing/jobs/retransmit_job.c
index 5bfa20dfd..8c15aa651 100644
--- a/src/charon/processing/jobs/retransmit_job.c
+++ b/src/charon/processing/jobs/retransmit_job.c
@@ -48,17 +48,18 @@ struct private_retransmit_job_t {
};
/**
- * Implements job_t.get_type.
+ * Implements job_t.destroy.
*/
-static job_type_t get_type(private_retransmit_job_t *this)
+static void destroy(private_retransmit_job_t *this)
{
- return RETRANSMIT;
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ free(this);
}
/**
* Implementation of job_t.execute.
*/
-static status_t execute(private_retransmit_job_t *this)
+static void execute(private_retransmit_job_t *this)
{
ike_sa_t *ike_sa;
@@ -77,16 +78,7 @@ static status_t execute(private_retransmit_job_t *this)
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
}
- return DESTROY_ME;
-}
-
-/**
- * Implements job_t.destroy.
- */
-static void destroy(private_retransmit_job_t *this)
-{
- this->ike_sa_id->destroy(this->ike_sa_id);
- free(this);
+ destroy(this);
}
/*
@@ -97,8 +89,7 @@ retransmit_job_t *retransmit_job_create(u_int32_t message_id,ike_sa_id_t *ike_sa
private_retransmit_job_t *this = malloc_thing(private_retransmit_job_t);
/* interface functions */
- this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
- this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
+ this->public.job_interface.execute = (void (*) (job_t *)) execute;
this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
/* private variables */
diff --git a/src/charon/processing/jobs/roam_job.c b/src/charon/processing/jobs/roam_job.c
new file mode 100644
index 000000000..3b5cd0ed2
--- /dev/null
+++ b/src/charon/processing/jobs/roam_job.c
@@ -0,0 +1,115 @@
+/**
+ * @file roam_job.c
+ *
+ * @brief Implementation of roam_job_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+
+#include <stdlib.h>
+
+#include "roam_job.h"
+
+#include <sa/ike_sa.h>
+#include <daemon.h>
+
+
+typedef struct private_roam_job_t private_roam_job_t;
+
+/**
+ * Private data of an roam_job_t Object
+ */
+struct private_roam_job_t {
+ /**
+ * public roam_job_t interface
+ */
+ roam_job_t public;
+
+ /**
+ * has the address list changed, or the routing only?
+ */
+ bool address;
+};
+
+/**
+ * Implements job_t.destroy.
+ */
+static void destroy(private_roam_job_t *this)
+{
+ free(this);
+}
+
+/**
+ * Implementation of job_t.execute.
+ */
+static void execute(private_roam_job_t *this)
+{
+ ike_sa_t *ike_sa;
+ linked_list_t *list;
+ ike_sa_id_t *id;
+ iterator_t *iterator;
+
+ /* iterating over all IKE_SAs gives us no way to checkin_and_destroy
+ * after a DESTROY_ME, so we check out each available IKE_SA by hand. */
+ list = linked_list_create();
+ iterator = charon->ike_sa_manager->create_iterator(charon->ike_sa_manager);
+ while (iterator->iterate(iterator, (void**)&ike_sa))
+ {
+ id = ike_sa->get_id(ike_sa);
+ list->insert_last(list, id->clone(id));
+ }
+ iterator->destroy(iterator);
+
+ while (list->remove_last(list, (void**)&id) == SUCCESS)
+ {
+ ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id);
+ if (ike_sa)
+ {
+ if (ike_sa->roam(ike_sa, this->address) == DESTROY_ME)
+ {
+ charon->ike_sa_manager->checkin_and_destroy(
+ charon->ike_sa_manager, ike_sa);
+ }
+ else
+ {
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
+ }
+ id->destroy(id);
+ }
+ list->destroy(list);
+
+ destroy(this);
+}
+
+/*
+ * Described in header
+ */
+roam_job_t *roam_job_create(bool address)
+{
+ private_roam_job_t *this = malloc_thing(private_roam_job_t);
+
+ this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
+ this->public.job_interface.execute = (void (*) (job_t *)) execute;
+ this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
+
+ this->address = address;
+
+ return &this->public;
+}
+
diff --git a/src/charon/processing/jobs/roam_job.h b/src/charon/processing/jobs/roam_job.h
new file mode 100644
index 000000000..293b09f08
--- /dev/null
+++ b/src/charon/processing/jobs/roam_job.h
@@ -0,0 +1,61 @@
+/**
+ * @file roam_job.h
+ *
+ * @brief Interface of roam_job_t.
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef ROAM_JOB_H_
+#define ROAM_JOB_H_
+
+typedef struct roam_job_t roam_job_t;
+
+#include <library.h>
+#include <sa/ike_sa_id.h>
+#include <processing/jobs/job.h>
+
+/**
+ * @brief A job to inform IKE_SAs about changed local address setup.
+ *
+ * If a local address appears or disappears, the kernel fires this job to
+ * update all IKE_SAs.
+ *
+ * @b Constructors:
+ * - roam_job_create()
+ *
+ * @ingroup jobs
+ */
+struct roam_job_t {
+
+ /**
+ * implements job_t interface
+ */
+ job_t job_interface;
+};
+
+/**
+ * @brief Creates a job to inform IKE_SAs about an updated address list.
+ *
+ * @param address TRUE if address list changed, FALSE if routing changed
+ * @return initiate_ike_sa_job_t object
+ *
+ * @ingroup jobs
+ */
+roam_job_t *roam_job_create(bool address);
+
+#endif /*ROAM_JOB_H_*/
+
diff --git a/src/charon/processing/jobs/send_dpd_job.c b/src/charon/processing/jobs/send_dpd_job.c
index 7294d78d5..f6786bfb4 100644
--- a/src/charon/processing/jobs/send_dpd_job.c
+++ b/src/charon/processing/jobs/send_dpd_job.c
@@ -47,45 +47,35 @@ struct private_send_dpd_job_t {
};
/**
- * Implements send_dpd_job_t.get_type.
+ * Implements job_t.destroy.
*/
-static job_type_t get_type(private_send_dpd_job_t *this)
+static void destroy(private_send_dpd_job_t *this)
{
- return SEND_DPD;
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ free(this);
}
/**
* Implementation of job_t.execute.
*/
-static status_t execute(private_send_dpd_job_t *this)
+static void execute(private_send_dpd_job_t *this)
{
ike_sa_t *ike_sa;
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
this->ike_sa_id);
- if (ike_sa == NULL)
- {
- return DESTROY_ME;
- }
-
- if (ike_sa->send_dpd(ike_sa) == DESTROY_ME)
+ if (ike_sa)
{
- charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
+ if (ike_sa->send_dpd(ike_sa) == DESTROY_ME)
+ {
+ charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa);
+ }
+ else
+ {
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+ }
}
- else
- {
- charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
- }
- return DESTROY_ME;
-}
-
-/**
- * Implements job_t.destroy.
- */
-static void destroy(private_send_dpd_job_t *this)
-{
- this->ike_sa_id->destroy(this->ike_sa_id);
- free(this);
+ destroy(this);
}
/*
@@ -96,15 +86,12 @@ send_dpd_job_t *send_dpd_job_create(ike_sa_id_t *ike_sa_id)
private_send_dpd_job_t *this = malloc_thing(private_send_dpd_job_t);
/* interface functions */
- this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
- this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
-
- /* public functions */
- this->public.destroy = (void (*)(send_dpd_job_t *)) destroy;
+ this->public.job_interface.execute = (void (*) (job_t *)) execute;
+ this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
/* private variables */
this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
- return &(this->public);
+ return &this->public;
}
diff --git a/src/charon/processing/jobs/send_dpd_job.h b/src/charon/processing/jobs/send_dpd_job.h
index 26c9e2e81..0e4059131 100644
--- a/src/charon/processing/jobs/send_dpd_job.h
+++ b/src/charon/processing/jobs/send_dpd_job.h
@@ -45,13 +45,6 @@ struct send_dpd_job_t {
* implements job_t interface
*/
job_t job_interface;
-
- /**
- * @brief Destroys an send_dpd_job_t object.
- *
- * @param this send_dpd_job_t object to destroy
- */
- void (*destroy) (send_dpd_job_t *this);
};
/**
diff --git a/src/charon/processing/jobs/send_keepalive_job.c b/src/charon/processing/jobs/send_keepalive_job.c
index 1c1cb288e..8cb51e5dd 100644
--- a/src/charon/processing/jobs/send_keepalive_job.c
+++ b/src/charon/processing/jobs/send_keepalive_job.c
@@ -47,38 +47,29 @@ struct private_send_keepalive_job_t {
};
/**
- * Implements send_keepalive_job_t.get_type.
+ * Implements job_t.destroy.
*/
-static job_type_t get_type(private_send_keepalive_job_t *this)
+static void destroy(private_send_keepalive_job_t *this)
{
- return SEND_KEEPALIVE;
+ this->ike_sa_id->destroy(this->ike_sa_id);
+ free(this);
}
/**
* Implementation of job_t.execute.
*/
-static status_t execute(private_send_keepalive_job_t *this)
+static void execute(private_send_keepalive_job_t *this)
{
ike_sa_t *ike_sa;
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
this->ike_sa_id);
- if (ike_sa == NULL)
+ if (ike_sa)
{
- return DESTROY_ME;
+ ike_sa->send_keepalive(ike_sa);
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
- ike_sa->send_keepalive(ike_sa);
- charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
- return DESTROY_ME;
-}
-
-/**
- * Implements job_t.destroy.
- */
-static void destroy(private_send_keepalive_job_t *this)
-{
- this->ike_sa_id->destroy(this->ike_sa_id);
- free(this);
+ destroy(this);
}
/*
@@ -89,15 +80,12 @@ send_keepalive_job_t *send_keepalive_job_create(ike_sa_id_t *ike_sa_id)
private_send_keepalive_job_t *this = malloc_thing(private_send_keepalive_job_t);
/* interface functions */
- this->public.job_interface.get_type = (job_type_t (*) (job_t *)) get_type;
this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
- this->public.job_interface.execute = (status_t (*) (job_t *)) execute;
-
- /* public functions */
- this->public.destroy = (void (*)(send_keepalive_job_t *)) destroy;
+ this->public.job_interface.execute = (void (*) (job_t *)) execute;
+ this->public.job_interface.destroy = (void (*) (job_t *)) destroy;
/* private variables */
this->ike_sa_id = ike_sa_id->clone(ike_sa_id);
- return &(this->public);
+ return &this->public;
}
diff --git a/src/charon/processing/jobs/send_keepalive_job.h b/src/charon/processing/jobs/send_keepalive_job.h
index f7b38337e..e8d214aed 100644
--- a/src/charon/processing/jobs/send_keepalive_job.h
+++ b/src/charon/processing/jobs/send_keepalive_job.h
@@ -44,13 +44,6 @@ struct send_keepalive_job_t {
* implements job_t interface
*/
job_t job_interface;
-
- /**
- * @brief Destroys an send_keepalive_job_t object.
- *
- * @param this send_keepalive_job_t object to destroy
- */
- void (*destroy) (send_keepalive_job_t *this);
};
/**
diff --git a/src/charon/processing/processor.c b/src/charon/processing/processor.c
new file mode 100644
index 000000000..b3815eeb1
--- /dev/null
+++ b/src/charon/processing/processor.c
@@ -0,0 +1,233 @@
+/**
+ * @file processor.c
+ *
+ * @brief Implementation of processor_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stdlib.h>
+#include <pthread.h>
+#include <string.h>
+#include <errno.h>
+
+#include "processor.h"
+
+#include <daemon.h>
+#include <utils/linked_list.h>
+
+
+typedef struct private_processor_t private_processor_t;
+
+/**
+ * @brief Private data of processor_t class.
+ */
+struct private_processor_t {
+ /**
+ * Public processor_t interface.
+ */
+ processor_t public;
+
+ /**
+ * Number of running threads
+ */
+ u_int total_threads;
+
+ /**
+ * Desired number of threads
+ */
+ u_int desired_threads;
+
+ /**
+ * Number of threads waiting for work
+ */
+ u_int idle_threads;
+
+ /**
+ * The jobs are stored in a linked list
+ */
+ linked_list_t *list;
+
+ /**
+ * access to linked_list is locked through this mutex
+ */
+ pthread_mutex_t mutex;
+
+ /**
+ * Condvar to wait for new jobs
+ */
+ pthread_cond_t condvar;
+};
+
+static void process_jobs(private_processor_t *this);
+
+/**
+ * restart a terminated thread
+ */
+static void restart(private_processor_t *this)
+{
+ pthread_t thread;
+
+ if (pthread_create(&thread, NULL, (void*)process_jobs, this) != 0)
+ {
+ this->total_threads--;
+ }
+}
+
+/**
+ * Process queued jobs, called by the worker threads
+ */
+static void process_jobs(private_processor_t *this)
+{
+ int oldstate;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
+
+ DBG2(DBG_JOB, "started worker thread, thread_ID: %06u", (int)pthread_self());
+
+ pthread_mutex_lock(&this->mutex);
+ while (this->desired_threads >= this->total_threads)
+ {
+ job_t *job;
+
+ if (this->list->get_count(this->list) == 0)
+ {
+ this->idle_threads++;
+ pthread_cond_wait(&this->condvar, &this->mutex);
+ this->idle_threads--;
+ continue;
+ }
+ this->list->remove_first(this->list, (void**)&job);
+ pthread_mutex_unlock(&this->mutex);
+ /* terminated threads are restarted, so we have a constant pool */
+ pthread_cleanup_push((void*)restart, this);
+ job->execute(job);
+ pthread_cleanup_pop(0);
+ pthread_mutex_lock(&this->mutex);
+ }
+ this->total_threads--;
+ pthread_cond_broadcast(&this->condvar);
+ pthread_mutex_unlock(&this->mutex);
+}
+
+/**
+ * Implementation of processor_t.get_total_threads.
+ */
+static u_int get_total_threads(private_processor_t *this)
+{
+ return this->total_threads;
+}
+
+/**
+ * Implementation of processor_t.get_idle_threads.
+ */
+static u_int get_idle_threads(private_processor_t *this)
+{
+ return this->idle_threads;
+}
+
+/**
+ * implements processor_t.get_job_load
+ */
+static u_int get_job_load(private_processor_t *this)
+{
+ u_int load;
+ pthread_mutex_lock(&this->mutex);
+ load = this->list->get_count(this->list);
+ pthread_mutex_unlock(&this->mutex);
+ return load;
+}
+
+/**
+ * implements function processor_t.queue_job
+ */
+static void queue_job(private_processor_t *this, job_t *job)
+{
+ pthread_mutex_lock(&this->mutex);
+ this->list->insert_last(this->list, job);
+ pthread_mutex_unlock(&this->mutex);
+ pthread_cond_signal(&this->condvar);
+}
+
+/**
+ * Implementation of processor_t.set_threads.
+ */
+static void set_threads(private_processor_t *this, u_int count)
+{
+ pthread_mutex_lock(&this->mutex);
+ if (count > this->total_threads)
+ { /* increase thread count */
+ int i;
+ pthread_t current;
+
+ this->desired_threads = count;
+ DBG1(DBG_JOB, "spawning %d worker threads", count - this->total_threads);
+ for (i = this->total_threads; i < count; i++)
+ {
+ if (pthread_create(&current, NULL, (void*)process_jobs, this) == 0)
+ {
+ this->total_threads++;
+ }
+ }
+ }
+ else if (count < this->total_threads)
+ { /* decrease thread count */
+ this->desired_threads = count;
+ }
+ pthread_mutex_unlock(&this->mutex);
+}
+
+/**
+ * Implementation of processor_t.destroy.
+ */
+static void destroy(private_processor_t *this)
+{
+ set_threads(this, 0);
+ while (this->total_threads > 0)
+ {
+ pthread_cond_broadcast(&this->condvar);
+ pthread_cond_wait(&this->condvar, &this->mutex);
+ }
+ this->list->destroy_offset(this->list, offsetof(job_t, destroy));
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+processor_t *processor_create(size_t pool_size)
+{
+ private_processor_t *this = malloc_thing(private_processor_t);
+
+ this->public.get_total_threads = (u_int(*)(processor_t*))get_total_threads;
+ this->public.get_idle_threads = (u_int(*)(processor_t*))get_idle_threads;
+ this->public.get_job_load = (u_int(*)(processor_t*))get_job_load;
+ this->public.queue_job = (void(*)(processor_t*, job_t*))queue_job;
+ this->public.set_threads = (void(*)(processor_t*, u_int))set_threads;
+ this->public.destroy = (void(*)(processor_t*))destroy;
+
+ this->list = linked_list_create();
+ pthread_mutex_init(&this->mutex, NULL);
+ pthread_cond_init(&this->condvar, NULL);
+ this->total_threads = 0;
+ this->desired_threads = 0;
+ this->idle_threads = 0;
+
+ return &this->public;
+}
+
diff --git a/src/charon/processing/processor.h b/src/charon/processing/processor.h
new file mode 100644
index 000000000..f12c7f10e
--- /dev/null
+++ b/src/charon/processing/processor.h
@@ -0,0 +1,111 @@
+/**
+ * @file processor.h
+ *
+ * @brief Interface of processor_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2005-2007 Martin Willi
+ * Copyright (C) 2005 Jan Hutter
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef PROCESSOR_H_
+#define PROCESSOR_H_
+
+typedef struct processor_t processor_t;
+
+#include <stdlib.h>
+
+#include <library.h>
+#include <processing/jobs/job.h>
+
+/**
+ * @brief The processor uses threads to process queued jobs.
+ *
+ * @b Constructors:
+ * - processor_create()
+ *
+ * @ingroup processing
+ */
+struct processor_t {
+
+ /**
+ * @brief Get the total number of threads used by the processor.
+ *
+ * @param this calling object
+ * @return size of thread pool
+ */
+ u_int (*get_total_threads) (processor_t *this);
+
+ /**
+ * @brief Get the number of threads currently waiting.
+ *
+ * @param this calling object
+ * @return number of idle threads
+ */
+ u_int (*get_idle_threads) (processor_t *this);
+
+ /**
+ * @brief Get the number of queued jobs.
+ *
+ * @param this calling object
+ * @returns number of items in queue
+ */
+ u_int (*get_job_load) (processor_t *this);
+
+ /**
+ * @brief Adds a job to the queue.
+ *
+ * This function is non blocking and adds a job_t to the queue.
+ *
+ * @param this calling object
+ * @param job job to add to the queue
+ */
+ void (*queue_job) (processor_t *this, job_t *job);
+
+ /**
+ * @brief Set the number of threads to use in the processor.
+ *
+ * If the number of threads is smaller than number of currently running
+ * threads, thread count is decreased. Use 0 to disable the processor.
+ * This call blocks if it decreases thread count until threads have
+ * terminated, so make sure there are not too many blocking jobs.
+ *
+ * @param this calling object
+ * @param count number of threads to allocate
+ */
+ void (*set_threads)(processor_t *this, u_int count);
+
+ /**
+ * @brief Destroy a processor object.
+ *
+ * @param processor calling object
+ */
+ void (*destroy) (processor_t *processor);
+};
+
+/**
+ * @brief Create the thread pool without any threads.
+ *
+ * Use the set_threads method to start processing jobs.
+ *
+ * @return processor_t object
+ *
+ * @ingroup processing
+ */
+processor_t *processor_create();
+
+#endif /*PROCESSOR_H_*/
+
diff --git a/src/charon/processing/scheduler.c b/src/charon/processing/scheduler.c
index 7249e43e6..2706585b0 100644
--- a/src/charon/processing/scheduler.c
+++ b/src/charon/processing/scheduler.c
@@ -23,12 +23,39 @@
#include <stdlib.h>
#include <pthread.h>
+#include <sys/time.h>
#include "scheduler.h"
#include <daemon.h>
-#include <processing/job_queue.h>
+#include <processing/processor.h>
+#include <processing/jobs/callback_job.h>
+typedef struct event_t event_t;
+
+/**
+ * Event containing a job and a schedule time
+ */
+struct event_t {
+ /**
+ * Time to fire the event.
+ */
+ timeval_t time;
+
+ /**
+ * Every event has its assigned job.
+ */
+ job_t *job;
+};
+
+/**
+ * destroy an event and its job
+ */
+static void event_destroy(event_t *event)
+{
+ event->job->destroy(event->job);
+ free(event);
+}
typedef struct private_scheduler_t private_scheduler_t;
@@ -42,36 +69,164 @@ struct private_scheduler_t {
scheduler_t public;
/**
- * Assigned thread.
+ * Job wich schedules
*/
- pthread_t assigned_thread;
+ callback_job_t *job;
+
+ /**
+ * The jobs are scheduled in a list.
+ */
+ linked_list_t *list;
+
+ /**
+ * Exclusive access to list
+ */
+ pthread_mutex_t mutex;
+
+ /**
+ * Condvar to wait for next job.
+ */
+ pthread_cond_t condvar;
};
/**
- * Implementation of private_scheduler_t.get_events.
+ * Returns the difference of two timeval structs in milliseconds
+ */
+static long time_difference(timeval_t *end, timeval_t *start)
+{
+ time_t s;
+ suseconds_t us;
+
+ s = end->tv_sec - start->tv_sec;
+ us = end->tv_usec - start->tv_usec;
+ return (s * 1000 + us/1000);
+}
+
+/**
+ * Get events from the queue and pass it to the processor
*/
-static void get_events(private_scheduler_t * this)
+static job_requeue_t schedule(private_scheduler_t * this)
{
- job_t *current_job;
+ timespec_t timeout;
+ timeval_t now;
+ event_t *event;
+ long difference;
+ int oldstate;
+ bool timed = FALSE;
- /* cancellation disabled by default */
- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+ DBG2(DBG_JOB, "waiting for next event...");
+ pthread_mutex_lock(&this->mutex);
- DBG1(DBG_JOB, "scheduler thread running, thread_ID: %06u",
- (int)pthread_self());
+ gettimeofday(&now, NULL);
+
+ if (this->list->get_count(this->list) > 0)
+ {
+ this->list->get_first(this->list, (void **)&event);
+ difference = time_difference(&now, &event->time);
+ if (difference > 0)
+ {
+ DBG2(DBG_JOB, "got event, queueing job for execution");
+ this->list->remove_first(this->list, (void **)&event);
+ pthread_mutex_unlock(&this->mutex);
+ charon->processor->queue_job(charon->processor, event->job);
+ free(event);
+ return JOB_REQUEUE_DIRECT;
+ }
+ timeout.tv_sec = event->time.tv_sec;
+ timeout.tv_nsec = event->time.tv_usec * 1000;
+ timed = TRUE;
+ }
+ pthread_cleanup_push((void*)pthread_mutex_unlock, &this->mutex);
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
+
+ if (timed)
+ {
+ pthread_cond_timedwait(&this->condvar, &this->mutex, &timeout);
+ }
+ else
+ {
+ pthread_cond_wait(&this->condvar, &this->mutex);
+ }
+ pthread_setcancelstate(oldstate, NULL);
+ pthread_cleanup_pop(0);
+
+ pthread_mutex_unlock(&this->mutex);
+ return JOB_REQUEUE_DIRECT;
+}
- charon->drop_capabilities(charon, TRUE);
+/**
+ * Implements scheduler_t.get_job_load
+ */
+static u_int get_job_load(private_scheduler_t *this)
+{
+ int count;
+ pthread_mutex_lock(&this->mutex);
+ count = this->list->get_count(this->list);
+ pthread_mutex_unlock(&this->mutex);
+ return count;
+}
- while (TRUE)
+/**
+ * Implements scheduler_t.schedule_job.
+ */
+static void schedule_job(private_scheduler_t *this, job_t *job, u_int32_t time)
+{
+ timeval_t now;
+ event_t *event, *current;
+ iterator_t *iterator;
+ time_t s;
+ suseconds_t us;
+
+ event = malloc_thing(event_t);
+ event->job = job;
+
+ /* calculate absolute time */
+ s = time / 1000;
+ us = (time - s * 1000) * 1000;
+ gettimeofday(&now, NULL);
+ event->time.tv_usec = (now.tv_usec + us) % 1000000;
+ event->time.tv_sec = now.tv_sec + (now.tv_usec + us)/1000000 + s;
+
+ pthread_mutex_lock(&this->mutex);
+ while(TRUE)
{
- DBG2(DBG_JOB, "waiting for next event...");
- /* get a job, this block until one is available */
- current_job = charon->event_queue->get(charon->event_queue);
- /* queue the job in the job queue, workers will eat them */
- DBG2(DBG_JOB, "got event, adding job %N to job-queue",
- job_type_names, current_job->get_type(current_job));
- charon->job_queue->add(charon->job_queue, current_job);
+ if (this->list->get_count(this->list) == 0)
+ {
+ this->list->insert_first(this->list,event);
+ break;
+ }
+
+ this->list->get_last(this->list, (void**)&current);
+ if (time_difference(&event->time, &current->time) >= 0)
+ { /* new event has to be fired after the last event in list */
+ this->list->insert_last(this->list, event);
+ break;
+ }
+
+ this->list->get_first(this->list, (void**)&current);
+ if (time_difference(&event->time, &current->time) < 0)
+ { /* new event has to be fired before the first event in list */
+ this->list->insert_first(this->list, event);
+ break;
+ }
+
+ iterator = this->list->create_iterator(this->list, TRUE);
+ /* first element has not to be checked (already done) */
+ iterator->iterate(iterator, (void**)&current);
+ while(iterator->iterate(iterator, (void**)&current))
+ {
+ if (time_difference(&event->time, &current->time) <= 0)
+ {
+ /* new event has to be fired before the current event in list */
+ iterator->insert_before(iterator, event);
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+ break;
}
+ pthread_cond_signal(&this->condvar);
+ pthread_mutex_unlock(&this->mutex);
}
/**
@@ -79,8 +234,8 @@ static void get_events(private_scheduler_t * this)
*/
static void destroy(private_scheduler_t *this)
{
- pthread_cancel(this->assigned_thread);
- pthread_join(this->assigned_thread, NULL);
+ this->job->cancel(this->job);
+ this->list->destroy_function(this->list, (void*)event_destroy);
free(this);
}
@@ -91,14 +246,17 @@ scheduler_t * scheduler_create()
{
private_scheduler_t *this = malloc_thing(private_scheduler_t);
+ this->public.get_job_load = (u_int (*) (scheduler_t *this)) get_job_load;
+ this->public.schedule_job = (void (*) (scheduler_t *this, job_t *job, u_int32_t ms)) schedule_job;
this->public.destroy = (void(*)(scheduler_t*)) destroy;
- if (pthread_create(&(this->assigned_thread), NULL, (void*(*)(void*))get_events, this) != 0)
- {
- /* thread could not be created */
- free(this);
- charon->kill(charon, "unable to create scheduler thread");
- }
+ this->list = linked_list_create();
+ pthread_mutex_init(&this->mutex, NULL);
+ pthread_cond_init(&this->condvar, NULL);
+
+ this->job = callback_job_create((callback_job_cb_t)schedule, this, NULL, NULL);
+ charon->processor->queue_job(charon->processor, (job_t*)this->job);
- return &(this->public);
+ return &this->public;
}
+
diff --git a/src/charon/processing/scheduler.h b/src/charon/processing/scheduler.h
index bea93e7c9..7bde6e638 100644
--- a/src/charon/processing/scheduler.h
+++ b/src/charon/processing/scheduler.h
@@ -6,7 +6,7 @@
*/
/*
- * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005-2007 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
@@ -27,14 +27,12 @@
typedef struct scheduler_t scheduler_t;
#include <library.h>
+#include <processing/jobs/job.h>
/**
- * @brief The scheduler thread is responsible for timed events.
+ * @brief The scheduler queues and executes timed events.
*
- * The scheduler thread takes out jobs from the event-queue and adds them
- * to the job-queue.
- *
- * Starts a thread which does the work, since event-queue is blocking.
+ * The scheduler stores timed events and passes them to the processor.
*
* @b Constructors:
* - scheduler_create()
@@ -44,25 +42,40 @@ typedef struct scheduler_t scheduler_t;
struct scheduler_t {
/**
+ * @brief Adds a event to the queue, using a relative time offset.
+ *
+ * Schedules a job for execution using a relative time offset.
+ *
+ * @param this calling object
+ * @param job job to schedule
+ * @param time relative to to schedule job (in ms)
+ */
+ void (*schedule_job) (scheduler_t *this, job_t *job, u_int32_t time);
+
+ /**
+ * @brief Returns number of jobs scheduled.
+ *
+ * @param this calling object
+ * @return number of scheduled jobs
+ */
+ u_int (*get_job_load) (scheduler_t *this);
+
+ /**
* @brief Destroys a scheduler object.
*
- * @param scheduler calling object
+ * @param this calling object
*/
- void (*destroy) (scheduler_t *scheduler);
+ void (*destroy) (scheduler_t *this);
};
/**
- * @brief Create a scheduler with its associated thread.
- *
- * The thread will start to get jobs form the event queue
- * and adds them to the job queue.
+ * @brief Create a scheduler.
*
- * @return
- * - scheduler_t object
- * - NULL if thread could not be started
+ * @return scheduler_t object
*
* @ingroup processing
*/
-scheduler_t * scheduler_create(void);
+scheduler_t *scheduler_create(void);
#endif /*SCHEDULER_H_*/
+
diff --git a/src/charon/processing/thread_pool.c b/src/charon/processing/thread_pool.c
deleted file mode 100644
index a9891da15..000000000
--- a/src/charon/processing/thread_pool.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/**
- * @file thread_pool.c
- *
- * @brief Implementation of thread_pool_t.
- *
- */
-
-/*
- * Copyright (C) 2005-2006 Martin Willi
- * Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#include <stdlib.h>
-#include <pthread.h>
-#include <string.h>
-#include <errno.h>
-
-#include "thread_pool.h"
-
-#include <daemon.h>
-#include <processing/job_queue.h>
-
-
-typedef struct private_thread_pool_t private_thread_pool_t;
-
-/**
- * @brief Private data of thread_pool_t class.
- */
-struct private_thread_pool_t {
- /**
- * Public thread_pool_t interface.
- */
- thread_pool_t public;
-
- /**
- * Number of running threads.
- */
- u_int pool_size;
-
- /**
- * Number of threads waiting for work
- */
- u_int idle_threads;
-
- /**
- * Array of thread ids.
- */
- pthread_t *threads;
-};
-
-/**
- * Implementation of private_thread_pool_t.process_jobs.
- */
-static void process_jobs(private_thread_pool_t *this)
-{
- job_t *job;
- status_t status;
-
- /* cancellation disabled by default */
- pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
-
- DBG1(DBG_JOB, "worker thread running, thread_ID: %06u",
- (int)pthread_self());
-
- charon->drop_capabilities(charon, TRUE);
-
- while (TRUE)
- {
- /* TODO: should be atomic, but is not mission critical */
- this->idle_threads++;
- job = charon->job_queue->get(charon->job_queue);
- this->idle_threads--;
-
- status = job->execute(job);
-
- if (status == DESTROY_ME)
- {
- job->destroy(job);
- }
- }
-}
-
-/**
- * Implementation of thread_pool_t.get_pool_size.
- */
-static u_int get_pool_size(private_thread_pool_t *this)
-{
- return this->pool_size;
-}
-
-/**
- * Implementation of thread_pool_t.get_idle_threads.
- */
-static u_int get_idle_threads(private_thread_pool_t *this)
-{
- return this->idle_threads;
-}
-
-/**
- * Implementation of thread_pool_t.destroy.
- */
-static void destroy(private_thread_pool_t *this)
-{
- int current;
- /* flag thread for termination */
- for (current = 0; current < this->pool_size; current++)
- {
- DBG1(DBG_JOB, "cancelling worker thread #%d", current+1);
- pthread_cancel(this->threads[current]);
- }
-
- /* wait for all threads */
- for (current = 0; current < this->pool_size; current++) {
- if (pthread_join(this->threads[current], NULL) == 0)
- {
- DBG1(DBG_JOB, "worker thread #%d terminated", current+1);
- }
- else
- {
- DBG1(DBG_JOB, "could not terminate worker thread #%d", current+1);
- }
- }
-
- /* free mem */
- free(this->threads);
- free(this);
-}
-
-/*
- * Described in header.
- */
-thread_pool_t *thread_pool_create(size_t pool_size)
-{
- int current;
- private_thread_pool_t *this = malloc_thing(private_thread_pool_t);
-
- /* fill in public fields */
- this->public.destroy = (void(*)(thread_pool_t*))destroy;
- this->public.get_pool_size = (u_int(*)(thread_pool_t*))get_pool_size;
- this->public.get_idle_threads = (u_int(*)(thread_pool_t*))get_idle_threads;
-
- /* initialize member */
- this->pool_size = pool_size;
- this->idle_threads = 0;
- this->threads = malloc(sizeof(pthread_t) * pool_size);
-
- /* try to create as many threads as possible, up to pool_size */
- for (current = 0; current < pool_size; current++)
- {
- if (pthread_create(&(this->threads[current]), NULL,
- (void*(*)(void*))process_jobs, this) == 0)
- {
- DBG1(DBG_JOB, "created worker thread #%d", current+1);
- }
- else
- {
- /* creation failed, is it the first one? */
- if (current == 0)
- {
- free(this->threads);
- free(this);
- charon->kill(charon, "could not create any worker threads");
- }
- /* not all threads could be created, but at least one :-/ */
- DBG1(DBG_JOB, "could only create %d from requested %d threads!",
- current, pool_size);
- this->pool_size = current;
- break;
- }
- }
- return (thread_pool_t*)this;
-}
diff --git a/src/charon/processing/thread_pool.h b/src/charon/processing/thread_pool.h
deleted file mode 100644
index 09a6312a8..000000000
--- a/src/charon/processing/thread_pool.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * @file thread_pool.h
- *
- * @brief Interface of thread_pool_t.
- *
- */
-
-/*
- * Copyright (C) 2005-2006 Martin Willi
- * Copyright (C) 2005 Jan Hutter
- * Hochschule fuer Technik Rapperswil
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
-
-#ifndef THREAD_POOL_H_
-#define THREAD_POOL_H_
-
-typedef struct thread_pool_t thread_pool_t;
-
-#include <stdlib.h>
-
-#include <library.h>
-
-/**
- * @brief A thread_pool consists of a pool of threads processing jobs from the job queue.
- *
- * Current implementation uses as many threads as specified in constructor.
- * A more improved version would dynamically increase thread count if necessary.
- *
- * @b Constructors:
- * - thread_pool_create()
- *
- * @todo Add support for dynamic thread handling
- *
- * @ingroup processing
- */
-struct thread_pool_t {
-
- /**
- * @brief Return currently instanciated thread count.
- *
- * @param thread_pool calling object
- * @return size of thread pool
- */
- u_int (*get_pool_size) (thread_pool_t *thread_pool);
-
- /**
- * @brief Get the number of threads currently waiting for work.
- *
- * @param thread_pool calling object
- * @return number of idle threads
- */
- u_int (*get_idle_threads) (thread_pool_t *thread_pool);
-
- /**
- * @brief Destroy a thread_pool_t object.
- *
- * Sends cancellation request to all threads and AWAITS their termination.
- *
- * @param thread_pool calling object
- */
- void (*destroy) (thread_pool_t *thread_pool);
-};
-
-/**
- * @brief Create the thread pool using using pool_size of threads.
- *
- * @param pool_size desired pool size
- * @return
- * - thread_pool_t object if one ore more threads could be started, or
- * - NULL if no threads could be created
- *
- * @ingroup processing
- */
-thread_pool_t *thread_pool_create(size_t pool_size);
-
-
-#endif /*THREAD_POOL_H_*/
diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c
index 1e7b6cb2c..118af3b30 100644
--- a/src/charon/sa/child_sa.c
+++ b/src/charon/sa/child_sa.c
@@ -60,7 +60,7 @@ struct sa_policy_t {
typedef struct private_child_sa_t private_child_sa_t;
/**
- * Private data of a child_sa_t bject.
+ * Private data of a child_sa_t object.
*/
struct private_child_sa_t {
/**
@@ -138,9 +138,9 @@ struct private_child_sa_t {
child_sa_state_t state;
/**
- * Specifies if NAT traversal is used
+ * Specifies if UDP encapsulation is enabled (NAT traversal)
*/
- bool use_natt;
+ bool encap;
/**
* mode this SA uses, tunnel/transport
@@ -156,6 +156,11 @@ struct private_child_sa_t {
* config used to create this child
*/
child_cfg_t *config;
+
+ /**
+ * cached interface name for iptables
+ */
+ char *iface;
};
/**
@@ -276,11 +281,10 @@ static void updown(private_child_sa_t *this, bool up)
while (iterator->iterate(iterator, (void**)&policy))
{
char command[1024];
- char *ifname = NULL;
char *my_client, *other_client, *my_client_mask, *other_client_mask;
char *pos, *virtual_ip;
FILE *shell;
-
+
/* get subnet/bits from string */
asprintf(&my_client, "%R", policy->my_ts);
pos = strchr(my_client, '/');
@@ -301,18 +305,24 @@ static void updown(private_child_sa_t *this, bool up)
*pos = '\0';
}
- if (this->virtual_ip)
- {
- asprintf(&virtual_ip, "PLUTO_MY_SOURCEIP='%H' ",
- this->virtual_ip);
- }
- else
- {
- asprintf(&virtual_ip, "");
- }
+ if (this->virtual_ip)
+ {
+ asprintf(&virtual_ip, "PLUTO_MY_SOURCEIP='%H' ",
+ this->virtual_ip);
+ }
+ else
+ {
+ asprintf(&virtual_ip, "");
+ }
- ifname = charon->kernel_interface->get_interface(charon->kernel_interface,
- this->me.addr);
+ /* we cache the iface name, as it may not be available when
+ * the SA gets deleted */
+ if (up)
+ {
+ free(this->iface);
+ this->iface = charon->kernel_interface->get_interface(
+ charon->kernel_interface, this->me.addr);
+ }
/* build the command with all env variables.
* TODO: PLUTO_PEER_CA and PLUTO_NEXT_HOP are currently missing
@@ -346,7 +356,7 @@ static void updown(private_child_sa_t *this, bool up)
this->me.addr) ? "-host" : "-client",
this->me.addr->get_family(this->me.addr) == AF_INET ? "" : "-ipv6",
this->config->get_name(this->config),
- ifname ? ifname : "(unknown)",
+ this->iface ? this->iface : "unknown",
this->reqid,
this->me.addr,
this->me.id,
@@ -364,11 +374,11 @@ static void updown(private_child_sa_t *this, bool up)
this->config->get_hostaccess(this->config) ?
"PLUTO_HOST_ACCESS='1' " : "",
script);
- free(ifname);
free(my_client);
free(other_client);
free(virtual_ip);
+ DBG3(DBG_CHD, "running updown script: %s", command);
shell = popen(command, "r");
if (shell == NULL)
@@ -494,7 +504,6 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal,
algorithm_t int_algo_none = {AUTH_UNDEFINED, 0};
host_t *src;
host_t *dst;
- natt_conf_t *natt;
status_t status;
this->protocol = proposal->get_protocol(proposal);
@@ -561,18 +570,6 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal,
int_algo = &int_algo_none;
}
- /* setup nat-t */
- if (this->use_natt)
- {
- natt = alloca(sizeof(natt_conf_t));
- natt->sport = src->get_port(src);
- natt->dport = dst->get_port(dst);
- }
- else
- {
- natt = NULL;
- }
-
soft = this->config->get_lifetime(this->config, TRUE);
hard = this->config->get_lifetime(this->config, FALSE);
@@ -582,7 +579,7 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal,
src, dst, spi, this->protocol,
this->reqid, mine ? soft : 0,
hard, enc_algo, int_algo,
- prf_plus, natt, mode, mine);
+ prf_plus, mode, this->encap, mine);
this->encryption = *enc_algo;
this->integrity = *int_algo;
@@ -689,15 +686,15 @@ static status_t add_policies(private_child_sa_t *this,
/* install 3 policies: out, in and forward */
status = charon->kernel_interface->add_policy(charon->kernel_interface,
this->me.addr, this->other.addr, my_ts, other_ts, POLICY_OUT,
- this->protocol, this->reqid, high_prio, mode, FALSE);
+ this->protocol, this->reqid, high_prio, mode);
status |= charon->kernel_interface->add_policy(charon->kernel_interface,
this->other.addr, this->me.addr, other_ts, my_ts, POLICY_IN,
- this->protocol, this->reqid, high_prio, mode, FALSE);
+ this->protocol, this->reqid, high_prio, mode);
status |= charon->kernel_interface->add_policy(charon->kernel_interface,
this->other.addr, this->me.addr, other_ts, my_ts, POLICY_FWD,
- this->protocol, this->reqid, high_prio, mode, FALSE);
+ this->protocol, this->reqid, high_prio, mode);
if (status != SUCCESS)
{
@@ -782,139 +779,89 @@ static status_t get_use_time(private_child_sa_t *this, bool inbound, time_t *use
}
/**
- * Update the host adress/port of a SA
- */
-static status_t update_sa_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other,
- int my_changes, int other_changes, bool mine)
-{
- host_t *src, *dst, *new_src, *new_dst;
- int src_changes, dst_changes;
- status_t status;
- u_int32_t spi;
-
- if (mine)
- {
- src = this->other.addr;
- dst = this->me.addr;
- new_src = new_other;
- new_dst = new_me;
- src_changes = other_changes;
- dst_changes = my_changes;
- spi = this->other.spi;
- }
- else
- {
- src = this->me.addr;
- dst = this->other.addr;
- new_src = new_me;
- new_dst = new_other;
- src_changes = my_changes;
- dst_changes = other_changes;
- spi = this->me.spi;
- }
-
- DBG2(DBG_CHD, "updating %N SA 0x%x, from %#H..#H to %#H..%#H",
- protocol_id_names, this->protocol, ntohl(spi), src, dst, new_src, new_dst);
-
- status = charon->kernel_interface->update_sa(charon->kernel_interface,
- dst, spi, this->protocol,
- new_src, new_dst,
- src_changes, dst_changes);
-
- if (status != SUCCESS)
- {
- return FAILED;
- }
- return SUCCESS;
-}
-
-/**
- * Update the host adress/port of a policy
- */
-static status_t update_policy_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other)
-{
- iterator_t *iterator;
- sa_policy_t *policy;
- status_t status;
- /* we always use high priorities, as hosts getting updated are INSTALLED */
-
- iterator = this->policies->create_iterator(this->policies, TRUE);
- while (iterator->iterate(iterator, (void**)&policy))
- {
- status = charon->kernel_interface->add_policy(
- charon->kernel_interface,
- new_me, new_other,
- policy->my_ts, policy->other_ts,
- POLICY_OUT, this->protocol, this->reqid, TRUE, this->mode, TRUE);
-
- status |= charon->kernel_interface->add_policy(
- charon->kernel_interface,
- new_other, new_me,
- policy->other_ts, policy->my_ts,
- POLICY_IN, this->protocol, this->reqid, TRUE, this->mode, TRUE);
-
- status |= charon->kernel_interface->add_policy(
- charon->kernel_interface,
- new_other, new_me,
- policy->other_ts, policy->my_ts,
- POLICY_FWD, this->protocol, this->reqid, TRUE, this->mode, TRUE);
-
- if (status != SUCCESS)
- {
- iterator->destroy(iterator);
- return FAILED;
- }
- }
- iterator->destroy(iterator);
-
- return SUCCESS;
-}
-
-/**
* Implementation of child_sa_t.update_hosts.
*/
-static status_t update_hosts(private_child_sa_t *this, host_t *new_me, host_t *new_other,
- host_diff_t my_changes, host_diff_t other_changes)
+static status_t update_hosts(private_child_sa_t *this,
+ host_t *me, host_t *other, bool encap)
{
- if (!my_changes && !other_changes)
+ /* anything changed at all? */
+ if (me->equals(me, this->me.addr) &&
+ other->equals(other, this->other.addr) && this->encap == encap)
{
return SUCCESS;
}
-
+ /* run updown script to remove iptables rules */
+ updown(this, FALSE);
+
+ this->encap = encap;
+
/* update our (initator) SAs */
- if (update_sa_hosts(this, new_me, new_other, my_changes, other_changes, TRUE) != SUCCESS)
- {
- return FAILED;
- }
-
+ charon->kernel_interface->update_sa(charon->kernel_interface, this->me.spi,
+ this->protocol, this->other.addr, this->me.addr, other, me, encap);
/* update his (responder) SAs */
- if (update_sa_hosts(this, new_me, new_other, my_changes, other_changes, FALSE) != SUCCESS)
- {
- return FAILED;
- }
+ charon->kernel_interface->update_sa(charon->kernel_interface, this->other.spi,
+ this->protocol, this->me.addr, this->other.addr, me, other, encap);
/* update policies */
- if (my_changes & HOST_DIFF_ADDR || other_changes & HOST_DIFF_ADDR)
+ if (!me->ip_equals(me, this->me.addr) ||
+ !other->ip_equals(other, this->other.addr))
{
- if (update_policy_hosts(this, new_me, new_other) != SUCCESS)
+ iterator_t *iterator;
+ sa_policy_t *policy;
+
+ /* always use high priorities, as hosts getting updated are INSTALLED */
+ iterator = this->policies->create_iterator(this->policies, TRUE);
+ while (iterator->iterate(iterator, (void**)&policy))
{
- return FAILED;
+ /* remove old policies first */
+ charon->kernel_interface->del_policy(charon->kernel_interface,
+ policy->my_ts, policy->other_ts, POLICY_OUT);
+ charon->kernel_interface->del_policy(charon->kernel_interface,
+ policy->other_ts, policy->my_ts, POLICY_IN);
+ charon->kernel_interface->del_policy(charon->kernel_interface,
+ policy->other_ts, policy->my_ts, POLICY_FWD);
+
+ /* check wether we have to update a "dynamic" traffic selector */
+ if (!me->ip_equals(me, this->me.addr) &&
+ policy->my_ts->is_host(policy->my_ts, this->me.addr))
+ {
+ policy->my_ts->set_address(policy->my_ts, me);
+ }
+ if (!other->ip_equals(other, this->other.addr) &&
+ policy->other_ts->is_host(policy->other_ts, this->other.addr))
+ {
+ policy->other_ts->set_address(policy->other_ts, other);
+ }
+
+ /* reinstall updated policies */
+ charon->kernel_interface->add_policy(charon->kernel_interface,
+ me, other, policy->my_ts, policy->other_ts, POLICY_OUT,
+ this->protocol, this->reqid, TRUE, this->mode);
+ charon->kernel_interface->add_policy(charon->kernel_interface,
+ other, me, policy->other_ts, policy->my_ts, POLICY_IN,
+ this->protocol, this->reqid, TRUE, this->mode);
+ charon->kernel_interface->add_policy(charon->kernel_interface,
+ other, me, policy->other_ts, policy->my_ts, POLICY_FWD,
+ this->protocol, this->reqid, TRUE, this->mode);
}
+ iterator->destroy(iterator);
}
- /* update hosts */
- if (my_changes)
+ /* apply hosts */
+ if (!me->equals(me, this->me.addr))
{
this->me.addr->destroy(this->me.addr);
- this->me.addr = new_me->clone(new_me);
+ this->me.addr = me->clone(me);
}
-
- if (other_changes)
+ if (!other->equals(other, this->other.addr))
{
this->other.addr->destroy(this->other.addr);
- this->other.addr = new_other->clone(new_other);
- }
-
+ this->other.addr = other->clone(other);
+ }
+
+ /* install new iptables rules */
+ updown(this, TRUE);
+
return SUCCESS;
}
@@ -988,6 +935,7 @@ static void destroy(private_child_sa_t *this)
this->me.id->destroy(this->me.id);
this->other.id->destroy(this->other.id);
this->config->destroy(this->config);
+ free(this->iface);
DESTROY_IF(this->virtual_ip);
free(this);
}
@@ -997,7 +945,7 @@ static void destroy(private_child_sa_t *this)
*/
child_sa_t * child_sa_create(host_t *me, host_t* other,
identification_t *my_id, identification_t *other_id,
- child_cfg_t *config, u_int32_t rekey, bool use_natt)
+ child_cfg_t *config, u_int32_t rekey, bool encap)
{
static u_int32_t reqid = 0;
private_child_sa_t *this = malloc_thing(private_child_sa_t);
@@ -1011,7 +959,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc;
this->public.add = (status_t(*)(child_sa_t*,proposal_t*,mode_t,prf_plus_t*))add;
this->public.update = (status_t(*)(child_sa_t*,proposal_t*,mode_t,prf_plus_t*))update;
- this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,host_diff_t,host_diff_t))update_hosts;
+ this->public.update_hosts = (status_t (*)(child_sa_t*,host_t*,host_t*,bool))update_hosts;
this->public.add_policies = (status_t (*)(child_sa_t*, linked_list_t*,linked_list_t*,mode_t))add_policies;
this->public.get_traffic_selectors = (linked_list_t*(*)(child_sa_t*,bool))get_traffic_selectors;
this->public.get_use_time = (status_t (*)(child_sa_t*,bool,time_t*))get_use_time;
@@ -1030,7 +978,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
this->other.spi = 0;
this->alloc_ah_spi = 0;
this->alloc_esp_spi = 0;
- this->use_natt = use_natt;
+ this->encap = encap;
this->state = CHILD_CREATED;
/* reuse old reqid if we are rekeying an existing CHILD_SA */
this->reqid = rekey ? rekey : ++reqid;
@@ -1044,6 +992,7 @@ child_sa_t * child_sa_create(host_t *me, host_t* other,
this->protocol = PROTO_NONE;
this->mode = MODE_TUNNEL;
this->virtual_ip = NULL;
+ this->iface = NULL;
this->config = config;
config->get_ref(config);
diff --git a/src/charon/sa/child_sa.h b/src/charon/sa/child_sa.h
index cf5f3e7d7..b801dd012 100644
--- a/src/charon/sa/child_sa.h
+++ b/src/charon/sa/child_sa.h
@@ -35,11 +35,6 @@ typedef struct child_sa_t child_sa_t;
#include <config/child_cfg.h>
/**
- * Where we should start with reqid enumeration
- */
-#define REQID_START 2000000000
-
-/**
* @brief States of a CHILD_SA
*/
enum child_sa_state_t {
@@ -200,19 +195,18 @@ struct child_sa_t {
prf_plus_t *prf_plus);
/**
- * @brief Update the hosts in the kernel SAs and policies
+ * @brief Update the hosts in the kernel SAs and policies.
*
- * @warning only call this after update() has been called.
+ * The CHILD must be INSTALLED to do this update.
*
- * @param this calling object
- * @param new_me the new local host
- * @param new_other the new remote host
- * @param my_diff differences to apply for me
- * @param other_diff differences to apply for other
- * @return SUCCESS or FAILED
+ * @param this calling object
+ * @param me the new local host
+ * @param other the new remote host
+ * @param TRUE to use UDP encapsulation for NAT traversal
+ * @return SUCCESS or FAILED
*/
- status_t (*update_hosts)(child_sa_t *this, host_t *new_me, host_t *new_other,
- host_diff_t my_diff, host_diff_t other_diff);
+ status_t (*update_hosts)(child_sa_t *this, host_t *me, host_t *other,
+ bool encap);
/**
* @brief Install the policies using some traffic selectors.
@@ -298,13 +292,13 @@ struct child_sa_t {
* @param other_id id of remote peer
* @param config config to use for this CHILD_SA
* @param reqid reqid of old CHILD_SA when rekeying, 0 otherwise
- * @param use_natt TRUE if NAT traversal is used
+ * @param encap TRUE to enable UDP encapsulation (NAT traversal)
* @return child_sa_t object
*
* @ingroup sa
*/
child_sa_t * child_sa_create(host_t *me, host_t *other,
identification_t *my_id, identification_t* other_id,
- child_cfg_t *config, u_int32_t reqid, bool use_natt);
+ child_cfg_t *config, u_int32_t reqid, bool encap);
#endif /*CHILD_SA_H_*/
diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c
index 8b4b53e10..0a996329d 100644
--- a/src/charon/sa/ike_sa.c
+++ b/src/charon/sa/ike_sa.c
@@ -48,10 +48,12 @@
#include <sa/task_manager.h>
#include <sa/tasks/ike_init.h>
#include <sa/tasks/ike_natd.h>
+#include <sa/tasks/ike_mobike.h>
#include <sa/tasks/ike_auth.h>
#include <sa/tasks/ike_config.h>
#include <sa/tasks/ike_cert.h>
#include <sa/tasks/ike_rekey.h>
+#include <sa/tasks/ike_reauth.h>
#include <sa/tasks/ike_delete.h>
#include <sa/tasks/ike_dpd.h>
#include <sa/tasks/child_create.h>
@@ -142,6 +144,16 @@ struct private_ike_sa_t {
* CA that issued the certificate of other
*/
ca_info_t *other_ca;
+
+ /**
+ * set of extensions the peer supports
+ */
+ ike_extension_t extensions;
+
+ /**
+ * set of condition flags currently enabled for this IKE_SA
+ */
+ ike_condition_t conditions;
/**
* Linked List containing the child sa's of the current IKE_SA.
@@ -189,16 +201,6 @@ struct private_ike_sa_t {
chunk_t skp_verify;
/**
- * NAT status of local host.
- */
- bool nat_here;
-
- /**
- * NAT status of remote host.
- */
- bool nat_there;
-
- /**
* Virtual IP on local host, if any
*/
host_t *my_virtual_ip;
@@ -212,6 +214,16 @@ struct private_ike_sa_t {
* List of DNS servers installed by us
*/
linked_list_t *dns_servers;
+
+ /**
+ * list of peers additional addresses, transmitted via MOBIKE
+ */
+ linked_list_t *additional_addresses;
+
+ /**
+ * number pending UPDATE_SA_ADDRESS (MOBIKE)
+ */
+ u_int32_t pending_updates;
/**
* Timestamps for this IKE_SA
@@ -356,33 +368,68 @@ static void set_peer_cfg(private_ike_sa_t *this, peer_cfg_t *peer_cfg)
if (this->my_host->is_anyaddr(this->my_host))
{
host_t *me = this->ike_cfg->get_my_host(this->ike_cfg);
-
set_my_host(this, me->clone(me));
}
if (this->other_host->is_anyaddr(this->other_host))
{
host_t *other = this->ike_cfg->get_other_host(this->ike_cfg);
-
set_other_host(this, other->clone(other));
}
/* apply IDs if they are not already set */
if (this->my_id->contains_wildcards(this->my_id))
{
- identification_t *my_id = this->peer_cfg->get_my_id(this->peer_cfg);
-
DESTROY_IF(this->my_id);
- this->my_id = my_id->clone(my_id);
+ this->my_id = this->peer_cfg->get_my_id(this->peer_cfg);
+ this->my_id = this->my_id->clone(this->my_id);
}
if (this->other_id->contains_wildcards(this->other_id))
{
- identification_t *other_id = this->peer_cfg->get_other_id(this->peer_cfg);
-
DESTROY_IF(this->other_id);
- this->other_id = other_id->clone(other_id);
+ this->other_id = this->peer_cfg->get_other_id(this->peer_cfg);
+ this->other_id = this->other_id->clone(this->other_id);
}
}
/**
+ * Implementation of ike_sa_t.send_keepalive
+ */
+static void send_keepalive(private_ike_sa_t *this)
+{
+ send_keepalive_job_t *job;
+ time_t last_out, now, diff;
+
+ if (!(this->conditions & COND_NAT_HERE))
+ { /* disable keep alives if we are not NATed anymore */
+ return;
+ }
+
+ last_out = get_use_time(this, FALSE);
+ now = time(NULL);
+
+ diff = now - last_out;
+
+ if (diff >= KEEPALIVE_INTERVAL)
+ {
+ packet_t *packet;
+ chunk_t data;
+
+ packet = packet_create();
+ packet->set_source(packet, this->my_host->clone(this->my_host));
+ packet->set_destination(packet, this->other_host->clone(this->other_host));
+ data.ptr = malloc(1);
+ data.ptr[0] = 0xFF;
+ data.len = 1;
+ packet->set_data(packet, data);
+ DBG1(DBG_IKE, "sending keep alive");
+ charon->sender->send(charon->sender, packet);
+ diff = 0;
+ }
+ job = send_keepalive_job_create(this->ike_sa_id);
+ charon->scheduler->schedule_job(charon->scheduler, (job_t*)job,
+ (KEEPALIVE_INTERVAL - diff) * 1000);
+}
+
+/**
* Implementation of ike_sa_t.get_ike_cfg
*/
static ike_cfg_t *get_ike_cfg(private_ike_sa_t *this)
@@ -398,6 +445,80 @@ static void set_ike_cfg(private_ike_sa_t *this, ike_cfg_t *ike_cfg)
ike_cfg->get_ref(ike_cfg);
this->ike_cfg = ike_cfg;
}
+/**
+ * Implementation of ike_sa_t.enable_extension.
+ */
+static void enable_extension(private_ike_sa_t *this, ike_extension_t extension)
+{
+ this->extensions |= extension;
+}
+
+/**
+ * Implementation of ike_sa_t.has_extension.
+ */
+static bool supports_extension(private_ike_sa_t *this, ike_extension_t extension)
+{
+ return (this->extensions & extension) != FALSE;
+}
+
+/**
+ * Implementation of ike_sa_t.has_condition.
+ */
+static bool has_condition(private_ike_sa_t *this, ike_condition_t condition)
+{
+ return (this->conditions & condition) != FALSE;
+}
+
+/**
+ * Implementation of ike_sa_t.enable_condition.
+ */
+static void set_condition(private_ike_sa_t *this, ike_condition_t condition,
+ bool enable)
+{
+ if (has_condition(this, condition) != enable)
+ {
+ if (enable)
+ {
+ this->conditions |= condition;
+ switch (condition)
+ {
+ case COND_STALE:
+ DBG1(DBG_IKE, "no route to %H, setting IKE_SA to stale",
+ this->other_host);
+ break;
+ case COND_NAT_HERE:
+ DBG1(DBG_IKE, "local host is behind NAT, sending keep alives");
+ this->conditions |= COND_NAT_ANY;
+ send_keepalive(this);
+ break;
+ case COND_NAT_THERE:
+ DBG1(DBG_IKE, "remote host is behind NAT");
+ this->conditions |= COND_NAT_ANY;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ this->conditions &= ~condition;
+ switch (condition)
+ {
+ case COND_STALE:
+ DBG1(DBG_IKE, "new route to %H found", this->other_host);
+ break;
+ case COND_NAT_HERE:
+ case COND_NAT_THERE:
+ set_condition(this, COND_NAT_ANY,
+ has_condition(this, COND_NAT_HERE) ||
+ has_condition(this, COND_NAT_THERE));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
/**
* Implementation of ike_sa_t.send_dpd
@@ -442,46 +563,12 @@ static status_t send_dpd(private_ike_sa_t *this)
}
/* recheck in "interval" seconds */
job = send_dpd_job_create(this->ike_sa_id);
- charon->event_queue->add_relative(charon->event_queue, (job_t*)job,
- (delay - diff) * 1000);
+ charon->scheduler->schedule_job(charon->scheduler, (job_t*)job,
+ (delay - diff) * 1000);
return SUCCESS;
}
/**
- * Implementation of ike_sa_t.send_keepalive
- */
-static void send_keepalive(private_ike_sa_t *this)
-{
- send_keepalive_job_t *job;
- time_t last_out, now, diff;
-
- last_out = get_use_time(this, FALSE);
- now = time(NULL);
-
- diff = now - last_out;
-
- if (diff >= KEEPALIVE_INTERVAL)
- {
- packet_t *packet;
- chunk_t data;
-
- packet = packet_create();
- packet->set_source(packet, this->my_host->clone(this->my_host));
- packet->set_destination(packet, this->other_host->clone(this->other_host));
- data.ptr = malloc(1);
- data.ptr[0] = 0xFF;
- data.len = 1;
- packet->set_data(packet, data);
- charon->sender->send(charon->sender, packet);
- DBG1(DBG_IKE, "sending keep alive");
- diff = 0;
- }
- job = send_keepalive_job_create(this->ike_sa_id);
- charon->event_queue->add_relative(charon->event_queue, (job_t*)job,
- (KEEPALIVE_INTERVAL - diff) * 1000);
-}
-
-/**
* Implementation of ike_sa_t.get_state.
*/
static ike_sa_state_t get_state(private_ike_sa_t *this)
@@ -524,16 +611,16 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state)
{
this->time.rekey = now + soft;
job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, reauth);
- charon->event_queue->add_relative(charon->event_queue, job,
- soft * 1000);
+ charon->scheduler->schedule_job(charon->scheduler, job,
+ soft * 1000);
}
if (hard)
{
this->time.delete = now + hard;
job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
- charon->event_queue->add_relative(charon->event_queue, job,
- hard * 1000);
+ charon->scheduler->schedule_job(charon->scheduler, job,
+ hard * 1000);
}
}
break;
@@ -542,8 +629,8 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state)
{
/* delete may fail if a packet gets lost, so set a timeout */
job_t *job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
- charon->event_queue->add_relative(charon->event_queue, job,
- HALF_OPEN_IKE_SA_TIMEOUT);
+ charon->scheduler->schedule_job(charon->scheduler, job,
+ HALF_OPEN_IKE_SA_TIMEOUT);
break;
}
default:
@@ -570,67 +657,151 @@ static void reset(private_ike_sa_t *this)
}
/**
+ * Implementation of ike_sa_t.set_virtual_ip
+ */
+static void set_virtual_ip(private_ike_sa_t *this, bool local, host_t *ip)
+{
+ if (local)
+ {
+ DBG1(DBG_IKE, "installing new virtual IP %H", ip);
+ if (this->my_virtual_ip)
+ {
+ DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip);
+ charon->kernel_interface->del_ip(charon->kernel_interface,
+ this->my_virtual_ip);
+ this->my_virtual_ip->destroy(this->my_virtual_ip);
+ }
+ if (charon->kernel_interface->add_ip(charon->kernel_interface, ip,
+ this->my_host) == SUCCESS)
+ {
+ this->my_virtual_ip = ip->clone(ip);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "installing virtual IP %H failed", ip);
+ this->my_virtual_ip = NULL;
+ }
+ }
+ else
+ {
+ DESTROY_IF(this->other_virtual_ip);
+ this->other_virtual_ip = ip->clone(ip);
+ }
+}
+
+/**
+ * Implementation of ike_sa_t.get_virtual_ip
+ */
+static host_t* get_virtual_ip(private_ike_sa_t *this, bool local)
+{
+ if (local)
+ {
+ return this->my_virtual_ip;
+ }
+ else
+ {
+ return this->other_virtual_ip;
+ }
+}
+
+/**
+ * Implementation of ike_sa_t.add_additional_address.
+ */
+static void add_additional_address(private_ike_sa_t *this, host_t *host)
+{
+ this->additional_addresses->insert_last(this->additional_addresses, host);
+}
+
+/**
+ * Implementation of ike_sa_t.create_additional_address_iterator.
+ */
+static iterator_t* create_additional_address_iterator(private_ike_sa_t *this)
+{
+ return this->additional_addresses->create_iterator(
+ this->additional_addresses, TRUE);
+}
+
+/**
+ * Implementation of ike_sa_t.set_pending_updates.
+ */
+static void set_pending_updates(private_ike_sa_t *this, u_int32_t updates)
+{
+ this->pending_updates = updates;
+}
+
+/**
+ * Implementation of ike_sa_t.get_pending_updates.
+ */
+static u_int32_t get_pending_updates(private_ike_sa_t *this)
+{
+ return this->pending_updates;
+}
+
+/**
* Update hosts, as addresses may change (NAT)
*/
static void update_hosts(private_ike_sa_t *this, host_t *me, host_t *other)
{
- iterator_t *iterator = NULL;
- child_sa_t *child_sa = NULL;
- host_diff_t my_diff, other_diff;
+ bool update = FALSE;
- if (this->my_host->is_anyaddr(this->my_host) ||
- this->other_host->is_anyaddr(this->other_host))
- {
- /* on first received message */
- this->my_host->destroy(this->my_host);
- this->my_host = me->clone(me);
- this->other_host->destroy(this->other_host);
- this->other_host = other->clone(other);
+ if (supports_extension(this, EXT_MOBIKE))
+ { /* if peer speaks mobike, address updates are explicit only */
return;
}
- my_diff = me->get_differences(me, this->my_host);
- other_diff = other->get_differences(other, this->other_host);
-
- if (!my_diff && !other_diff)
+ if (me == NULL)
{
- return;
+ me = this->my_host;
}
-
- if (my_diff)
+ if (other == NULL)
{
- this->my_host->destroy(this->my_host);
- this->my_host = me->clone(me);
+ other = this->other_host;
}
- if (!this->nat_here)
+ /* apply hosts on first received message */
+ if (this->my_host->is_anyaddr(this->my_host) ||
+ this->other_host->is_anyaddr(this->other_host))
{
- /* update without restrictions if we are not NATted */
- if (other_diff)
- {
- this->other_host->destroy(this->other_host);
- this->other_host = other->clone(other);
- }
+ set_my_host(this, me->clone(me));
+ set_other_host(this, other->clone(other));
+ update = TRUE;
}
else
{
- /* if we are natted, only port may change */
- if (other_diff & HOST_DIFF_ADDR)
+ /* update our address in any case */
+ if (!me->equals(me, this->my_host))
{
- return;
+ set_my_host(this, me->clone(me));
+ update = TRUE;
}
- else if (other_diff & HOST_DIFF_PORT)
+
+ if (!other->equals(other, this->other_host))
{
- this->other_host->set_port(this->other_host, other->get_port(other));
+ /* update others adress if we are NOT NATed,
+ * and allow port changes if we are NATed */
+ if (!has_condition(this, COND_NAT_HERE) ||
+ other->ip_equals(other, this->other_host))
+ {
+ set_other_host(this, other->clone(other));
+ update = TRUE;
+ }
}
}
- iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
- while (iterator->iterate(iterator, (void**)&child_sa))
+
+ /* update all associated CHILD_SAs, if required */
+ if (update)
{
- child_sa->update_hosts(child_sa, this->my_host, this->other_host,
- my_diff, other_diff);
+ iterator_t *iterator;
+ child_sa_t *child_sa;
+
+ iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ child_sa->update_hosts(child_sa, this->my_host, this->other_host,
+ has_condition(this, COND_NAT_ANY));
+ }
+ iterator->destroy(iterator);
}
- iterator->destroy(iterator);
}
/**
@@ -761,12 +932,12 @@ static status_t process_message(private_ike_sa_t *this, message_t *message)
}
/* add a timeout if peer does not establish it completely */
job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, FALSE);
- charon->event_queue->add_relative(charon->event_queue, job,
- HALF_OPEN_IKE_SA_TIMEOUT);
+ charon->scheduler->schedule_job(charon->scheduler, job,
+ HALF_OPEN_IKE_SA_TIMEOUT);
}
/* check if message is trustworthy, and update host information */
- if (this->state == IKE_CREATED ||
+ if (this->state == IKE_CREATED || this->state == IKE_CONNECTING ||
message->get_exchange_type(message) != IKE_SA_INIT)
{
update_hosts(this, me, other);
@@ -788,6 +959,7 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg)
if (this->other_host->is_anyaddr(this->other_host))
{
+ child_cfg->destroy(child_cfg);
SIG(IKE_UP_START, "initiating IKE_SA");
SIG(IKE_UP_FAILED, "unable to initiate to %%any");
return DESTROY_ME;
@@ -803,6 +975,8 @@ static status_t initiate(private_ike_sa_t *this, child_cfg_t *child_cfg)
this->task_manager->queue_task(this->task_manager, task);
task = (task_t*)ike_config_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, task);
+ task = (task_t*)ike_mobike_create(&this->public, TRUE);
+ this->task_manager->queue_task(this->task_manager, task);
}
task = (task_t*)child_create_create(&this->public, child_cfg);
@@ -863,6 +1037,8 @@ static status_t acquire(private_ike_sa_t *this, u_int32_t reqid)
this->task_manager->queue_task(this->task_manager, task);
task = (task_t*)ike_config_create(&this->public, TRUE);
this->task_manager->queue_task(this->task_manager, task);
+ task = (task_t*)ike_mobike_create(&this->public, TRUE);
+ this->task_manager->queue_task(this->task_manager, task);
}
child_cfg = child_sa->get_config(child_sa);
@@ -881,6 +1057,7 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg)
child_sa_t *child_sa;
iterator_t *iterator;
linked_list_t *my_ts, *other_ts;
+ host_t *me, *other;
status_t status;
SIG(CHILD_ROUTE_START, "routing CHILD_SA");
@@ -916,11 +1093,19 @@ static status_t route(private_ike_sa_t *this, child_cfg_t *child_cfg)
/* install kernel policies */
child_sa = child_sa_create(this->my_host, this->other_host, this->my_id,
this->other_id, child_cfg, FALSE, 0);
+ me = this->my_host;
+ if (this->my_virtual_ip)
+ {
+ me = this->my_virtual_ip;
+ }
+ other = this->other_host;
+ if (this->other_virtual_ip)
+ {
+ other = this->other_virtual_ip;
+ }
- my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL,
- this->my_host);
- other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL,
- this->other_host);
+ my_ts = child_cfg->get_traffic_selectors(child_cfg, TRUE, NULL, me);
+ other_ts = child_cfg->get_traffic_selectors(child_cfg, FALSE, NULL, other);
status = child_sa->add_policies(child_sa, my_ts, other_ts,
child_cfg->get_mode(child_cfg));
my_ts->destroy_offset(my_ts, offsetof(traffic_selector_t, destroy));
@@ -1063,6 +1248,16 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
/* use actual used host, not the wildcarded one in config */
new->other_host->destroy(new->other_host);
new->other_host = this->other_host->clone(this->other_host);
+ /* reset port to 500, but only if peer is not NATed */
+ if (!has_condition(this, COND_NAT_THERE))
+ {
+ new->other_host->set_port(new->other_host, IKEV2_UDP_PORT);
+ }
+ /* take over virtual ip, as we need it for a proper route */
+ if (this->my_virtual_ip)
+ {
+ set_virtual_ip(new, TRUE, this->my_virtual_ip);
+ }
/* install routes */
while (to_route->remove_last(to_route, (void**)&child_cfg) == SUCCESS)
@@ -1089,6 +1284,8 @@ static status_t retransmit(private_ike_sa_t *this, u_int32_t message_id)
task = (task_t*)child_create_create(&new->public, child_cfg);
new->task_manager->queue_task(new->task_manager, task);
}
+ task = (task_t*)ike_mobike_create(&new->public, TRUE);
+ 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);
@@ -1191,55 +1388,6 @@ static void set_other_ca(private_ike_sa_t *this, ca_info_t *other_ca)
}
/**
- * Implementation of ike_sa_t.set_virtual_ip
- */
-static void set_virtual_ip(private_ike_sa_t *this, bool local, host_t *ip)
-{
- if (local)
- {
- DBG1(DBG_IKE, "installing new virtual IP %H", ip);
- if (this->my_virtual_ip)
- {
- DBG1(DBG_IKE, "removing old virtual IP %H", this->my_virtual_ip);
- charon->kernel_interface->del_ip(charon->kernel_interface,
- this->my_virtual_ip,
- this->my_host);
- this->my_virtual_ip->destroy(this->my_virtual_ip);
- }
- if (charon->kernel_interface->add_ip(charon->kernel_interface, ip,
- this->my_host) == SUCCESS)
- {
- this->my_virtual_ip = ip->clone(ip);
- }
- else
- {
- DBG1(DBG_IKE, "installing virtual IP %H failed", ip);
- this->my_virtual_ip = NULL;
- }
- }
- else
- {
- DESTROY_IF(this->other_virtual_ip);
- this->other_virtual_ip = ip->clone(ip);
- }
-}
-
-/**
- * Implementation of ike_sa_t.get_virtual_ip
- */
-static host_t* get_virtual_ip(private_ike_sa_t *this, bool local)
-{
- if (local)
- {
- return this->my_virtual_ip;
- }
- else
- {
- return this->other_virtual_ip;
- }
-}
-
-/**
* Implementation of ike_sa_t.derive_keys.
*/
static status_t derive_keys(private_ike_sa_t *this,
@@ -1560,72 +1708,78 @@ static status_t rekey(private_ike_sa_t *this)
/**
* Implementation of ike_sa_t.reestablish
*/
-static void reestablish(private_ike_sa_t *this)
+static status_t reestablish(private_ike_sa_t *this)
{
- private_ike_sa_t *other;
- iterator_t *iterator;
- child_sa_t *child_sa;
- child_cfg_t *child_cfg;
task_t *task;
- job_t *job;
-
- other = (private_ike_sa_t*)charon->ike_sa_manager->checkout_new(
- charon->ike_sa_manager, TRUE);
- set_peer_cfg(other, this->peer_cfg);
- other->other_host->destroy(other->other_host);
- other->other_host = this->other_host->clone(this->other_host);
- if (this->my_virtual_ip)
- {
- /* if we already have a virtual IP, we reuse it */
- set_virtual_ip(other, TRUE, this->my_virtual_ip);
- }
-
- if (this->state == IKE_ESTABLISHED)
- {
- task = (task_t*)ike_init_create(&other->public, TRUE, NULL);
- other->task_manager->queue_task(other->task_manager, task);
- task = (task_t*)ike_natd_create(&other->public, TRUE);
- other->task_manager->queue_task(other->task_manager, task);
- task = (task_t*)ike_cert_create(&other->public, TRUE);
- other->task_manager->queue_task(other->task_manager, task);
- task = (task_t*)ike_config_create(&other->public, TRUE);
- other->task_manager->queue_task(other->task_manager, task);
- task = (task_t*)ike_auth_create(&other->public, TRUE);
- other->task_manager->queue_task(other->task_manager, task);
- }
+ task = (task_t*)ike_reauth_create(&this->public);
+ this->task_manager->queue_task(this->task_manager, task);
- other->task_manager->adopt_tasks(other->task_manager, this->task_manager);
+ return this->task_manager->initiate(this->task_manager);
+}
+
+/**
+ * Implementation of ike_sa_t.roam.
+ */
+static status_t roam(private_ike_sa_t *this, bool address)
+{
+ host_t *me, *other;
+ ike_mobike_t *mobike;
- /* Create task for established children, adopt routed children directly */
- iterator = this->child_sas->create_iterator(this->child_sas, TRUE);
- while(iterator->iterate(iterator, (void**)&child_sa))
+ /* responder just updates the peer about changed address config */
+ if (!this->ike_sa_id->is_initiator(this->ike_sa_id))
{
- switch (child_sa->get_state(child_sa))
+ if (supports_extension(this, EXT_MOBIKE) && address)
{
- case CHILD_ROUTED:
- {
- iterator->remove(iterator);
- other->child_sas->insert_first(other->child_sas, child_sa);
- break;
- }
- default:
- {
- child_cfg = child_sa->get_config(child_sa);
- task = (task_t*)child_create_create(&other->public, child_cfg);
- other->task_manager->queue_task(other->task_manager, task);
- break;
- }
+ DBG1(DBG_IKE, "sending address list update using MOBIKE");
+ mobike = ike_mobike_create(&this->public, TRUE);
+ this->task_manager->queue_task(this->task_manager, (task_t*)mobike);
+ return this->task_manager->initiate(this->task_manager);
}
+ return SUCCESS;
}
- iterator->destroy(iterator);
- other->task_manager->initiate(other->task_manager);
+ /* get best address pair to use */
+ other = this->other_host;
+ me = charon->kernel_interface->get_source_addr(charon->kernel_interface,
+ other);
+
+ /* TODO: find a better path using additional addresses of peer */
- charon->ike_sa_manager->checkin(charon->ike_sa_manager, &other->public);
+ if (!me)
+ {
+ /* no route found to host, set to stale, wait for a new route */
+ set_condition(this, COND_STALE, TRUE);
+ return FAILED;
+ }
+
+ set_condition(this, COND_STALE, FALSE);
+ if (me->ip_equals(me, this->my_host) &&
+ other->ip_equals(other, this->other_host))
+ {
+ DBG2(DBG_IKE, "%H still reached through %H, no update needed",
+ this->other_host, me);
+ me->destroy(me);
+ return SUCCESS;
+ }
+ me->set_port(me, this->my_host->get_port(this->my_host));
+ other = other->clone(other);
+ other->set_port(other, this->other_host->get_port(this->other_host));
+ set_my_host(this, me);
+ set_other_host(this, other);
- job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE);
- charon->job_queue->add(charon->job_queue, job);
+ /* update addresses with mobike, if supported ... */
+ if (supports_extension(this, EXT_MOBIKE))
+ {
+ DBG1(DBG_IKE, "requesting address change using MOBIKE");
+ mobike = ike_mobike_create(&this->public, TRUE);
+ mobike->roam(mobike, address);
+ this->task_manager->queue_task(this->task_manager, (task_t*)mobike);
+ return this->task_manager->initiate(this->task_manager);
+ }
+ DBG1(DBG_IKE, "reestablishing IKE_SA due address change");
+ /* ... reestablish if not */
+ return reestablish(this);
}
/**
@@ -1680,32 +1834,6 @@ static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other)
}
/**
- * Implementation of ike_sa_t.is_natt_enabled.
- */
-static bool is_natt_enabled(private_ike_sa_t *this)
-{
- return this->nat_here || this->nat_there;
-}
-
-/**
- * Implementation of ike_sa_t.enable_natt.
- */
-static void enable_natt(private_ike_sa_t *this, bool local)
-{
- if (local)
- {
- DBG1(DBG_IKE, "local host is behind NAT, scheduling keep alives");
- this->nat_here = TRUE;
- send_keepalive(this);
- }
- else
- {
- DBG1(DBG_IKE, "remote host is behind NAT");
- this->nat_there = TRUE;
- }
-}
-
-/**
* Implementation of ike_sa_t.remove_dns_server
*/
static void remove_dns_servers(private_ike_sa_t *this)
@@ -1857,13 +1985,16 @@ static void destroy(private_ike_sa_t *this)
if (this->my_virtual_ip)
{
charon->kernel_interface->del_ip(charon->kernel_interface,
- this->my_virtual_ip, this->my_host);
+ this->my_virtual_ip);
this->my_virtual_ip->destroy(this->my_virtual_ip);
}
DESTROY_IF(this->other_virtual_ip);
remove_dns_servers(this);
- this->dns_servers->destroy_offset(this->dns_servers, offsetof(host_t, destroy));
+ this->dns_servers->destroy_offset(this->dns_servers,
+ offsetof(host_t, destroy));
+ this->additional_addresses->destroy_offset(this->additional_addresses,
+ offsetof(host_t, destroy));
DESTROY_IF(this->my_host);
DESTROY_IF(this->other_host);
@@ -1905,12 +2036,21 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->public.set_my_host = (void (*)(ike_sa_t*,host_t*)) set_my_host;
this->public.get_other_host = (host_t* (*)(ike_sa_t*)) get_other_host;
this->public.set_other_host = (void (*)(ike_sa_t*,host_t*)) set_other_host;
+ this->public.update_hosts = (void(*)(ike_sa_t*, host_t *me, host_t *other))update_hosts;
this->public.get_my_id = (identification_t* (*)(ike_sa_t*)) get_my_id;
this->public.set_my_id = (void (*)(ike_sa_t*,identification_t*)) set_my_id;
this->public.get_other_id = (identification_t* (*)(ike_sa_t*)) get_other_id;
this->public.set_other_id = (void (*)(ike_sa_t*,identification_t*)) set_other_id;
this->public.get_other_ca = (ca_info_t* (*)(ike_sa_t*)) get_other_ca;
this->public.set_other_ca = (void (*)(ike_sa_t*,ca_info_t*)) set_other_ca;
+ this->public.enable_extension = (void(*)(ike_sa_t*, ike_extension_t extension))enable_extension;
+ this->public.supports_extension = (bool(*)(ike_sa_t*, ike_extension_t extension))supports_extension;
+ this->public.set_condition = (void (*)(ike_sa_t*, ike_condition_t,bool)) set_condition;
+ this->public.has_condition = (bool (*)(ike_sa_t*,ike_condition_t)) has_condition;
+ this->public.set_pending_updates = (void(*)(ike_sa_t*, u_int32_t updates))set_pending_updates;
+ this->public.get_pending_updates = (u_int32_t(*)(ike_sa_t*))get_pending_updates;
+ this->public.create_additional_address_iterator = (iterator_t*(*)(ike_sa_t*))create_additional_address_iterator;
+ this->public.add_additional_address = (void(*)(ike_sa_t*, host_t *host))add_additional_address;
this->public.retransmit = (status_t (*)(ike_sa_t *, u_int32_t)) retransmit;
this->public.delete = (status_t (*)(ike_sa_t*))delete_;
this->public.destroy = (void (*)(ike_sa_t*))destroy;
@@ -1927,10 +2067,9 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->public.rekey_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t)) rekey_child_sa;
this->public.delete_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t)) delete_child_sa;
this->public.destroy_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t))destroy_child_sa;
- this->public.enable_natt = (void (*)(ike_sa_t*, bool)) enable_natt;
- this->public.is_natt_enabled = (bool (*)(ike_sa_t*)) is_natt_enabled;
this->public.rekey = (status_t (*)(ike_sa_t*))rekey;
- this->public.reestablish = (void (*)(ike_sa_t*))reestablish;
+ this->public.reestablish = (status_t (*)(ike_sa_t*))reestablish;
+ this->public.roam = (status_t(*)(ike_sa_t*,bool))roam;
this->public.inherit = (status_t (*)(ike_sa_t*,ike_sa_t*))inherit;
this->public.generate_message = (status_t (*)(ike_sa_t*,message_t*,packet_t**))generate_message;
this->public.reset = (void (*)(ike_sa_t*))reset;
@@ -1947,6 +2086,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->my_id = identification_create_from_encoding(ID_ANY, chunk_empty);
this->other_id = identification_create_from_encoding(ID_ANY, chunk_empty);
this->other_ca = NULL;
+ this->extensions = 0;
+ this->conditions = 0;
this->crypter_in = NULL;
this->crypter_out = NULL;
this->signer_in = NULL;
@@ -1955,8 +2096,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->skp_verify = chunk_empty;
this->skp_build = chunk_empty;
this->child_prf = NULL;
- this->nat_here = FALSE;
- this->nat_there = FALSE;
this->state = IKE_CREATED;
this->time.inbound = this->time.outbound = time(NULL);
this->time.established = 0;
@@ -1969,6 +2108,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id)
this->my_virtual_ip = NULL;
this->other_virtual_ip = NULL;
this->dns_servers = linked_list_create();
+ this->additional_addresses = linked_list_create();
+ this->pending_updates = 0;
this->keyingtry = 0;
return &this->public;
diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h
index 76942b208..ba189577c 100644
--- a/src/charon/sa/ike_sa.h
+++ b/src/charon/sa/ike_sa.h
@@ -25,6 +25,8 @@
#ifndef IKE_SA_H_
#define IKE_SA_H_
+typedef enum ike_extension_t ike_extension_t;
+typedef enum ike_condition_t ike_condition_t;
typedef enum ike_sa_state_t ike_sa_state_t;
typedef struct ike_sa_t ike_sa_t;
@@ -70,6 +72,47 @@ typedef struct ike_sa_t ike_sa_t;
*/
#define RETRY_JITTER 20
+/**
+ * @brief Extensions (or optional features) the peer supports
+ */
+enum ike_extension_t {
+
+ /**
+ * peer supports NAT traversal as specified in RFC4306
+ */
+ EXT_NATT = (1<<0),
+
+ /**
+ * peer supports MOBIKE (RFC4555)
+ */
+ EXT_MOBIKE = (1<<1),
+};
+
+/**
+ * @brief Conditions of an IKE_SA, change during its lifetime
+ */
+enum ike_condition_t {
+
+ /**
+ * Connection is natted somewhere
+ */
+ COND_NAT_ANY = (1<<0),
+
+ /**
+ * we are behind NAT
+ */
+ COND_NAT_HERE = (1<<1),
+
+ /**
+ * other is behind NAT
+ */
+ COND_NAT_THERE = (1<<2),
+
+ /**
+ * peer is currently not reachable (due missing route, ...)
+ */
+ COND_STALE = (1<<3),
+};
/**
* @brief State of an IKE_SA.
@@ -240,6 +283,17 @@ struct ike_sa_t {
void (*set_other_host) (ike_sa_t *this, host_t *other);
/**
+ * @brief Update the IKE_SAs host.
+ *
+ * Hosts may be NULL to use current host.
+ *
+ * @param this calling object
+ * @param me new local host address, or NULL
+ * @param other new remote host address, or NULL
+ */
+ void (*update_hosts)(ike_sa_t *this, host_t *me, host_t *other);
+
+ /**
* @brief Get the own identification.
*
* @param this calling object
@@ -318,8 +372,83 @@ struct ike_sa_t {
* @param config peer_config to use
*/
void (*set_peer_cfg) (ike_sa_t *this, peer_cfg_t *config);
+
+ /**
+ * @brief Add an additional address for the peer.
+ *
+ * In MOBIKE, a peer may transmit additional addresses where it is
+ * reachable. These are stored in the IKE_SA.
+ * The own list of addresses is not stored, they are queried from
+ * the kernel when required.
+ *
+ * @param this calling object
+ * @param host host to add to list
+ */
+ void (*add_additional_address)(ike_sa_t *this, host_t *host);
+
+ /**
+ * @brief Create an iterator over all additional addresses of the peer.
+ *
+ * @param this calling object
+ * @return iterator over addresses
+ */
+ iterator_t* (*create_additional_address_iterator)(ike_sa_t *this);
+
+ /**
+ * @brief Enable an extension the peer supports.
+ *
+ * If support for an IKE extension is detected, this method is called
+ * to enable that extension and behave accordingly.
+ *
+ * @param this calling object
+ * @param extension extension to enable
+ */
+ void (*enable_extension)(ike_sa_t *this, ike_extension_t extension);
+
+ /**
+ * @brief Check if the peer supports an extension.
+ *
+ * @param this calling object
+ * @param extension extension to check for support
+ * @return TRUE if peer supports it, FALSE otherwise
+ */
+ bool (*supports_extension)(ike_sa_t *this, ike_extension_t extension);
+
+ /**
+ * @brief Enable/disable a condition flag for this IKE_SA.
+ *
+ * @param this calling object
+ * @param condition condition to enable/disable
+ * @param enable TRUE to enable condition, FALSE to disable
+ */
+ void (*set_condition) (ike_sa_t *this, ike_condition_t condition, bool enable);
/**
+ * @brief Check if a condition flag is set.
+ *
+ * @param this calling object
+ * @param condition condition to check
+ * @return TRUE if condition flag set, FALSE otherwise
+ */
+ bool (*has_condition) (ike_sa_t *this, ike_condition_t condition);
+
+ /**
+ * @brief Get the number of queued MOBIKE address updates.
+ *
+ * @param this calling object
+ * @return number of pending updates
+ */
+ u_int32_t (*get_pending_updates)(ike_sa_t *this);
+
+ /**
+ * @brief Set the number of queued MOBIKE address updates.
+ *
+ * @param this calling object
+ * @param updates number of pending updates
+ */
+ void (*set_pending_updates)(ike_sa_t *this, u_int32_t updates);
+
+ /**
* @brief Initiate a new connection.
*
* The configs are owned by the IKE_SA after the call.
@@ -389,6 +518,21 @@ struct ike_sa_t {
status_t (*delete) (ike_sa_t *this);
/**
+ * @brief Update IKE_SAs after network interfaces have changed.
+ *
+ * Whenever the network interface configuration changes, the kernel
+ * interface calls roam() on each IKE_SA. The IKE_SA then checks if
+ * the new network config requires changes, and handles appropriate.
+ * If MOBIKE is supported, addresses are updated; If not, the tunnel is
+ * restarted.
+ *
+ * @param this calling object
+ * @param address TRUE if address list changed, FALSE otherwise
+ * @return SUCCESS, FAILED, DESTROY_ME
+ */
+ status_t (*roam)(ike_sa_t *this, bool address);
+
+ /**
* @brief Processes a incoming IKEv2-Message.
*
* Message processing may fail. If a critical failure occurs,
@@ -457,29 +601,6 @@ struct ike_sa_t {
* @param this calling object
*/
void (*send_keepalive) (ike_sa_t *this);
-
- /**
- * @brief Check if NAT traversal is enabled for this IKE_SA.
- *
- * @param this calling object
- * @return TRUE if NAT traversal enabled
- */
- bool (*is_natt_enabled) (ike_sa_t *this);
-
- /**
- * @brief Enable NAT detection for this IKE_SA.
- *
- * If a Network address translation is detected with
- * NAT_DETECTION notifys, a SA must switch to ports
- * 4500. To enable this behavior, call enable_natt().
- * It is relevant which peer is NATted, this is specified
- * with the "local" parameter. Call it twice when both
- * are NATted.
- *
- * @param this calling object
- * @param local TRUE, if we are NATted, FALSE if other
- */
- void (*enable_natt) (ike_sa_t *this, bool local);
/**
* @brief Derive all keys and create the transforms for IKE communication.
@@ -621,11 +742,12 @@ struct ike_sa_t {
* @brief Restablish the IKE_SA.
*
* Create a completely new IKE_SA with authentication, recreates all children
- * within the IKE_SA, but lets the old IKE_SA untouched.
+ * within the IKE_SA, closes this IKE_SA.
*
* @param this calling object
+ * @return DESTROY_ME to destroy the IKE_SA
*/
- void (*reestablish) (ike_sa_t *this);
+ status_t (*reestablish) (ike_sa_t *this);
/**
* @brief Set the virtual IP to use for this IKE_SA and its children.
diff --git a/src/charon/sa/ike_sa_manager.c b/src/charon/sa/ike_sa_manager.c
index a62ec5e3c..56b865891 100644
--- a/src/charon/sa/ike_sa_manager.c
+++ b/src/charon/sa/ike_sa_manager.c
@@ -525,19 +525,21 @@ static ike_sa_t* checkout_by_peer(private_ike_sa_manager_t *this,
/* IKE_SA has no IDs yet, so we can't use it */
continue;
}
-
+ DBG2(DBG_MGR, "candidate IKE_SA for \n\t%H[%D]...%H[%D]\n\t%H[%D]...%H[%D]",
+ my_host, my_id, other_host, other_id,
+ found_my_host, found_my_id, found_other_host, found_other_id);
/* compare ID and hosts. Supplied ID may contain wildcards, and IP
* may be %any. */
- if ((found_my_host->is_anyaddr(found_my_host) ||
+ if ((my_host->is_anyaddr(my_host) ||
my_host->ip_equals(my_host, found_my_host)) &&
- (found_other_host->is_anyaddr(found_other_host) ||
+ (other_host->is_anyaddr(other_host) ||
other_host->ip_equals(other_host, found_other_host)) &&
found_my_id->matches(found_my_id, my_id, &wc) &&
found_other_id->matches(found_other_id, other_id, &wc))
{
/* looks good, we take this one */
DBG2(DBG_MGR, "found an existing IKE_SA for %H[%D]...%H[%D]",
- my_host, other_host, my_id, other_id);
+ my_host, my_id, other_host, other_id);
entry->checked_out = TRUE;
ike_sa = entry->ike_sa;
}
@@ -682,16 +684,16 @@ static ike_sa_t* checkout_by_name(private_ike_sa_manager_t *this, char *name,
/**
* Iterator hook for iterate, gets ike_sas instead of entries
*/
-static bool iterator_hook(private_ike_sa_manager_t* this, entry_t *in,
- ike_sa_t **out)
+static hook_result_t iterator_hook(private_ike_sa_manager_t* this, entry_t *in,
+ ike_sa_t **out)
{
/* check out entry */
if (wait_for_entry(this, in))
{
*out = in->ike_sa;
- return TRUE;
+ return HOOK_NEXT;
}
- return FALSE;
+ return HOOK_SKIP;
}
/**
@@ -701,6 +703,7 @@ static iterator_t *create_iterator(private_ike_sa_manager_t* this)
{
iterator_t *iterator = this->ike_sa_list->create_iterator_locked(
this->ike_sa_list, &this->mutex);
+
/* register hook to iterator over ike_sas, not entries */
iterator->set_iterator_hook(iterator, (iterator_hook_t*)iterator_hook, this);
return iterator;
diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c
index e67508ed1..55592f437 100644
--- a/src/charon/sa/task_manager.c
+++ b/src/charon/sa/task_manager.c
@@ -27,6 +27,7 @@
#include <daemon.h>
#include <sa/tasks/ike_init.h>
#include <sa/tasks/ike_natd.h>
+#include <sa/tasks/ike_mobike.h>
#include <sa/tasks/ike_auth.h>
#include <sa/tasks/ike_cert.h>
#include <sa/tasks/ike_rekey.h>
@@ -130,6 +131,11 @@ struct private_task_manager_t {
* List of tasks initiated by peer
*/
linked_list_t *passive_tasks;
+
+ /**
+ * the task manager has been reset
+ */
+ bool reset;
};
/**
@@ -140,7 +146,7 @@ static void flush(private_task_manager_t *this)
task_t *task;
this->queued_tasks->destroy_offset(this->queued_tasks,
- offsetof(task_t, destroy));
+ offsetof(task_t, destroy));
this->passive_tasks->destroy_offset(this->passive_tasks,
offsetof(task_t, destroy));
@@ -235,7 +241,7 @@ static status_t retransmit(private_task_manager_t *this, u_int32_t message_id)
this->initiating.packet->clone(this->initiating.packet));
job = (job_t*)retransmit_job_create(this->initiating.mid,
this->ike_sa->get_id(this->ike_sa));
- charon->event_queue->add_relative(charon->event_queue, job, timeout);
+ charon->scheduler->schedule_job(charon->scheduler, job, timeout);
}
return SUCCESS;
}
@@ -274,6 +280,7 @@ static status_t build_request(private_task_manager_t *this)
activate_task(this, IKE_AUTHENTICATE);
activate_task(this, IKE_CONFIG);
activate_task(this, CHILD_CREATE);
+ activate_task(this, IKE_MOBIKE);
}
break;
case IKE_ESTABLISHED:
@@ -302,7 +309,17 @@ static status_t build_request(private_task_manager_t *this)
exchange = CREATE_CHILD_SA;
break;
}
- if (activate_task(this, IKE_DEADPEER))
+ if (activate_task(this, IKE_REAUTH))
+ {
+ exchange = INFORMATIONAL;
+ break;
+ }
+ if (activate_task(this, IKE_MOBIKE))
+ {
+ exchange = INFORMATIONAL;
+ break;
+ }
+ if (activate_task(this, IKE_DPD))
{
exchange = INFORMATIONAL;
break;
@@ -338,6 +355,8 @@ static status_t build_request(private_task_manager_t *this)
case IKE_REKEY:
exchange = CREATE_CHILD_SA;
break;
+ case IKE_MOBIKE:
+ exchange = INFORMATIONAL;
default:
continue;
}
@@ -415,6 +434,8 @@ static status_t process_response(private_task_manager_t *this,
return DESTROY_ME;
}
+ /* catch if we get resetted while processing */
+ this->reset = FALSE;
iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
while (iterator->iterate(iterator, (void*)&task))
{
@@ -434,6 +455,12 @@ static status_t process_response(private_task_manager_t *this,
iterator->destroy(iterator);
return DESTROY_ME;
}
+ if (this->reset)
+ { /* start all over again if we were reset */
+ this->reset = FALSE;
+ iterator->destroy(iterator);
+ return build_request(this);
+ }
}
iterator->destroy(iterator);
@@ -456,7 +483,7 @@ static void handle_collisions(private_task_manager_t *this, task_t *task)
/* do we have to check */
if (type == IKE_REKEY || type == CHILD_REKEY ||
- type == CHILD_DELETE || type == IKE_DELETE)
+ type == CHILD_DELETE || type == IKE_DELETE || type == IKE_REAUTH)
{
/* find an exchange collision, and notify these tasks */
iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
@@ -465,7 +492,8 @@ static void handle_collisions(private_task_manager_t *this, task_t *task)
switch (active->get_type(active))
{
case IKE_REKEY:
- if (type == IKE_REKEY || type == IKE_DELETE)
+ if (type == IKE_REKEY || type == IKE_DELETE ||
+ type == IKE_REAUTH)
{
ike_rekey_t *rekey = (ike_rekey_t*)active;
rekey->collide(rekey, task);
@@ -571,6 +599,7 @@ static status_t process_request(private_task_manager_t *this,
exchange_type_t exchange;
payload_t *payload;
notify_payload_t *notify;
+ delete_payload_t *delete;
exchange = message->get_exchange_type(message);
@@ -591,6 +620,8 @@ static status_t process_request(private_task_manager_t *this,
this->passive_tasks->insert_last(this->passive_tasks, task);
task = (task_t*)child_create_create(this->ike_sa, NULL);
this->passive_tasks->insert_last(this->passive_tasks, task);
+ task = (task_t*)ike_mobike_create(this->ike_sa, FALSE);
+ this->passive_tasks->insert_last(this->passive_tasks, task);
break;
}
case CREATE_CHILD_SA:
@@ -646,27 +677,60 @@ static status_t process_request(private_task_manager_t *this,
}
case INFORMATIONAL:
{
- delete_payload_t *delete;
-
- delete = (delete_payload_t*)message->get_payload(message, DELETE);
- if (delete)
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
{
- if (delete->get_protocol_id(delete) == PROTO_IKE)
+ switch (payload->get_type(payload))
{
- task = (task_t*)ike_delete_create(this->ike_sa, FALSE);
- this->passive_tasks->insert_last(this->passive_tasks, task);
+ case NOTIFY:
+ {
+ notify = (notify_payload_t*)payload;
+ switch (notify->get_notify_type(notify))
+ {
+ case ADDITIONAL_IP4_ADDRESS:
+ case ADDITIONAL_IP6_ADDRESS:
+ case NO_ADDITIONAL_ADDRESSES:
+ case UPDATE_SA_ADDRESSES:
+ case NO_NATS_ALLOWED:
+ case UNACCEPTABLE_ADDRESSES:
+ case UNEXPECTED_NAT_DETECTED:
+ case COOKIE2:
+ task = (task_t*)ike_mobike_create(this->ike_sa,
+ FALSE);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case DELETE:
+ {
+ delete = (delete_payload_t*)payload;
+ if (delete->get_protocol_id(delete) == PROTO_IKE)
+ {
+ task = (task_t*)ike_delete_create(this->ike_sa, FALSE);
+ }
+ else
+ {
+ task = (task_t*)child_delete_create(this->ike_sa, NULL);
+ }
+ break;
+ }
+ default:
+ break;
}
- else
+ if (task)
{
- task = (task_t*)child_delete_create(this->ike_sa, NULL);
- this->passive_tasks->insert_last(this->passive_tasks, task);
+ break;
}
}
- else
+ iterator->destroy(iterator);
+
+ if (task == NULL)
{
task = (task_t*)ike_dpd_create(FALSE);
- this->passive_tasks->insert_last(this->passive_tasks, task);
}
+ this->passive_tasks->insert_last(this->passive_tasks, task);
break;
}
default:
@@ -806,7 +870,7 @@ static void reset(private_task_manager_t *this)
this->responding.packet = NULL;
this->initiating.packet = NULL;
this->responding.mid = 0;
- this->initiating.mid = -1;
+ this->initiating.mid = 0;
this->initiating.type = EXCHANGE_TYPE_UNDEFINED;
/* reset active tasks */
@@ -816,6 +880,8 @@ static void reset(private_task_manager_t *this)
task->migrate(task, this->ike_sa);
this->queued_tasks->insert_first(this->queued_tasks, task);
}
+
+ this->reset = TRUE;
}
/**
@@ -859,6 +925,7 @@ task_manager_t *task_manager_create(ike_sa_t *ike_sa)
this->queued_tasks = linked_list_create();
this->active_tasks = linked_list_create();
this->passive_tasks = linked_list_create();
+ this->reset = FALSE;
return &this->public;
}
diff --git a/src/charon/sa/tasks/child_create.c b/src/charon/sa/tasks/child_create.c
index f70730b05..42f34a94b 100644
--- a/src/charon/sa/tasks/child_create.c
+++ b/src/charon/sa/tasks/child_create.c
@@ -297,7 +297,7 @@ static status_t select_and_install(private_child_create_t *this, bool no_dh)
this->mode = MODE_TUNNEL;
DBG1(DBG_IKE, "not using tranport mode, not host-to-host");
}
- else if (this->ike_sa->is_natt_enabled(this->ike_sa))
+ else if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY))
{
this->mode = MODE_TUNNEL;
DBG1(DBG_IKE, "not using tranport mode, connection NATed");
@@ -493,6 +493,7 @@ static void process_payloads(private_child_create_t *this, message_t *message)
static status_t build_i(private_child_create_t *this, message_t *message)
{
host_t *me, *other, *vip;
+ bool propose_all = FALSE;
peer_cfg_t *peer_cfg;
switch (message->get_exchange_type(message))
@@ -523,33 +524,53 @@ static status_t build_i(private_child_create_t *this, message_t *message)
SIG(CHILD_UP_START, "establishing CHILD_SA");
- me = this->ike_sa->get_my_host(this->ike_sa);
- other = this->ike_sa->get_other_host(this->ike_sa);
- peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
- vip = peer_cfg->get_my_virtual_ip(peer_cfg);
+ /* reuse virtual IP if we already have one */
+ me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
+ if (me == NULL)
+ {
+ me = this->ike_sa->get_my_host(this->ike_sa);
+ }
+ other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
+ if (other == NULL)
+ {
+ other = this->ike_sa->get_other_host(this->ike_sa);
+ }
- if (vip)
+ /* check if we want a virtual IP, but don't have one */
+ if (!this->reqid)
+ {
+ peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
+ vip = peer_cfg->get_my_virtual_ip(peer_cfg);
+ if (vip)
+ {
+ propose_all = TRUE;
+ vip->destroy(vip);
+ }
+ }
+
+ if (propose_all)
{ /* propose a 0.0.0.0/0 subnet when we use virtual ip */
this->tsi = this->config->get_traffic_selectors(this->config, TRUE,
NULL, NULL);
- vip->destroy(vip);
}
else
- { /* but shorten a 0.0.0.0/0 subnet to the actual address if host2host */
+ { /* but shorten a 0.0.0.0/0 subnet for host2host/we already have a vip */
this->tsi = this->config->get_traffic_selectors(this->config, TRUE,
NULL, me);
}
this->tsr = this->config->get_traffic_selectors(this->config, FALSE,
NULL, other);
+
this->proposals = this->config->get_proposals(this->config,
this->dh_group == MODP_NONE);
this->mode = this->config->get_mode(this->config);
- this->child_sa = child_sa_create(me, other,
- this->ike_sa->get_my_id(this->ike_sa),
- this->ike_sa->get_other_id(this->ike_sa),
- this->config, this->reqid,
- this->ike_sa->is_natt_enabled(this->ike_sa));
+ this->child_sa = child_sa_create(
+ this->ike_sa->get_my_host(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa),
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa), this->config, this->reqid,
+ this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY));
if (this->child_sa->alloc(this->child_sa, this->proposals) != SUCCESS)
{
@@ -609,9 +630,21 @@ static status_t process_r(private_child_create_t *this, message_t *message)
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
if (peer_cfg)
{
- this->config = peer_cfg->select_child_cfg(peer_cfg, this->tsr, this->tsi,
- this->ike_sa->get_my_host(this->ike_sa),
- this->ike_sa->get_other_host(this->ike_sa));
+ host_t *me, *other;
+
+ me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
+ if (me == NULL)
+ {
+ me = this->ike_sa->get_my_host(this->ike_sa);
+ }
+ other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE);
+ if (other == NULL)
+ {
+ other = this->ike_sa->get_other_host(this->ike_sa);
+ }
+
+ this->config = peer_cfg->select_child_cfg(peer_cfg, this->tsr,
+ this->tsi, me, other);
}
return NEED_MORE;
}
@@ -660,12 +693,12 @@ static status_t build_r(private_child_create_t *this, message_t *message)
return SUCCESS;
}
- this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa),
- this->ike_sa->get_other_host(this->ike_sa),
- this->ike_sa->get_my_id(this->ike_sa),
- this->ike_sa->get_other_id(this->ike_sa),
- this->config, this->reqid,
- this->ike_sa->is_natt_enabled(this->ike_sa));
+ this->child_sa = child_sa_create(
+ this->ike_sa->get_my_host(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa),
+ this->ike_sa->get_my_id(this->ike_sa),
+ this->ike_sa->get_other_id(this->ike_sa), this->config, this->reqid,
+ this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY));
switch (select_and_install(this, no_dh))
{
diff --git a/src/charon/sa/tasks/child_rekey.c b/src/charon/sa/tasks/child_rekey.c
index 4f3c69034..3667d8fad 100644
--- a/src/charon/sa/tasks/child_rekey.c
+++ b/src/charon/sa/tasks/child_rekey.c
@@ -206,7 +206,7 @@ static status_t process_i(private_child_rekey_t *this, message_t *message)
DBG1(DBG_IKE, "CHILD_SA rekeying failed, "
"trying again in %d seconds", retry);
this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
- charon->event_queue->add_relative(charon->event_queue, job, retry * 1000);
+ charon->scheduler->schedule_job(charon->scheduler, job, retry * 1000);
}
return SUCCESS;
}
diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c
index d0dd49aee..c1c0cd5a2 100644
--- a/src/charon/sa/tasks/ike_auth.c
+++ b/src/charon/sa/tasks/ike_auth.c
@@ -636,7 +636,12 @@ static status_t process_i(private_ike_auth_t *this, message_t *message)
case INVALID_SELECTORS:
/* these are errors, but are not critical as only the
* CHILD_SA won't get build, but IKE_SA establishes anyway */
- break;
+ break;
+ case MOBIKE_SUPPORTED:
+ case ADDITIONAL_IP4_ADDRESS:
+ case ADDITIONAL_IP6_ADDRESS:
+ /* handled in ike_mobike task */
+ break;
default:
{
if (type < 16383)
diff --git a/src/charon/sa/tasks/ike_dpd.c b/src/charon/sa/tasks/ike_dpd.c
index 1cb05c45c..be751766e 100644
--- a/src/charon/sa/tasks/ike_dpd.c
+++ b/src/charon/sa/tasks/ike_dpd.c
@@ -61,7 +61,7 @@ static status_t return_success(private_ike_dpd_t *this, message_t *message)
*/
static task_type_t get_type(private_ike_dpd_t *this)
{
- return IKE_DEADPEER;
+ return IKE_DPD;
}
/**
diff --git a/src/charon/sa/tasks/ike_mobike.c b/src/charon/sa/tasks/ike_mobike.c
new file mode 100644
index 000000000..8d4dce36c
--- /dev/null
+++ b/src/charon/sa/tasks/ike_mobike.c
@@ -0,0 +1,431 @@
+/**
+ * @file ike_mobike.c
+ *
+ * @brief Implementation of the ike_mobike task.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "ike_mobike.h"
+
+#include <string.h>
+
+#include <daemon.h>
+#include <sa/tasks/ike_natd.h>
+#include <encoding/payloads/notify_payload.h>
+
+
+typedef struct private_ike_mobike_t private_ike_mobike_t;
+
+/**
+ * Private members of a ike_mobike_t task.
+ */
+struct private_ike_mobike_t {
+
+ /**
+ * Public methods and task_t interface.
+ */
+ ike_mobike_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * Are we the initiator?
+ */
+ bool initiator;
+
+ /**
+ * cookie2 value to verify new addresses
+ */
+ chunk_t cookie2;
+
+ /**
+ * NAT discovery reusing the IKE_NATD task
+ */
+ ike_natd_t *natd;
+
+ /**
+ * use task to update addresses
+ */
+ bool roam;
+
+ /**
+ * include address list update
+ */
+ bool address;
+};
+
+/**
+ * flush the IKE_SAs list of additional addresses
+ */
+static void flush_additional_addresses(private_ike_mobike_t *this)
+{
+ iterator_t *iterator;
+ host_t *host;
+
+ iterator = this->ike_sa->create_additional_address_iterator(this->ike_sa);
+ while (iterator->iterate(iterator, (void**)&host))
+ {
+ iterator->remove(iterator);
+ host->destroy(host);
+ }
+ iterator->destroy(iterator);
+}
+
+
+/**
+ * read notifys from message and evaluate them
+ */
+static void process_payloads(private_ike_mobike_t *this, message_t *message)
+{
+ iterator_t *iterator;
+ payload_t *payload;
+ bool first = TRUE;
+
+ iterator = message->get_payload_iterator(message);
+ while (iterator->iterate(iterator, (void**)&payload))
+ {
+ int family = AF_INET;
+ notify_payload_t *notify;
+ chunk_t data;
+ host_t *host;
+
+ if (payload->get_type(payload) != NOTIFY)
+ {
+ continue;
+ }
+ notify = (notify_payload_t*)payload;
+ switch (notify->get_notify_type(notify))
+ {
+ case MOBIKE_SUPPORTED:
+ {
+ DBG1(DBG_IKE, "peer supports MOBIKE");
+ this->ike_sa->enable_extension(this->ike_sa, EXT_MOBIKE);
+ break;
+ }
+ case ADDITIONAL_IP6_ADDRESS:
+ {
+ family = AF_INET6;
+ /* fall through */
+ }
+ case ADDITIONAL_IP4_ADDRESS:
+ {
+ if (first)
+ { /* an ADDITIONAL_*_ADDRESS means replace, so flush once */
+ flush_additional_addresses(this);
+ first = FALSE;
+ }
+ data = notify->get_notification_data(notify);
+ host = host_create_from_chunk(family, data, 0);
+ DBG2(DBG_IKE, "got additional MOBIKE peer address: %H", host);
+ this->ike_sa->add_additional_address(this->ike_sa, host);
+ break;
+ }
+ case UPDATE_SA_ADDRESSES:
+ {
+ this->roam = TRUE;
+ break;
+ }
+ case NO_ADDITIONAL_ADDRESSES:
+ {
+ flush_additional_addresses(this);
+ break;
+ }
+ case NAT_DETECTION_SOURCE_IP:
+ case NAT_DETECTION_DESTINATION_IP:
+ {
+ /* NAT check in this MOBIKE exchange, create subtask for it */
+ if (this->natd == NULL)
+ {
+ this->natd = ike_natd_create(this->ike_sa, this->initiator);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * Add ADDITIONAL_*_ADDRESS notifys depending on our address list
+ */
+static void build_address_list(private_ike_mobike_t *this, message_t *message)
+{
+ iterator_t *iterator;
+ host_t *host, *me;
+ notify_type_t type;
+ bool additional = FALSE;
+
+ me = this->ike_sa->get_my_host(this->ike_sa);
+ iterator = charon->kernel_interface->create_address_iterator(
+ charon->kernel_interface);
+ while (iterator->iterate(iterator, (void**)&host))
+ {
+ if (me->ip_equals(me, host))
+ { /* "ADDITIONAL" means do not include IKE_SAs host */
+ continue;
+ }
+ switch (host->get_family(host))
+ {
+ case AF_INET:
+ type = ADDITIONAL_IP4_ADDRESS;
+ break;
+ case AF_INET6:
+ type = ADDITIONAL_IP6_ADDRESS;
+ break;
+ default:
+ continue;
+ }
+ message->add_notify(message, FALSE, type, host->get_address(host));
+ additional = TRUE;
+ }
+ if (!additional)
+ {
+ message->add_notify(message, FALSE, NO_ADDITIONAL_ADDRESSES, chunk_empty);
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * update addresses of associated CHILD_SAs
+ */
+static void update_children(private_ike_mobike_t *this)
+{
+ iterator_t *iterator;
+ child_sa_t *child_sa;
+
+ iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa);
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ child_sa->update_hosts(child_sa,
+ this->ike_sa->get_my_host(this->ike_sa),
+ this->ike_sa->get_other_host(this->ike_sa),
+ this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY));
+ }
+ iterator->destroy(iterator);
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t build_i(private_ike_mobike_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_AUTH &&
+ message->get_payload(message, SECURITY_ASSOCIATION))
+ {
+ message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty);
+ build_address_list(this, message);
+ }
+ else
+ {
+ if (this->roam)
+ {
+ message->add_notify(message, FALSE, UPDATE_SA_ADDRESSES, chunk_empty);
+ }
+ if (this->address)
+ {
+ build_address_list(this, message);
+ }
+
+ this->natd = ike_natd_create(this->ike_sa, this->initiator);
+ this->natd->task.build(&this->natd->task, message);
+ update_children(this);
+ }
+
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for responder
+ */
+static status_t process_r(private_ike_mobike_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_AUTH &&
+ message->get_payload(message, SECURITY_ASSOCIATION))
+ {
+ process_payloads(this, message);
+ }
+ else if (message->get_exchange_type(message) == INFORMATIONAL)
+ {
+ process_payloads(this, message);
+ if (this->roam)
+ {
+ host_t *me, *other;
+
+ me = message->get_destination(message);
+ other = message->get_source(message);
+ this->ike_sa->set_my_host(this->ike_sa, me->clone(me));
+ this->ike_sa->set_other_host(this->ike_sa, other->clone(other));
+ }
+
+ if (this->natd)
+ {
+ this->natd->task.process(&this->natd->task, message);
+ }
+ }
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.build for responder
+ */
+static status_t build_r(private_ike_mobike_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_AUTH &&
+ message->get_payload(message, SECURITY_ASSOCIATION))
+ {
+ if (this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE))
+ {
+ message->add_notify(message, FALSE, MOBIKE_SUPPORTED, chunk_empty);
+ build_address_list(this, message);
+ }
+ return SUCCESS;
+ }
+ else if (message->get_exchange_type(message) == INFORMATIONAL)
+ {
+ if (this->natd)
+ {
+ this->natd->task.build(&this->natd->task, message);
+ }
+ if (this->roam)
+ {
+ update_children(this);
+ }
+ return SUCCESS;
+ }
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_mobike_t *this, message_t *message)
+{
+ if (message->get_exchange_type(message) == IKE_AUTH &&
+ message->get_payload(message, SECURITY_ASSOCIATION))
+ {
+ process_payloads(this, message);
+
+ return SUCCESS;
+ }
+ else if (message->get_exchange_type(message) == INFORMATIONAL)
+ {
+ u_int32_t updates = this->ike_sa->get_pending_updates(this->ike_sa) - 1;
+ this->ike_sa->set_pending_updates(this->ike_sa, updates);
+ if (updates > 0)
+ {
+ /* newer update queued, ignore this one */
+ return SUCCESS;
+ }
+ process_payloads(this, message);
+ if (this->natd)
+ {
+ this->natd->task.process(&this->natd->task, message);
+ }
+ if (this->roam)
+ {
+ /* update again, as NAT state may have changed */
+ update_children(this);
+ }
+ return SUCCESS;
+ }
+ return NEED_MORE;
+}
+
+/**
+ * Implementation of ike_mobike_t.roam.
+ */
+static void roam(private_ike_mobike_t *this, bool address)
+{
+ this->roam = TRUE;
+ this->address = address;
+ this->ike_sa->set_pending_updates(this->ike_sa,
+ this->ike_sa->get_pending_updates(this->ike_sa) + 1);
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_mobike_t *this)
+{
+ return IKE_MOBIKE;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_mobike_t *this, ike_sa_t *ike_sa)
+{
+ chunk_free(&this->cookie2);
+ this->ike_sa = ike_sa;
+ if (this->natd)
+ {
+ this->natd->task.migrate(&this->natd->task, ike_sa);
+ }
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_mobike_t *this)
+{
+ chunk_free(&this->cookie2);
+ if (this->natd)
+ {
+ this->natd->task.destroy(&this->natd->task);
+ }
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator)
+{
+ private_ike_mobike_t *this = malloc_thing(private_ike_mobike_t);
+
+ this->public.roam = (void(*)(ike_mobike_t*,bool))roam;
+ this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+ this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+ this->public.task.destroy = (void(*)(task_t*))destroy;
+
+ if (initiator)
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+ }
+ else
+ {
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
+ }
+
+ this->ike_sa = ike_sa;
+ this->initiator = initiator;
+ this->roam = FALSE;
+ this->address = TRUE;
+ this->cookie2 = chunk_empty;
+ this->natd = NULL;
+
+ return &this->public;
+}
+
diff --git a/src/charon/sa/tasks/ike_mobike.h b/src/charon/sa/tasks/ike_mobike.h
new file mode 100644
index 000000000..db493c459
--- /dev/null
+++ b/src/charon/sa/tasks/ike_mobike.h
@@ -0,0 +1,73 @@
+/**
+ * @file ike_mobike.h
+ *
+ * @brief Interface ike_mobike_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef IKE_MOBIKE_H_
+#define IKE_MOBIKE_H_
+
+typedef struct ike_mobike_t ike_mobike_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type ike_mobike, detects and handles MOBIKE extension.
+ *
+ * The MOBIKE extension is defined in RFC4555. It allows to update IKE
+ * and IPsec tunnel addresses.
+ * This tasks handles the MOBIKE_SUPPORTED notify exchange to detect MOBIKE
+ * support, allows the exchange of ADDITIONAL_*_ADDRESS to exchange additional
+ * endpoints and handles the UPDATE_SA_ADDRESS notify to finally update
+ * endpoints.
+ *
+ * @b Constructors:
+ * - ike_mobike_create()
+ *
+ * @ingroup tasks
+ */
+struct ike_mobike_t {
+
+ /**
+ * Implements the task_t interface
+ */
+ task_t task;
+
+ /**
+ * @brief Use the task to roam to other addresses.
+ *
+ * @param this calling object
+ * @param address TRUE to include address list update
+ */
+ void (*roam)(ike_mobike_t *this, bool address);
+};
+
+/**
+ * @brief Create a new ike_mobike task.
+ *
+ * @param ike_sa IKE_SA this task works for
+ * @param initiator TRUE if taks is initiated by us
+ * @return ike_mobike task to handle by the task_manager
+ */
+ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator);
+
+#endif /* IKE_MOBIKE_H_ */
+
diff --git a/src/charon/sa/tasks/ike_natd.c b/src/charon/sa/tasks/ike_natd.c
index 50b5d652b..84a28d024 100644
--- a/src/charon/sa/tasks/ike_natd.c
+++ b/src/charon/sa/tasks/ike_natd.c
@@ -203,14 +203,12 @@ static void process_payloads(private_ike_natd_t *this, message_t *message)
if (this->src_seen && this->dst_seen)
{
- if (!this->dst_matched)
- {
- this->ike_sa->enable_natt(this->ike_sa, TRUE);
- }
- if (!this->src_matched)
- {
- this->ike_sa->enable_natt(this->ike_sa, FALSE);
- }
+ this->ike_sa->enable_extension(this->ike_sa, EXT_NATT);
+
+ this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE,
+ !this->dst_matched);
+ this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE,
+ !this->src_matched);
}
}
@@ -220,8 +218,11 @@ static void process_payloads(private_ike_natd_t *this, message_t *message)
static status_t process_i(private_ike_natd_t *this, message_t *message)
{
process_payloads(this, message);
-
- if (this->ike_sa->is_natt_enabled(this->ike_sa))
+
+ /* if peer supports NAT-T, we switch to port 4500 even
+ * if no NAT is detected. MOBIKE requires this. */
+ if (message->get_exchange_type(message) == IKE_SA_INIT &&
+ this->ike_sa->supports_extension(this->ike_sa, EXT_NATT))
{
host_t *me, *other;
@@ -240,33 +241,49 @@ static status_t process_i(private_ike_natd_t *this, message_t *message)
static status_t build_i(private_ike_natd_t *this, message_t *message)
{
notify_payload_t *notify;
- linked_list_t *list;
+ iterator_t *iterator;
host_t *host;
- /* include one notify if our address is defined, all addresses otherwise */
+ /* destination is always set */
+ host = this->ike_sa->get_other_host(this->ike_sa);
+ notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host);
+ message->add_payload(message, (payload_t*)notify);
+
+ /* source may be any, we have 3 possibilities to get our source address:
+ * 1. It is defined in the config => use the one of the IKE_SA
+ * 2. We do a routing lookup in the kernel interface
+ * 3. Include all possbile addresses
+ */
host = this->ike_sa->get_my_host(this->ike_sa);
- if (host->is_anyaddr(host))
+ if (!host->is_anyaddr(host))
+ { /* 1. */
+ notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
+ message->add_payload(message, (payload_t*)notify);
+ }
+ else
{
- /* TODO: we could get the src address from netlink!? */
- list = charon->kernel_interface->create_address_list(charon->kernel_interface);
- while (list->remove_first(list, (void**)&host) == SUCCESS)
- {
+ host = charon->kernel_interface->get_source_addr(
+ charon->kernel_interface,
+ this->ike_sa->get_other_host(this->ike_sa));
+ if (host)
+ { /* 2. */
+ host->set_port(host, IKEV2_UDP_PORT);
notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
- host->destroy(host);
message->add_payload(message, (payload_t*)notify);
+ host->destroy(host);
+ }
+ else
+ { /* 3. */
+ iterator = charon->kernel_interface->create_address_iterator(
+ charon->kernel_interface);
+ while (iterator->iterate(iterator, (void**)&host))
+ {
+ notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
+ message->add_payload(message, (payload_t*)notify);
+ }
+ iterator->destroy(iterator);
}
- list->destroy(list);
- }
- else
- {
- notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
- message->add_payload(message, (payload_t*)notify);
}
-
- host = this->ike_sa->get_other_host(this->ike_sa);
- notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host);
- message->add_payload(message, (payload_t*)notify);
-
return NEED_MORE;
}
@@ -279,7 +296,8 @@ static status_t build_r(private_ike_natd_t *this, message_t *message)
host_t *me, *other;
/* only add notifies on successfull responses. */
- if (message->get_payload(message, SECURITY_ASSOCIATION) == NULL)
+ if (message->get_exchange_type(message) == IKE_SA_INIT &&
+ message->get_payload(message, SECURITY_ASSOCIATION) == NULL)
{
return SUCCESS;
}
diff --git a/src/charon/sa/tasks/ike_reauth.c b/src/charon/sa/tasks/ike_reauth.c
new file mode 100644
index 000000000..0e98382a8
--- /dev/null
+++ b/src/charon/sa/tasks/ike_reauth.c
@@ -0,0 +1,175 @@
+/**
+ * @file ike_reauth.c
+ *
+ * @brief Implementation of the ike_reauth task.
+ *
+ */
+
+/*
+ * Copyright (C) 2006-2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "ike_reauth.h"
+
+#include <daemon.h>
+#include <sa/tasks/ike_delete.h>
+
+
+typedef struct private_ike_reauth_t private_ike_reauth_t;
+
+/**
+ * Private members of a ike_reauth_t task.
+ */
+struct private_ike_reauth_t {
+
+ /**
+ * Public methods and task_t interface.
+ */
+ ike_reauth_t public;
+
+ /**
+ * Assigned IKE_SA.
+ */
+ ike_sa_t *ike_sa;
+
+ /**
+ * reused ike_delete task
+ */
+ ike_delete_t *ike_delete;
+};
+
+/**
+ * Implementation of task_t.build for initiator
+ */
+static status_t build_i(private_ike_reauth_t *this, message_t *message)
+{
+ return this->ike_delete->task.build(&this->ike_delete->task, message);
+}
+
+/**
+ * Implementation of task_t.process for initiator
+ */
+static status_t process_i(private_ike_reauth_t *this, message_t *message)
+{
+ ike_sa_t *new;
+ host_t *host;
+ iterator_t *iterator;
+ child_sa_t *child_sa;
+
+ /* process delete response first */
+ this->ike_delete->task.process(&this->ike_delete->task, message);
+
+ /* reestablish only if we have children */
+ iterator = this->ike_sa->create_child_sa_iterator(this->ike_sa);
+ if (iterator->get_count(iterator) == 0)
+ {
+ DBG1(DBG_IKE, "unable to reestablish IKE_SA, no CHILD_SA to recreate");
+ iterator->destroy(iterator);
+ return FAILED;
+ }
+
+ new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, TRUE);
+
+ new->set_peer_cfg(new, this->ike_sa->get_peer_cfg(this->ike_sa));
+ host = this->ike_sa->get_other_host(this->ike_sa);
+ new->set_other_host(new, host->clone(host));
+ host = this->ike_sa->get_my_host(this->ike_sa);
+ new->set_my_host(new, host->clone(host));
+ /* if we already have a virtual IP, we reuse it */
+ host = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE);
+ if (host)
+ {
+ new->set_virtual_ip(new, TRUE, host);
+ }
+
+ while (iterator->iterate(iterator, (void**)&child_sa))
+ {
+ switch (child_sa->get_state(child_sa))
+ {
+ case CHILD_ROUTED:
+ {
+ /* move routed child directly */
+ iterator->remove(iterator);
+ new->add_child_sa(new, child_sa);
+ break;
+ }
+ default:
+ {
+ /* initiate/queue all child SAs */
+ child_cfg_t *child_cfg = child_sa->get_config(child_sa);
+ child_cfg->get_ref(child_cfg);
+ if (new->initiate(new, child_cfg) == DESTROY_ME)
+ {
+ iterator->destroy(iterator);
+ charon->ike_sa_manager->checkin_and_destroy(
+ charon->ike_sa_manager, new);
+ DBG1(DBG_IKE, "reestablishing IKE_SA failed");
+ return FAILED;
+ }
+ break;
+ }
+ }
+ }
+ iterator->destroy(iterator);
+ charon->ike_sa_manager->checkin(charon->ike_sa_manager, new);
+
+ /* we always return failed to delete the obsolete IKE_SA */
+ return FAILED;
+}
+
+/**
+ * Implementation of task_t.get_type
+ */
+static task_type_t get_type(private_ike_reauth_t *this)
+{
+ return IKE_REAUTH;
+}
+
+/**
+ * Implementation of task_t.migrate
+ */
+static void migrate(private_ike_reauth_t *this, ike_sa_t *ike_sa)
+{
+ this->ike_delete->task.migrate(&this->ike_delete->task, ike_sa);
+ this->ike_sa = ike_sa;
+}
+
+/**
+ * Implementation of task_t.destroy
+ */
+static void destroy(private_ike_reauth_t *this)
+{
+ this->ike_delete->task.destroy(&this->ike_delete->task);
+ free(this);
+}
+
+/*
+ * Described in header.
+ */
+ike_reauth_t *ike_reauth_create(ike_sa_t *ike_sa)
+{
+ private_ike_reauth_t *this = malloc_thing(private_ike_reauth_t);
+
+ this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
+ this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
+ this->public.task.destroy = (void(*)(task_t*))destroy;
+ this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
+ this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
+
+ this->ike_sa = ike_sa;
+ this->ike_delete = ike_delete_create(ike_sa, TRUE);
+
+ return &this->public;
+}
+
diff --git a/src/charon/sa/tasks/ike_reauth.h b/src/charon/sa/tasks/ike_reauth.h
new file mode 100644
index 000000000..3c872e1e1
--- /dev/null
+++ b/src/charon/sa/tasks/ike_reauth.h
@@ -0,0 +1,59 @@
+/**
+ * @file ike_reauth.h
+ *
+ * @brief Interface ike_reauth_t.
+ *
+ */
+
+/*
+ * Copyright (C) 2007 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#ifndef IKE_REAUTH_H_
+#define IKE_REAUTH_H_
+
+typedef struct ike_reauth_t ike_reauth_t;
+
+#include <library.h>
+#include <sa/ike_sa.h>
+#include <sa/tasks/task.h>
+
+/**
+ * @brief Task of type ike_reauth, reestablishes an IKE_SA.
+ *
+ * @b Constructors:
+ * - ike_reauth_create()
+ *
+ * @ingroup tasks
+ */
+struct ike_reauth_t {
+
+ /**
+ * Implements the task_t interface
+ */
+ task_t task;
+};
+
+/**
+ * @brief Create a new ike_reauth task.
+ *
+ * This task is initiator only.
+ *
+ * @param ike_sa IKE_SA this task works for
+ * @return ike_reauth task to handle by the task_manager
+ */
+ike_reauth_t *ike_reauth_create(ike_sa_t *ike_sa);
+
+#endif /* IKE_REAUTH_H_ */
+
diff --git a/src/charon/sa/tasks/ike_rekey.c b/src/charon/sa/tasks/ike_rekey.c
index d54fc3524..827f95156 100644
--- a/src/charon/sa/tasks/ike_rekey.c
+++ b/src/charon/sa/tasks/ike_rekey.c
@@ -170,8 +170,9 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message)
{
case FAILED:
/* rekeying failed, fallback to old SA */
- if (!(this->collision &&
- this->collision->get_type(this->collision) == IKE_DELETE))
+ if (!(this->collision && (
+ this->collision->get_type(this->collision) == IKE_DELETE ||
+ this->collision->get_type(this->collision) == IKE_REAUTH)))
{
job_t *job;
u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER);
@@ -180,7 +181,7 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message)
DBG1(DBG_IKE, "IKE_SA rekeying failed, "
"trying again in %d seconds", retry);
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
- charon->event_queue->add_relative(charon->event_queue, job, retry * 1000);
+ charon->scheduler->schedule_job(charon->scheduler, job, retry * 1000);
}
return SUCCESS;
case NEED_MORE:
@@ -231,7 +232,7 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message)
}
job = (job_t*)delete_ike_sa_job_create(to_delete, TRUE);
- charon->job_queue->add(charon->job_queue, job);
+ charon->processor->queue_job(charon->processor, job);
return SUCCESS;
}
diff --git a/src/charon/sa/tasks/task.c b/src/charon/sa/tasks/task.c
index 68d8ebf0c..713403d47 100644
--- a/src/charon/sa/tasks/task.c
+++ b/src/charon/sa/tasks/task.c
@@ -25,14 +25,16 @@
ENUM(task_type_names, IKE_INIT, CHILD_REKEY,
"IKE_INIT",
"IKE_NATD",
+ "IKE_MOBIKE",
"IKE_AUTHENTICATE",
"IKE_CERT",
"IKE_CONFIG",
- "IKE_DPD",
"IKE_REKEY",
+ "IKE_REAUTH",
"IKE_DELETE",
- "IKE_DEADPEER",
+ "IKE_DPD",
"CHILD_CREATE",
"CHILD_DELETE",
"CHILD_REKEY",
);
+
diff --git a/src/charon/sa/tasks/task.h b/src/charon/sa/tasks/task.h
index 128d7db4a..ff60ea816 100644
--- a/src/charon/sa/tasks/task.h
+++ b/src/charon/sa/tasks/task.h
@@ -40,16 +40,18 @@ enum task_type_t {
IKE_INIT,
/** detect NAT situation */
IKE_NATD,
+ /** handle MOBIKE stuff */
+ IKE_MOBIKE,
/** authenticate the initiated IKE_SA */
IKE_AUTHENTICATE,
/** exchange certificates and requests */
IKE_CERT,
/** Configuration payloads, virtual IP and such */
IKE_CONFIG,
- /** DPD detection */
- IKE_DEADPEER,
/** rekey an IKE_SA */
IKE_REKEY,
+ /** reestablish a complete IKE_SA */
+ IKE_REAUTH,
/** delete an IKE_SA */
IKE_DELETE,
/** liveness check */